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 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
     * @throws IOException if the inputstream is closed unexpectedly while reading.
31
     */
32
    @Override
33
    public int read() throws IOException {
34 1 1. read : negated conditional → KILLED
        if (isFinished) {
35 1 1. read : replaced int return with 0 for com/renomad/minum/web/UrlEncodedDataGetter::read → TIMED_OUT
            return -1;
36
        }
37 1 1. read : negated conditional → KILLED
        if (countBytesRead.getCount() == contentLength) {
38
            isFinished = true;
39 1 1. read : replaced int return with 0 for com/renomad/minum/web/UrlEncodedDataGetter::read → KILLED
            return -1;
40
        }
41
        int result = inputStream.read();
42
43 1 1. read : negated conditional → KILLED
        if (result == -1) {
44
            isFinished = true;
45
            // I know this is surprising, however: Because we always have the content length while reading the body,
46
            // we know exactly when we expect to read the last byte.  If we read and get a -1, it means
47
            // the stream is closed - but that should not have happened, because we should have stopped reading when
48
            // we hit the limit of bytes to read.  But in the real world, it will happen:  You can observe it by uploading a large
49
            // file and using the browser's "stop" button during the upload.
50
            throw new IOException("Error: The inputstream has closed unexpectedly while reading");
51
        }
52
53 1 1. read : removed call to com/renomad/minum/web/CountBytesRead::increment → KILLED
        countBytesRead.increment();
54
        char byteValue = (char) result;
55 1 1. read : negated conditional → KILLED
        if (byteValue == '&') {
56
            isFinished = true;
57 1 1. read : replaced int return with 0 for com/renomad/minum/web/UrlEncodedDataGetter::read → KILLED
            return -1;
58
        }
59 1 1. read : replaced int return with 0 for com/renomad/minum/web/UrlEncodedDataGetter::read → KILLED
        return result;
60
    }
61
62
    @Override
63
    public byte[] readAllBytes() throws IOException {
64
        var baos = new ByteArrayOutputStream();
65
        while (true) {
66
            int result = read();
67 1 1. readAllBytes : negated conditional → KILLED
            if (result == -1) {
68
                // if our read function determines we are at the end of the value,
69
                // because we encountered an ampersand, it will return a -1 value,
70
                // and we return our value - but more keys and values expected.
71 1 1. readAllBytes : replaced return value with null for com/renomad/minum/web/UrlEncodedDataGetter::readAllBytes → KILLED
                return baos.toByteArray();
72
            }
73 1 1. readAllBytes : removed call to java/io/ByteArrayOutputStream::write → KILLED
            baos.write((byte)result);
74
        }
75
    }
76
77
    /**
78
     * By "close", we will read from the {@link InputStream} until we have finished the body,
79
     * so that our InputStream has been read until the start of the next partition.
80
     */
81
    @Override
82
    public void close() throws IOException {
83
        while (true) {
84
            int result = read();
85 1 1. close : negated conditional → TIMED_OUT
            if (result == -1) {
86
                return;
87
            }
88
        }
89
    }
90
}

Mutations

34

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

35

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

37

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

39

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

43

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

53

1.1
Location : read
Killed by : com.renomad.minum.web.RequestTests.test_Request_getUrlEncoded_EdgeCase_ContentLengthNotLongEnough(com.renomad.minum.web.RequestTests)
removed call to com/renomad/minum/web/CountBytesRead::increment → KILLED

55

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

57

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

59

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

67

1.1
Location : readAllBytes
Killed by : com.renomad.minum.web.RequestTests.test_Request_getUrlEncoded_EdgeCase_ContentLengthTooLong(com.renomad.minum.web.RequestTests)
negated conditional → KILLED

71

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

73

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

85

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

Active mutators

Tests examined


Report generated by PIT 1.17.0