UrlEncodedDataGetter.java

1
package com.renomad.minum.web;
2
3
import java.io.ByteArrayOutputStream;
4
import java.io.IOException;
5
import java.io.InputStream;
6
7
/**
8
 * This class enables pulling key-value pairs one at a time
9
 * from the Request body. This enables the developer to pull data
10
 * incrementally, rather than reading it all into memory at once.
11
 */
12
public final class UrlEncodedDataGetter extends InputStream {
13
    private final InputStream inputStream;
14
    private final CountBytesRead countBytesRead;
15
    private final long contentLength;
16
    /**
17
     * After we hit the boundary, we will set this flag to true, and all
18
     * subsequent reads will return -1.
19
     */
20
    private boolean isFinished = false;
21
22
    UrlEncodedDataGetter(InputStream inputStream, CountBytesRead countBytesRead, long contentLength) {
23
        this.inputStream = inputStream;
24
        this.countBytesRead = countBytesRead;
25
        this.contentLength = contentLength;
26
    }
27
28
    /**
29
     * Mostly similar behavior to {@link InputStream#read()}
30
     */
31
    @Override
32
    public int read() {
33 1 1. read : negated conditional → KILLED
        if (isFinished) {
34 1 1. read : replaced int return with 0 for com/renomad/minum/web/UrlEncodedDataGetter::read → TIMED_OUT
            return -1;
35
        }
36 1 1. read : negated conditional → KILLED
        if (countBytesRead.getCount() == contentLength) {
37
            isFinished = true;
38 1 1. read : replaced int return with 0 for com/renomad/minum/web/UrlEncodedDataGetter::read → TIMED_OUT
            return -1;
39
        }
40
        int result = 0;
41
        try {
42
            result = inputStream.read();
43
        } catch (IOException e) {
44
            throw new WebServerException("Error in UrlEncodedDataGetter.read", e);
45
        }
46
47 1 1. read : negated conditional → KILLED
        if (result == -1) {
48
            isFinished = true;
49
            // I know this is surprising, however: Because we always have the content length while reading the body,
50
            // we know exactly when we expect to read the last byte.  If we read and get a -1, it means
51
            // the stream is closed - but that should not have happened, because we should have stopped reading when
52
            // we hit the limit of bytes to read.  But in the real world, it will happen:  You can observe it by uploading a large
53
            // file and using the browser's "stop" button during the upload.
54
            throw new WebServerException("Error: The inputstream has closed unexpectedly while reading");
55
        }
56
57 1 1. read : removed call to com/renomad/minum/web/CountBytesRead::increment → KILLED
        countBytesRead.increment();
58
        char byteValue = (char) result;
59 1 1. read : negated conditional → KILLED
        if (byteValue == '&') {
60
            isFinished = true;
61 1 1. read : replaced int return with 0 for com/renomad/minum/web/UrlEncodedDataGetter::read → TIMED_OUT
            return -1;
62
        }
63 1 1. read : replaced int return with 0 for com/renomad/minum/web/UrlEncodedDataGetter::read → KILLED
        return result;
64
    }
65
66
    @Override
67
    public byte[] readAllBytes() {
68
        var baos = new ByteArrayOutputStream();
69
        while (true) {
70
            int result = read();
71 1 1. readAllBytes : negated conditional → KILLED
            if (result == -1) {
72
                // if our read function determines we are at the end of the value,
73
                // because we encountered an ampersand, it will return a -1 value,
74
                // and we return our value - but more keys and values expected.
75 1 1. readAllBytes : replaced return value with null for com/renomad/minum/web/UrlEncodedDataGetter::readAllBytes → KILLED
                return baos.toByteArray();
76
            }
77 1 1. readAllBytes : removed call to java/io/ByteArrayOutputStream::write → KILLED
            baos.write((byte)result);
78
        }
79
    }
80
81
    /**
82
     * By "close", we will read from the {@link InputStream} until we have finished the body,
83
     * so that our InputStream has been read until the start of the next partition.
84
     */
85
    @Override
86
    public void close() {
87
        while (true) {
88
            int result = read();
89 1 1. close : negated conditional → TIMED_OUT
            if (result == -1) {
90
                return;
91
            }
92
        }
93
    }
94
}

Mutations

33

1.1
Location : read
Killed by : com.renomad.minum.web.UrlEncodedDataGetterTests.testRead_NegativeCase_ExceptionThrown(com.renomad.minum.web.UrlEncodedDataGetterTests)
negated conditional → KILLED

34

1.1
Location : read
Killed by : none
replaced int return with 0 for com/renomad/minum/web/UrlEncodedDataGetter::read → TIMED_OUT

36

1.1
Location : read
Killed by : com.renomad.minum.web.UrlEncodedDataGetterTests.testRead_NegativeCase_ExceptionThrown(com.renomad.minum.web.UrlEncodedDataGetterTests)
negated conditional → KILLED

38

1.1
Location : read
Killed by : none
replaced int return with 0 for com/renomad/minum/web/UrlEncodedDataGetter::read → TIMED_OUT

47

1.1
Location : read
Killed by : com.renomad.minum.web.BodyProcessorTests
negated conditional → KILLED

57

1.1
Location : read
Killed by : com.renomad.minum.web.BodyProcessorTests
removed call to com/renomad/minum/web/CountBytesRead::increment → KILLED

59

1.1
Location : read
Killed by : com.renomad.minum.web.BodyProcessorTests
negated conditional → KILLED

61

1.1
Location : read
Killed by : none
replaced int return with 0 for com/renomad/minum/web/UrlEncodedDataGetter::read → TIMED_OUT

63

1.1
Location : read
Killed by : com.renomad.minum.web.BodyProcessorTests
replaced int return with 0 for com/renomad/minum/web/UrlEncodedDataGetter::read → KILLED

71

1.1
Location : readAllBytes
Killed by : com.renomad.minum.web.BodyProcessorTests
negated conditional → KILLED

75

1.1
Location : readAllBytes
Killed by : com.renomad.minum.web.BodyProcessorTests
replaced return value with null for com/renomad/minum/web/UrlEncodedDataGetter::readAllBytes → KILLED

77

1.1
Location : readAllBytes
Killed by : com.renomad.minum.web.BodyProcessorTests
removed call to java/io/ByteArrayOutputStream::write → KILLED

89

1.1
Location : close
Killed by : none
negated conditional → TIMED_OUT

Active mutators

Tests examined


Report generated by PIT 1.17.0