RequestLine.java

1
package com.renomad.minum.web;
2
3
import com.renomad.minum.logging.ILogger;
4
import com.renomad.minum.security.ForbiddenUseException;
5
import com.renomad.minum.utils.StringUtils;
6
7
import java.util.*;
8
9
import static com.renomad.minum.utils.Invariants.mustNotBeNull;
10
11
/**
12
 * This class holds data and methods for dealing with the
13
 * "start line" in an HTTP request.  For example,
14
 * GET /foo HTTP/1.1
15
 */
16
public final class RequestLine {
17
18
    private final Method method;
19
    private final PathDetails pathDetails;
20
    private final HttpVersion version;
21
    private final String rawValue;
22
    private final ILogger logger;
23
    static final int MAX_QUERY_STRING_KEYS_COUNT = 50;
24
25
    /**
26
     * @param method GET, POST, etc.
27
     * @param pathDetails See {@link PathDetails}
28
     * @param version the version of HTTP (1.0 or 1.1) we're receiving
29
     * @param rawValue the entire raw string of the start line
30
     */
31
    public RequestLine(
32
            Method method,
33
            PathDetails pathDetails,
34
            HttpVersion version,
35
            String rawValue,
36
            ILogger logger
37
    ) {
38
        this.method = method;
39
        this.pathDetails = pathDetails;
40
        this.version = version;
41
        this.rawValue = rawValue;
42
        this.logger = logger;
43
    }
44
45
46
47
    public static final RequestLine EMPTY = new RequestLine(Method.NONE, PathDetails.empty, HttpVersion.NONE, "", null);
48
49
    /**
50
     * Returns a map of the key-value pairs in the URL,
51
     * for example in {@code http://foo.com?name=alice} you
52
     * have a key of name and a value of alice.
53
     */
54
    public Map<String, String> queryString() {
55 2 1. queryString : negated conditional → KILLED
2. queryString : negated conditional → KILLED
        if (pathDetails == null || pathDetails.getQueryString().isEmpty()) {
56
            return Map.of();
57
        } else {
58 1 1. queryString : replaced return value with Collections.emptyMap for com/renomad/minum/web/RequestLine::queryString → KILLED
            return new HashMap<>(pathDetails.getQueryString());
59
        }
60
61
    }
62
63
    /**
64
     * These are the HTTP methods we handle.
65
     */
66
    public enum Method {
67
        GET,
68
        POST,
69
        PUT,
70
        DELETE,
71
        TRACE,
72
        PATCH,
73
        OPTIONS,
74
        HEAD,
75
76
        /**
77
         * Represents the null value of Method
78
         */
79
        NONE
80
    }
81
82
    /**
83
     * Given the string value of a Request Line (like GET /hello HTTP/1.1)
84
     * validate and extract the values for our use.
85
     */
86
    public RequestLine extractRequestLine(String value) {
87
        mustNotBeNull(value);
88 1 1. extractRequestLine : negated conditional → KILLED
        if (value.isEmpty()) {
89 1 1. extractRequestLine : replaced return value with null for com/renomad/minum/web/RequestLine::extractRequestLine → KILLED
            return RequestLine.EMPTY;
90
        }
91
        RequestLineRawValues rawValues = requestLineTokenizer(value);
92 1 1. extractRequestLine : negated conditional → KILLED
        if (rawValues == null) {
93 1 1. extractRequestLine : replaced return value with null for com/renomad/minum/web/RequestLine::extractRequestLine → KILLED
            return RequestLine.EMPTY;
94
        }
95
        Method myMethod = extractMethod(rawValues.method());
96 1 1. extractRequestLine : negated conditional → KILLED
        if (myMethod.equals(Method.NONE)) {
97 1 1. extractRequestLine : replaced return value with null for com/renomad/minum/web/RequestLine::extractRequestLine → KILLED
            return RequestLine.EMPTY;
98
        }
99
        PathDetails pd = extractPathDetails(rawValues.path());
100
        HttpVersion httpVersion = getHttpVersion(rawValues.protocol());
101 1 1. extractRequestLine : negated conditional → KILLED
        if (httpVersion.equals(HttpVersion.NONE)) {
102 1 1. extractRequestLine : replaced return value with null for com/renomad/minum/web/RequestLine::extractRequestLine → KILLED
            return RequestLine.EMPTY;
103
        }
104
105 1 1. extractRequestLine : replaced return value with null for com/renomad/minum/web/RequestLine::extractRequestLine → KILLED
        return new RequestLine(myMethod, pd, httpVersion, value, logger);
106
    }
107
108
    /**
109
     * Split the request line into three parts - a method (e.g. GET), a
110
     * path (e.g. "/" or "/helloworld/hi/foo?name=hello") and a protocol,
111
     * which is typically "HTTP/1.1" but might be "HTTP/1.0" in some cases
112
     * <br>
113
     * If we don't find exactly three parts, we will return null, which
114
     * is interpreted by the calling method to mean we didn't receive a
115
     * valid request line.
116
     * @param rawRequestLine the full string of the first line received
117
     *                       after the socket is connected to the client.
118
     */
119
    private RequestLineRawValues requestLineTokenizer(String rawRequestLine) {
120
        int firstSpace = rawRequestLine.indexOf(' ');
121 1 1. requestLineTokenizer : negated conditional → KILLED
        if (firstSpace == -1) {
122
            return null;
123
        }
124 1 1. requestLineTokenizer : Replaced integer addition with subtraction → KILLED
        int secondSpace = rawRequestLine.indexOf(' ', firstSpace + 1);
125 1 1. requestLineTokenizer : negated conditional → KILLED
        if (secondSpace == -1) {
126
            return null;
127
        }
128 1 1. requestLineTokenizer : Replaced integer addition with subtraction → KILLED
        int thirdSpace = rawRequestLine.indexOf(' ', secondSpace + 1);
129 1 1. requestLineTokenizer : negated conditional → KILLED
        if (thirdSpace != -1) {
130
            return null;
131
        }
132
        String method = rawRequestLine.substring(0, firstSpace);
133 1 1. requestLineTokenizer : Replaced integer addition with subtraction → KILLED
        String path = rawRequestLine.substring(firstSpace + 1, secondSpace);
134 1 1. requestLineTokenizer : Replaced integer addition with subtraction → KILLED
        String protocol = rawRequestLine.substring(secondSpace + 1);
135 1 1. requestLineTokenizer : replaced return value with null for com/renomad/minum/web/RequestLine::requestLineTokenizer → KILLED
        return new RequestLineRawValues(method, path, protocol);
136
    }
137
138
    private Method extractMethod(String methodString) {
139
        try {
140 1 1. extractMethod : replaced return value with null for com/renomad/minum/web/RequestLine::extractMethod → KILLED
            return Method.valueOf(methodString.toUpperCase(Locale.ROOT));
141
        } catch (Exception ex) {
142
            logger.logDebug(() -> "Unable to convert method to enum: " + methodString);
143 1 1. extractMethod : replaced return value with null for com/renomad/minum/web/RequestLine::extractMethod → KILLED
            return Method.NONE;
144
        }
145
    }
146
147
    private PathDetails extractPathDetails(String path) {
148
        PathDetails pd;
149
        // the request line will have a forward slash at the beginning of
150
        // the path.  Remove that here.
151
        String adjustedPath = path.substring(1);
152
        int locationOfQueryBegin = adjustedPath.indexOf("?");
153 2 1. extractPathDetails : changed conditional boundary → KILLED
2. extractPathDetails : negated conditional → KILLED
        if (locationOfQueryBegin > 0) {
154
            // in this case, we found a question mark, suggesting that a query string exists
155 1 1. extractPathDetails : Replaced integer addition with subtraction → KILLED
            String rawQueryString = adjustedPath.substring(locationOfQueryBegin + 1);
156
            String isolatedPath = adjustedPath.substring(0, locationOfQueryBegin);
157
            Map<String, String> queryString = extractMapFromQueryString(rawQueryString);
158
            pd = new PathDetails(isolatedPath, rawQueryString, queryString);
159
        } else {
160
            // in this case, no question mark was found, thus no query string
161
            pd = new PathDetails(adjustedPath, null, null);
162
        }
163 1 1. extractPathDetails : replaced return value with null for com/renomad/minum/web/RequestLine::extractPathDetails → KILLED
        return pd;
164
    }
165
166
167
    /**
168
     * Given a string containing the combined key-values in
169
     * a query string (e.g. foo=bar&name=alice), split that
170
     * into a map of the key to value (e.g. foo to bar, and name to alice)
171
     */
172
    Map<String, String> extractMapFromQueryString(String rawQueryString) {
173
        Map<String, String> queryStrings = new HashMap<>();
174
        StringTokenizer tokenizer = new StringTokenizer(rawQueryString, "&");
175
        // we'll only take less than MAX_QUERY_STRING_KEYS_COUNT
176 2 1. extractMapFromQueryString : negated conditional → KILLED
2. extractMapFromQueryString : Changed increment from 1 to -1 → KILLED
        for (int i = 0; tokenizer.hasMoreTokens(); i++) {
177 2 1. extractMapFromQueryString : changed conditional boundary → KILLED
2. extractMapFromQueryString : negated conditional → KILLED
            if (i >= MAX_QUERY_STRING_KEYS_COUNT) throw new ForbiddenUseException("User tried providing too many query string keys.  max: " + MAX_QUERY_STRING_KEYS_COUNT);
178
            // this should give us a key and value joined with an equal sign, e.g. foo=bar
179
            String currentKeyValue = tokenizer.nextToken();
180
            int equalSignLocation = currentKeyValue.indexOf("=");
181 2 1. extractMapFromQueryString : changed conditional boundary → KILLED
2. extractMapFromQueryString : negated conditional → KILLED
            if (equalSignLocation <= 0) return Map.of();
182
            String key = currentKeyValue.substring(0, equalSignLocation);
183 1 1. extractMapFromQueryString : Replaced integer addition with subtraction → KILLED
            String rawValue = currentKeyValue.substring(equalSignLocation + 1);
184
            try {
185
                String value = StringUtils.decode(rawValue);
186
                queryStrings.put(key, value);
187
            } catch (IllegalArgumentException ex) {
188
                logger.logDebug(() -> "Query string parsing failed for key: (%s) value: (%s).  Skipping to next key-value pair. error message: %s".formatted(key, rawValue, ex.getMessage()));
189
            }
190
        }
191 1 1. extractMapFromQueryString : replaced return value with Collections.emptyMap for com/renomad/minum/web/RequestLine::extractMapFromQueryString → KILLED
        return queryStrings;
192
    }
193
194
    /**
195
     * Extract the HTTP version from the start line
196
     */
197
    private HttpVersion getHttpVersion(String version) {
198 1 1. getHttpVersion : negated conditional → KILLED
        if (version.equals("HTTP/1.1")) {
199 1 1. getHttpVersion : replaced return value with null for com/renomad/minum/web/RequestLine::getHttpVersion → KILLED
            return HttpVersion.ONE_DOT_ONE;
200 1 1. getHttpVersion : negated conditional → KILLED
        } else if (version.equals("HTTP/1.0")) {
201 1 1. getHttpVersion : replaced return value with null for com/renomad/minum/web/RequestLine::getHttpVersion → KILLED
            return HttpVersion.ONE_DOT_ZERO;
202
        } else {
203 1 1. getHttpVersion : replaced return value with null for com/renomad/minum/web/RequestLine::getHttpVersion → KILLED
            return HttpVersion.NONE;
204
        }
205
    }
206
207
    /**
208
     * Return the method of this request-line.  For example, GET, PUT, POST...
209
     */
210
    public Method getMethod() {
211 1 1. getMethod : replaced return value with null for com/renomad/minum/web/RequestLine::getMethod → KILLED
        return method;
212
    }
213
214
    /**
215
     * This returns an object which contains essential information about the path
216
     * in the request line.  For example, if the request line is "GET /sample?foo=bar HTTP/1.1",
217
     * this would hold data for the path ("sample") and the query string ("foo=bar")
218
     */
219
    public PathDetails getPathDetails() {
220 1 1. getPathDetails : replaced return value with null for com/renomad/minum/web/RequestLine::getPathDetails → KILLED
        return pathDetails;
221
    }
222
223
    /**
224
     * Gets the HTTP version, either 1.0 or 1.1
225
     */
226
    public HttpVersion getVersion() {
227 1 1. getVersion : replaced return value with null for com/renomad/minum/web/RequestLine::getVersion → KILLED
        return this.version;
228
    }
229
230
    /**
231
     * Get the string value of this request line, such as "GET /sample.html HTTP/1.1"
232
     */
233
    public String getRawValue() {
234 1 1. getRawValue : replaced return value with "" for com/renomad/minum/web/RequestLine::getRawValue → KILLED
        return rawValue;
235
    }
236
237
    @Override
238
    public boolean equals(Object o) {
239 2 1. equals : negated conditional → TIMED_OUT
2. equals : replaced boolean return with false for com/renomad/minum/web/RequestLine::equals → KILLED
        if (this == o) return true;
240 3 1. equals : negated conditional → TIMED_OUT
2. equals : negated conditional → TIMED_OUT
3. equals : replaced boolean return with true for com/renomad/minum/web/RequestLine::equals → TIMED_OUT
        if (o == null || getClass() != o.getClass()) return false;
241
        RequestLine that = (RequestLine) o;
242 6 1. equals : negated conditional → TIMED_OUT
2. equals : negated conditional → TIMED_OUT
3. equals : replaced boolean return with true for com/renomad/minum/web/RequestLine::equals → TIMED_OUT
4. equals : negated conditional → TIMED_OUT
5. equals : negated conditional → TIMED_OUT
6. equals : negated conditional → TIMED_OUT
        return method == that.method && Objects.equals(pathDetails, that.pathDetails) && version == that.version && Objects.equals(rawValue, that.rawValue) && Objects.equals(logger, that.logger);
243
    }
244
245
    @Override
246
    public int hashCode() {
247 1 1. hashCode : replaced int return with 0 for com/renomad/minum/web/RequestLine::hashCode → TIMED_OUT
        return Objects.hash(method, pathDetails, version, rawValue, logger);
248
    }
249
250
    @Override
251
    public String toString() {
252 1 1. toString : replaced return value with "" for com/renomad/minum/web/RequestLine::toString → KILLED
        return "RequestLine{" +
253
                "method=" + method +
254
                ", pathDetails=" + pathDetails +
255
                ", version=" + version +
256
                ", rawValue='" + rawValue + '\'' +
257
                ", logger=" + logger +
258
                '}';
259
    }
260
}

Mutations

55

1.1
Location : queryString
Killed by : com.renomad.minum.web.EndpointTests.test_Endpoint_HappyPath(com.renomad.minum.web.EndpointTests)
negated conditional → KILLED

2.2
Location : queryString
Killed by : com.renomad.minum.web.EndpointTests.test_Endpoint_HappyPath(com.renomad.minum.web.EndpointTests)
negated conditional → KILLED

58

1.1
Location : queryString
Killed by : com.renomad.minum.web.EndpointTests.test_Endpoint_HappyPath(com.renomad.minum.web.EndpointTests)
replaced return value with Collections.emptyMap for com/renomad/minum/web/RequestLine::queryString → KILLED

88

1.1
Location : extractRequestLine
Killed by : com.renomad.minum.web.WebPerformanceTests.test3(com.renomad.minum.web.WebPerformanceTests)
negated conditional → KILLED

89

1.1
Location : extractRequestLine
Killed by : com.renomad.minum.web.WebTests
replaced return value with null for com/renomad/minum/web/RequestLine::extractRequestLine → KILLED

92

1.1
Location : extractRequestLine
Killed by : com.renomad.minum.web.WebPerformanceTests.test3(com.renomad.minum.web.WebPerformanceTests)
negated conditional → KILLED

93

1.1
Location : extractRequestLine
Killed by : com.renomad.minum.web.WebTests
replaced return value with null for com/renomad/minum/web/RequestLine::extractRequestLine → KILLED

96

1.1
Location : extractRequestLine
Killed by : com.renomad.minum.web.WebPerformanceTests.test3(com.renomad.minum.web.WebPerformanceTests)
negated conditional → KILLED

97

1.1
Location : extractRequestLine
Killed by : com.renomad.minum.web.WebTests
replaced return value with null for com/renomad/minum/web/RequestLine::extractRequestLine → KILLED

101

1.1
Location : extractRequestLine
Killed by : com.renomad.minum.web.WebPerformanceTests.test3(com.renomad.minum.web.WebPerformanceTests)
negated conditional → KILLED

102

1.1
Location : extractRequestLine
Killed by : com.renomad.minum.web.WebTests
replaced return value with null for com/renomad/minum/web/RequestLine::extractRequestLine → KILLED

105

1.1
Location : extractRequestLine
Killed by : com.renomad.minum.web.WebPerformanceTests.test3(com.renomad.minum.web.WebPerformanceTests)
replaced return value with null for com/renomad/minum/web/RequestLine::extractRequestLine → KILLED

121

1.1
Location : requestLineTokenizer
Killed by : com.renomad.minum.web.WebPerformanceTests.test3(com.renomad.minum.web.WebPerformanceTests)
negated conditional → KILLED

124

1.1
Location : requestLineTokenizer
Killed by : com.renomad.minum.web.WebPerformanceTests.test3(com.renomad.minum.web.WebPerformanceTests)
Replaced integer addition with subtraction → KILLED

125

1.1
Location : requestLineTokenizer
Killed by : com.renomad.minum.web.WebPerformanceTests.test3(com.renomad.minum.web.WebPerformanceTests)
negated conditional → KILLED

128

1.1
Location : requestLineTokenizer
Killed by : com.renomad.minum.web.WebPerformanceTests.test3(com.renomad.minum.web.WebPerformanceTests)
Replaced integer addition with subtraction → KILLED

129

1.1
Location : requestLineTokenizer
Killed by : com.renomad.minum.web.WebPerformanceTests.test3(com.renomad.minum.web.WebPerformanceTests)
negated conditional → KILLED

133

1.1
Location : requestLineTokenizer
Killed by : com.renomad.minum.web.WebPerformanceTests.test3(com.renomad.minum.web.WebPerformanceTests)
Replaced integer addition with subtraction → KILLED

134

1.1
Location : requestLineTokenizer
Killed by : com.renomad.minum.web.WebPerformanceTests.test3(com.renomad.minum.web.WebPerformanceTests)
Replaced integer addition with subtraction → KILLED

135

1.1
Location : requestLineTokenizer
Killed by : com.renomad.minum.web.WebPerformanceTests.test3(com.renomad.minum.web.WebPerformanceTests)
replaced return value with null for com/renomad/minum/web/RequestLine::requestLineTokenizer → KILLED

140

1.1
Location : extractMethod
Killed by : com.renomad.minum.web.WebPerformanceTests.test3(com.renomad.minum.web.WebPerformanceTests)
replaced return value with null for com/renomad/minum/web/RequestLine::extractMethod → KILLED

143

1.1
Location : extractMethod
Killed by : com.renomad.minum.web.WebTests
replaced return value with null for com/renomad/minum/web/RequestLine::extractMethod → KILLED

153

1.1
Location : extractPathDetails
Killed by : com.renomad.minum.web.WebPerformanceTests.test3(com.renomad.minum.web.WebPerformanceTests)
changed conditional boundary → KILLED

2.2
Location : extractPathDetails
Killed by : com.renomad.minum.web.WebPerformanceTests.test3(com.renomad.minum.web.WebPerformanceTests)
negated conditional → KILLED

155

1.1
Location : extractPathDetails
Killed by : com.renomad.minum.web.WebPerformanceTests.test3(com.renomad.minum.web.WebPerformanceTests)
Replaced integer addition with subtraction → KILLED

163

1.1
Location : extractPathDetails
Killed by : com.renomad.minum.web.WebPerformanceTests.test3(com.renomad.minum.web.WebPerformanceTests)
replaced return value with null for com/renomad/minum/web/RequestLine::extractPathDetails → KILLED

176

1.1
Location : extractMapFromQueryString
Killed by : com.renomad.minum.web.WebPerformanceTests.test3(com.renomad.minum.web.WebPerformanceTests)
negated conditional → KILLED

2.2
Location : extractMapFromQueryString
Killed by : com.renomad.minum.web.WebPerformanceTests.test3(com.renomad.minum.web.WebPerformanceTests)
Changed increment from 1 to -1 → KILLED

177

1.1
Location : extractMapFromQueryString
Killed by : com.renomad.minum.web.WebPerformanceTests.test3(com.renomad.minum.web.WebPerformanceTests)
changed conditional boundary → KILLED

2.2
Location : extractMapFromQueryString
Killed by : com.renomad.minum.web.WebPerformanceTests.test3(com.renomad.minum.web.WebPerformanceTests)
negated conditional → KILLED

181

1.1
Location : extractMapFromQueryString
Killed by : com.renomad.minum.web.WebPerformanceTests.test3(com.renomad.minum.web.WebPerformanceTests)
changed conditional boundary → KILLED

2.2
Location : extractMapFromQueryString
Killed by : com.renomad.minum.web.WebPerformanceTests.test3(com.renomad.minum.web.WebPerformanceTests)
negated conditional → KILLED

183

1.1
Location : extractMapFromQueryString
Killed by : com.renomad.minum.web.WebPerformanceTests.test3(com.renomad.minum.web.WebPerformanceTests)
Replaced integer addition with subtraction → KILLED

191

1.1
Location : extractMapFromQueryString
Killed by : com.renomad.minum.web.WebPerformanceTests.test2(com.renomad.minum.web.WebPerformanceTests)
replaced return value with Collections.emptyMap for com/renomad/minum/web/RequestLine::extractMapFromQueryString → KILLED

198

1.1
Location : getHttpVersion
Killed by : com.renomad.minum.web.WebPerformanceTests.test3(com.renomad.minum.web.WebPerformanceTests)
negated conditional → KILLED

199

1.1
Location : getHttpVersion
Killed by : com.renomad.minum.web.WebPerformanceTests.test3(com.renomad.minum.web.WebPerformanceTests)
replaced return value with null for com/renomad/minum/web/RequestLine::getHttpVersion → KILLED

200

1.1
Location : getHttpVersion
Killed by : com.renomad.minum.web.WebTests
negated conditional → KILLED

201

1.1
Location : getHttpVersion
Killed by : com.renomad.minum.web.WebTests
replaced return value with null for com/renomad/minum/web/RequestLine::getHttpVersion → KILLED

203

1.1
Location : getHttpVersion
Killed by : com.renomad.minum.web.WebTests
replaced return value with null for com/renomad/minum/web/RequestLine::getHttpVersion → KILLED

211

1.1
Location : getMethod
Killed by : com.renomad.minum.web.WebPerformanceTests.test3(com.renomad.minum.web.WebPerformanceTests)
replaced return value with null for com/renomad/minum/web/RequestLine::getMethod → KILLED

220

1.1
Location : getPathDetails
Killed by : com.renomad.minum.web.WebPerformanceTests.test3(com.renomad.minum.web.WebPerformanceTests)
replaced return value with null for com/renomad/minum/web/RequestLine::getPathDetails → KILLED

227

1.1
Location : getVersion
Killed by : com.renomad.minum.web.WebPerformanceTests.test3(com.renomad.minum.web.WebPerformanceTests)
replaced return value with null for com/renomad/minum/web/RequestLine::getVersion → KILLED

234

1.1
Location : getRawValue
Killed by : com.renomad.minum.web.RequestLineTests.test_GetRawValue(com.renomad.minum.web.RequestLineTests)
replaced return value with "" for com/renomad/minum/web/RequestLine::getRawValue → KILLED

239

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

2.2
Location : equals
Killed by : com.renomad.minum.web.RequestTests.testSimplerRequest(com.renomad.minum.web.RequestTests)
replaced boolean return with false for com/renomad/minum/web/RequestLine::equals → KILLED

240

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

2.2
Location : equals
Killed by : none
negated conditional → TIMED_OUT

3.3
Location : equals
Killed by : none
replaced boolean return with true for com/renomad/minum/web/RequestLine::equals → TIMED_OUT

242

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

2.2
Location : equals
Killed by : none
negated conditional → TIMED_OUT

3.3
Location : equals
Killed by : none
replaced boolean return with true for com/renomad/minum/web/RequestLine::equals → TIMED_OUT

4.4
Location : equals
Killed by : none
negated conditional → TIMED_OUT

5.5
Location : equals
Killed by : none
negated conditional → TIMED_OUT

6.6
Location : equals
Killed by : none
negated conditional → TIMED_OUT

247

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

252

1.1
Location : toString
Killed by : com.renomad.minum.web.RequestTests.test_Request_ToString(com.renomad.minum.web.RequestTests)
replaced return value with "" for com/renomad/minum/web/RequestLine::toString → KILLED

Active mutators

Tests examined


Report generated by PIT 1.17.0