1 | package com.renomad.minum.web; | |
2 | ||
3 | import com.renomad.minum.security.ForbiddenUseException; | |
4 | import com.renomad.minum.utils.UtilsException; | |
5 | ||
6 | import java.io.ByteArrayOutputStream; | |
7 | import java.io.IOException; | |
8 | import java.io.InputStream; | |
9 | import java.nio.charset.StandardCharsets; | |
10 | import java.util.Objects; | |
11 | ||
12 | /** | |
13 | * Handy helpful utilities for working with input streams. | |
14 | */ | |
15 | final class InputStreamUtils implements IInputStreamUtils { | |
16 | ||
17 | private final int maxReadLineSizeBytes; | |
18 | ||
19 | public InputStreamUtils(int maxReadLineSizeBytes) { | |
20 | this.maxReadLineSizeBytes = maxReadLineSizeBytes; | |
21 | } | |
22 | ||
23 | @Override | |
24 | public String readLine(InputStream inputStream) throws IOException { | |
25 | final int NEWLINE_DECIMAL = 10; | |
26 | final int CARRIAGE_RETURN_DECIMAL = 13; | |
27 | ||
28 |
1
1. readLine : Replaced integer division with multiplication → SURVIVED |
final var result = new ByteArrayOutputStream(maxReadLineSizeBytes / 3); |
29 | int bytesRead = 0; | |
30 |
1
1. readLine : Changed increment from 1 to -1 → KILLED |
for (int i = 0;; i++) { |
31 |
2
1. readLine : changed conditional boundary → KILLED 2. readLine : negated conditional → KILLED |
if (i >= maxReadLineSizeBytes) { |
32 |
1
1. readLine : removed call to java/io/InputStream::close → SURVIVED |
inputStream.close(); |
33 | throw new ForbiddenUseException("client sent more bytes than allowed for a single line. max: " + maxReadLineSizeBytes); | |
34 | } | |
35 | int a = inputStream.read(); | |
36 |
1
1. readLine : negated conditional → KILLED |
if (a == -1) { |
37 |
2
1. readLine : negated conditional → KILLED 2. readLine : changed conditional boundary → KILLED |
if (bytesRead > 0) { |
38 |
1
1. readLine : replaced return value with "" for com/renomad/minum/web/InputStreamUtils::readLine → SURVIVED |
return result.toString(StandardCharsets.UTF_8); |
39 | } else { | |
40 | /* | |
41 | it could be unclear whether we read a line that's an empty string, or we | |
42 | reached the end of stream. With this code, if we get an empty string, | |
43 | that means the line we read is just an empty string, and if we get a null, | |
44 | that means we didn't have any characters read into our ByteArrayOutputStream, | |
45 | and tried reading at the end of stream. | |
46 | */ | |
47 |
1
1. readLine : replaced return value with "" for com/renomad/minum/web/InputStreamUtils::readLine → KILLED |
return null; |
48 | } | |
49 | } | |
50 |
1
1. readLine : negated conditional → KILLED |
if (a == CARRIAGE_RETURN_DECIMAL) continue; |
51 |
1
1. readLine : negated conditional → KILLED |
if (a == NEWLINE_DECIMAL) break; |
52 |
1
1. readLine : removed call to java/io/ByteArrayOutputStream::write → KILLED |
result.write(a); |
53 |
1
1. readLine : Changed increment from 1 to -1 → KILLED |
bytesRead += 1; |
54 | } | |
55 |
1
1. readLine : replaced return value with "" for com/renomad/minum/web/InputStreamUtils::readLine → KILLED |
return result.toString(StandardCharsets.UTF_8); |
56 | } | |
57 | ||
58 | @Override | |
59 | public byte[] read(int lengthToRead, InputStream inputStream) { | |
60 | final int typicalBufferSize = 1024 * 8; | |
61 | byte[] buf = new byte[Math.min(lengthToRead, typicalBufferSize)]; // 8k buffer is my understanding of a decent size. Fast, doesn't waste too much space. | |
62 | byte[] data; | |
63 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); | |
64 | int read; | |
65 | int totalRead = 0; | |
66 | try { | |
67 |
2
1. read : changed conditional boundary → KILLED 2. read : negated conditional → KILLED |
while ((read = inputStream.read(buf)) >= 0) { |
68 |
1
1. read : Replaced integer addition with subtraction → KILLED |
totalRead += read; |
69 |
2
1. read : negated conditional → KILLED 2. read : changed conditional boundary → KILLED |
if (totalRead < lengthToRead) { |
70 | // if we haven't gotten everything we wanted, write this to the output and loop again | |
71 |
1
1. read : removed call to java/io/ByteArrayOutputStream::write → KILLED |
baos.write(buf, 0, read); |
72 | } else { | |
73 |
3
1. read : Replaced integer subtraction with addition → KILLED 2. read : Replaced integer subtraction with addition → KILLED 3. read : removed call to java/io/ByteArrayOutputStream::write → KILLED |
baos.write(buf, 0, read - (totalRead - lengthToRead)); |
74 | break; | |
75 | } | |
76 | } | |
77 | } catch (IOException ex) { | |
78 | throw new UtilsException(ex); | |
79 | } | |
80 | data = baos.toByteArray(); | |
81 | ||
82 |
1
1. read : negated conditional → KILLED |
if (data.length != lengthToRead) { |
83 | String message = String.format("length of bytes read (%d) must be what we expected (%d)", data.length, lengthToRead); | |
84 | throw new ForbiddenUseException(message); | |
85 | } | |
86 |
1
1. read : replaced return value with null for com/renomad/minum/web/InputStreamUtils::read → KILLED |
return data; |
87 | } | |
88 | ||
89 | @Override | |
90 | public boolean equals(Object o) { | |
91 |
2
1. equals : negated conditional → KILLED 2. equals : replaced boolean return with false for com/renomad/minum/web/InputStreamUtils::equals → KILLED |
if (this == o) return true; |
92 |
3
1. equals : negated conditional → KILLED 2. equals : negated conditional → KILLED 3. equals : replaced boolean return with true for com/renomad/minum/web/InputStreamUtils::equals → KILLED |
if (o == null || getClass() != o.getClass()) return false; |
93 | InputStreamUtils that = (InputStreamUtils) o; | |
94 |
2
1. equals : negated conditional → KILLED 2. equals : replaced boolean return with true for com/renomad/minum/web/InputStreamUtils::equals → KILLED |
return maxReadLineSizeBytes == that.maxReadLineSizeBytes; |
95 | } | |
96 | ||
97 | @Override | |
98 | public int hashCode() { | |
99 |
1
1. hashCode : replaced int return with 0 for com/renomad/minum/web/InputStreamUtils::hashCode → KILLED |
return Objects.hash(maxReadLineSizeBytes); |
100 | } | |
101 | } | |
Mutations | ||
28 |
1.1 |
|
30 |
1.1 |
|
31 |
1.1 2.2 |
|
32 |
1.1 |
|
36 |
1.1 |
|
37 |
1.1 2.2 |
|
38 |
1.1 |
|
47 |
1.1 |
|
50 |
1.1 |
|
51 |
1.1 |
|
52 |
1.1 |
|
53 |
1.1 |
|
55 |
1.1 |
|
67 |
1.1 2.2 |
|
68 |
1.1 |
|
69 |
1.1 2.2 |
|
71 |
1.1 |
|
73 |
1.1 2.2 3.3 |
|
82 |
1.1 |
|
86 |
1.1 |
|
91 |
1.1 2.2 |
|
92 |
1.1 2.2 3.3 |
|
94 |
1.1 2.2 |
|
99 |
1.1 |