ConnectionUtil.java

1
package com.jsql.util;
2
3
import com.jsql.model.InjectionModel;
4
import com.jsql.model.bean.util.Header;
5
import com.jsql.model.bean.util.Interaction;
6
import com.jsql.model.bean.util.Request;
7
import com.jsql.model.exception.InjectionFailureException;
8
import com.jsql.model.exception.JSqlException;
9
import com.jsql.model.injection.method.AbstractMethodInjection;
10
import org.apache.commons.lang3.StringUtils;
11
import org.apache.logging.log4j.LogManager;
12
import org.apache.logging.log4j.Logger;
13
14
import java.io.IOException;
15
import java.net.Authenticator;
16
import java.net.CookieManager;
17
import java.net.PasswordAuthentication;
18
import java.net.URI;
19
import java.net.http.HttpClient;
20
import java.net.http.HttpClient.Version;
21
import java.net.http.HttpHeaders;
22
import java.net.http.HttpRequest;
23
import java.net.http.HttpRequest.BodyPublishers;
24
import java.net.http.HttpRequest.Builder;
25
import java.net.http.HttpResponse;
26
import java.net.http.HttpResponse.BodyHandlers;
27
import java.time.Duration;
28
import java.util.*;
29
import java.util.AbstractMap.SimpleEntry;
30
import java.util.Map.Entry;
31
import java.util.stream.Collectors;
32
import java.util.stream.Stream;
33
34
/**
35
 * Utility class in charge of connection to web resources and management
36
 * of source page and request and response headers.
37
 */
38
public class ConnectionUtil {
39
    
40
    /**
41
     * Log4j logger sent to view.
42
     */
43
    private static final Logger LOGGER = LogManager.getRootLogger();
44
    
45
    /**
46
     * URL entered by user
47
     */
48
    private String urlByUser;
49
50
    /**
51
     * URL entered by user without the query string
52
     */
53
    private String urlBase;
54
55
    /**
56
     * Method of injection: by query string, request or header.
57
     */
58
    private AbstractMethodInjection methodInjection;
59
60
    /**
61
     * Default HTTP method. It can be changed to a custom method.
62
     */
63
    private String typeRequest = "GET";
64
65
    private final Random randomForUserAgent = new Random();
66
    
67
    private final InjectionModel injectionModel;
68
    
69
    private final CookieManager cookieManager = new CookieManager();
70
    
71
    public ConnectionUtil(InjectionModel injectionModel) {
72
        this.injectionModel = injectionModel;
73
    }
74
    
75
    public HttpClient getHttpClient() {
76
        
77
        var httpClientBuilder = HttpClient.newBuilder()
78
            .connectTimeout(Duration.ofSeconds(this.getTimeout()))
79
            .sslContext(this.injectionModel.getMediatorUtils().getCertificateUtil().getSslContext())
80
            .followRedirects(
81 1 1. getHttpClient : negated conditional → NO_COVERAGE
                this.injectionModel.getMediatorUtils().getPreferencesUtil().isFollowingRedirection()
82
                ? HttpClient.Redirect.ALWAYS
83
                : HttpClient.Redirect.NEVER
84
            );
85
        
86 1 1. getHttpClient : negated conditional → NO_COVERAGE
        if (this.injectionModel.getMediatorUtils().getPreferencesUtil().isHttp2Disabled()) {
87
            httpClientBuilder.version(Version.HTTP_1_1);
88
        }
89
        
90 1 1. getHttpClient : negated conditional → NO_COVERAGE
        if (!this.injectionModel.getMediatorUtils().getPreferencesUtil().isNotProcessingCookies()) {
91
            httpClientBuilder.cookieHandler(this.cookieManager);
92
        }
93
        
94 1 1. getHttpClient : negated conditional → NO_COVERAGE
        if (this.injectionModel.getMediatorUtils().getAuthenticationUtil().isAuthentEnabled()) {
95
            httpClientBuilder.authenticator(new Authenticator() {
96
              @Override
97
              protected PasswordAuthentication getPasswordAuthentication() {
98 1 1. getPasswordAuthentication : replaced return value with null for com/jsql/util/ConnectionUtil$1::getPasswordAuthentication → NO_COVERAGE
                  return new PasswordAuthentication(
99
                      ConnectionUtil.this.injectionModel.getMediatorUtils().getAuthenticationUtil().getUsernameAuthentication(),
100
                      ConnectionUtil.this.injectionModel.getMediatorUtils().getAuthenticationUtil().getPasswordAuthentication().toCharArray()
101
                  );
102
              }
103
          });
104
      }
105
                
106 1 1. getHttpClient : replaced return value with null for com/jsql/util/ConnectionUtil::getHttpClient → NO_COVERAGE
        return httpClientBuilder.build();
107
    }
108
109
110
    public static <T> Map<String, String> getHeadersMap(HttpResponse<T> httpResponse) {
111
        
112
        Map<String, String> sortedMap = getHeadersMap(httpResponse.headers());
113
        
114
        String responseCodeHttp = ""+ httpResponse.statusCode();
115
        sortedMap.put(":status", responseCodeHttp);
116
        
117 1 1. getHeadersMap : replaced return value with Collections.emptyMap for com/jsql/util/ConnectionUtil::getHeadersMap → NO_COVERAGE
        return sortedMap;
118
    }
119
    
120
    public static Map<String, String> getHeadersMap(HttpHeaders httpHeaders) {
121
        
122
        Map<String, String> unsortedMap = httpHeaders.map()
123
            .entrySet()
124
            .stream()
125
            .sorted(Entry.comparingByKey())
126 1 1. lambda$getHeadersMap$0 : replaced return value with null for com/jsql/util/ConnectionUtil::lambda$getHeadersMap$0 → NO_COVERAGE
            .map(entrySet -> new AbstractMap.SimpleEntry<>(
127
                entrySet.getKey(),
128
                String.join(", ", entrySet.getValue())
129
            ))
130
            .collect(Collectors.toMap(
131
                AbstractMap.SimpleEntry::getKey,
132
                AbstractMap.SimpleEntry::getValue
133
            ));
134
        
135 1 1. getHeadersMap : replaced return value with Collections.emptyMap for com/jsql/util/ConnectionUtil::getHeadersMap → NO_COVERAGE
        return new TreeMap<>(unsortedMap);
136
    }
137
138
    /**
139
     * Check that the connection to the website is working correctly.
140
     * It uses authentication defined by user, with fixed timeout, and warn
141
     * user in case of authentication detected.
142
     * @return
143
     * @throws IOException
144
     * @throws InterruptedException
145
     */
146
    public HttpResponse<String> checkConnectionResponse() throws IOException, InterruptedException, JSqlException {
147
148
        var queryString = this.injectionModel.getMediatorUtils().getParameterUtil().getQueryStringFromEntries();
149
        var testUrl = this.getUrlBase().replaceAll("\\?$", "");
150
151 1 1. checkConnectionResponse : negated conditional → NO_COVERAGE
        if (StringUtils.isNotEmpty(queryString)) {
152
            testUrl += "?"+ queryString;
153
        }
154
155
        String contentTypeRequest = "text/plain";
156
157
        var body = this.injectionModel.getMediatorUtils().getParameterUtil().getRawRequest();
158
159 1 1. checkConnectionResponse : negated conditional → NO_COVERAGE
        if (this.injectionModel.getMediatorUtils().getParameterUtil().isMultipartRequest()) {
160
            body = body.replaceAll("(?s)\\\\n", "\r\n");
161 1 1. checkConnectionResponse : negated conditional → NO_COVERAGE
        } else if (this.injectionModel.getMediatorUtils().getParameterUtil().isRequestSoap()) {
162
            contentTypeRequest = "text/xml";
163 1 1. checkConnectionResponse : negated conditional → NO_COVERAGE
        } else if (!this.injectionModel.getMediatorUtils().getParameterUtil().getListRequest().isEmpty()) {
164
            contentTypeRequest = "application/x-www-form-urlencoded";
165
        }
166
167
        // Test the HTTP connection
168
        Builder httpRequest = HttpRequest.newBuilder();
169
        try {
170
            httpRequest.uri(
171
                URI.create(
172
                    // Get encoded params without fragment
173
                    testUrl
174
                    // Ignore injection point during the test
175
                    .replace(InjectionModel.STAR, StringUtils.EMPTY)
176
                )
177
            );
178
        } catch (IllegalArgumentException e) {
179
            throw new JSqlException(e);
180
        }
181
        httpRequest.setHeader(HeaderUtil.CONTENT_TYPE_REQUEST, contentTypeRequest)
182
            .timeout(Duration.ofSeconds(this.getTimeout()));
183
        
184 1 1. checkConnectionResponse : removed call to com/jsql/util/CsrfUtil::addHeaderToken → NO_COVERAGE
        this.injectionModel.getMediatorUtils().getCsrfUtil().addHeaderToken(httpRequest);
185 1 1. checkConnectionResponse : removed call to com/jsql/util/DigestUtil::addHeaderToken → NO_COVERAGE
        this.injectionModel.getMediatorUtils().getDigestUtil().addHeaderToken(httpRequest);
186
187
        httpRequest.method(
188
            this.typeRequest,
189
            BodyPublishers.ofString(body)
190
        );
191
192
        // Add headers if exists (Authorization:Basic, etc)
193
        for (SimpleEntry<String, String> header: this.injectionModel.getMediatorUtils().getParameterUtil().getListHeader()) {
194 1 1. checkConnectionResponse : removed call to com/jsql/util/HeaderUtil::sanitizeHeaders → NO_COVERAGE
            HeaderUtil.sanitizeHeaders(httpRequest, header);
195
        }
196
197 1 1. checkConnectionResponse : replaced return value with null for com/jsql/util/ConnectionUtil::checkConnectionResponse → NO_COVERAGE
        return this.injectionModel.getMediatorUtils().getHeaderUtil().checkResponseHeader(httpRequest, body);
198
    }
199
200
    public void testConnection() throws IOException, InterruptedException, JSqlException {
201
202
        // Check connection is working: define Cookie management, check HTTP status, parse <form> parameters, process CSRF
203
        LOGGER.log(LogLevelUtil.CONSOLE_DEFAULT, () -> I18nUtil.valueByKey("LOG_CONNECTION_TEST"));
204
        this.getCookieManager().getCookieStore().removeAll();
205
        HttpResponse<String> httpResponse = this.checkConnectionResponse();
206
207
        if (
208 2 1. testConnection : negated conditional → NO_COVERAGE
2. testConnection : negated conditional → NO_COVERAGE
            (httpResponse.statusCode() == 401 || httpResponse.statusCode() == 403)
209 1 1. testConnection : negated conditional → NO_COVERAGE
            && !this.injectionModel.getMediatorUtils().getPreferencesUtil().isNotProcessingCookies()
210
            && (
211 1 1. testConnection : negated conditional → NO_COVERAGE
                this.injectionModel.getMediatorUtils().getCsrfUtil().isCsrf()
212 1 1. testConnection : negated conditional → NO_COVERAGE
                || this.injectionModel.getMediatorUtils().getDigestUtil().isDigest()
213
            )
214
        ) {
215 1 1. testConnection : negated conditional → NO_COVERAGE
            if (this.injectionModel.getMediatorUtils().getPreferencesUtil().isProcessingCsrf()) {
216
                LOGGER.log(LogLevelUtil.CONSOLE_INFORM, () -> "Testing CSRF handshake from previous connection...");
217 1 1. testConnection : negated conditional → NO_COVERAGE
            } else if (StringUtils.isNotEmpty(this.injectionModel.getMediatorUtils().getDigestUtil().getTokenDigest())) {
218
                LOGGER.log(LogLevelUtil.CONSOLE_INFORM, () -> "Testing Digest handshake from previous connection...");
219
            }
220
            httpResponse = this.checkConnectionResponse();
221
        }
222
223 3 1. testConnection : changed conditional boundary → NO_COVERAGE
2. testConnection : negated conditional → NO_COVERAGE
3. testConnection : negated conditional → NO_COVERAGE
        if (httpResponse.statusCode() >= 400 && !this.injectionModel.getMediatorUtils().getPreferencesUtil().isNotTestingConnection()) {
224
            throw new InjectionFailureException(String.format("Connection failed: problem when calling %s", httpResponse.uri().toURL()));
225
        }
226
    }
227
228
    public String getSource(String url, boolean lineFeed) {
229
        
230
        Map<Header, Object> msgHeader = new EnumMap<>(Header.class);
231
        msgHeader.put(Header.URL, url);
232
        
233
        String pageSource = StringUtils.EMPTY;
234
        
235
        try {
236
            var httpRequest = HttpRequest.newBuilder()
237
                .uri(URI.create(url))
238
                .timeout(Duration.ofSeconds(this.getTimeout()))
239
                .build();
240
            
241
            HttpHeaders httpHeaders;
242
                
243 1 1. getSource : negated conditional → NO_COVERAGE
            if (lineFeed) {
244
                
245
                HttpResponse<Stream<String>> response = this.getHttpClient().send(httpRequest, BodyHandlers.ofLines());
246
                pageSource = response.body().collect(Collectors.joining("\n"));
247
                httpHeaders = response.headers();
248
                
249
            } else {
250
                
251
                HttpResponse<String> response = this.getHttpClient().send(httpRequest, BodyHandlers.ofString());
252
                pageSource = response.body();
253
                httpHeaders = response.headers();
254
            }
255
            
256
            msgHeader.put(Header.RESPONSE, ConnectionUtil.getHeadersMap(httpHeaders));
257
            msgHeader.put(Header.HEADER, ConnectionUtil.getHeadersMap(httpRequest.headers()));
258
            
259
        } catch (IOException e) {
260
            LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
261
        } catch (InterruptedException e) {
262
            
263
            LOGGER.log(LogLevelUtil.IGNORE, e, e);
264 1 1. getSource : removed call to java/lang/Thread::interrupt → NO_COVERAGE
            Thread.currentThread().interrupt();
265
            
266
        } finally {
267
            
268
            msgHeader.put(Header.SOURCE, pageSource);
269
            
270
            // Inform the view about the log infos
271
            var request = new Request();
272 1 1. getSource : removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE
            request.setMessage(Interaction.MESSAGE_HEADER);
273 1 1. getSource : removed call to com/jsql/model/bean/util/Request::setParameters → NO_COVERAGE
            request.setParameters(msgHeader);
274 1 1. getSource : removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE
            this.injectionModel.sendToViews(request);
275
        }
276
        
277 1 1. getSource : replaced return value with "" for com/jsql/util/ConnectionUtil::getSource → NO_COVERAGE
        return pageSource.trim();
278
    }
279
    
280
    /**
281
     * Call an URL and return the source page.
282
     * @param url to call
283
     * @return the source page of the URL
284
     */
285
    public String getSourceLineFeed(String url) {
286 1 1. getSourceLineFeed : replaced return value with "" for com/jsql/util/ConnectionUtil::getSourceLineFeed → NO_COVERAGE
        return this.getSource(url, true);
287
    }
288
    
289
    public String getSource(String url) {
290 1 1. getSource : replaced return value with "" for com/jsql/util/ConnectionUtil::getSource → NO_COVERAGE
        return this.getSource(url, false);
291
    }
292
293
    public void setCustomUserAgent(Builder httpRequest) {
294 1 1. setCustomUserAgent : negated conditional → NO_COVERAGE
        if (this.injectionModel.getMediatorUtils().getUserAgentUtil().isCustomUserAgent()) {
295
            
296
            String agents = this.injectionModel.getMediatorUtils().getUserAgentUtil().getCustomUserAgent();
297
            List<String> listAgents = Stream.of(agents.split("[\\r\\n]+"))
298 2 1. lambda$setCustomUserAgent$4 : replaced boolean return with true for com/jsql/util/ConnectionUtil::lambda$setCustomUserAgent$4 → NO_COVERAGE
2. lambda$setCustomUserAgent$4 : negated conditional → NO_COVERAGE
                .filter(q -> !q.matches("^#.*"))
299
                .collect(Collectors.toList());
300
            
301
            String randomElement = listAgents.get(this.randomForUserAgent.nextInt(listAgents.size()));
302
            
303
            httpRequest.setHeader("User-Agent", randomElement);
304
        }
305
    }
306
    
307
    
308
    // Builder
309
310
    public ConnectionUtil withMethodInjection(AbstractMethodInjection methodInjection) {
311
        this.methodInjection = methodInjection;
312 1 1. withMethodInjection : replaced return value with null for com/jsql/util/ConnectionUtil::withMethodInjection → NO_COVERAGE
        return this;
313
    }
314
    
315
    public ConnectionUtil withTypeRequest(String typeRequest) {
316
        this.typeRequest = typeRequest;
317 1 1. withTypeRequest : replaced return value with null for com/jsql/util/ConnectionUtil::withTypeRequest → NO_COVERAGE
        return this;
318
    }
319
    
320
    
321
    // Getters and setters
322
    
323
    public String getUrlByUser() {
324 1 1. getUrlByUser : replaced return value with "" for com/jsql/util/ConnectionUtil::getUrlByUser → NO_COVERAGE
        return this.urlByUser;
325
    }
326
327
    public void setUrlByUser(String urlByUser) {
328
        this.urlByUser = urlByUser;
329
    }
330
    
331
    public String getUrlBase() {
332 1 1. getUrlBase : replaced return value with "" for com/jsql/util/ConnectionUtil::getUrlBase → SURVIVED
        return this.urlBase;
333
    }
334
335
    public void setUrlBase(String urlBase) {
336
        this.urlBase = urlBase;
337
    }
338
    
339
    public AbstractMethodInjection getMethodInjection() {
340 1 1. getMethodInjection : replaced return value with null for com/jsql/util/ConnectionUtil::getMethodInjection → KILLED
        return this.methodInjection;
341
    }
342
343
    public void setMethodInjection(AbstractMethodInjection methodInjection) {
344
        this.methodInjection = methodInjection;
345
    }
346
    
347
    public String getTypeRequest() {
348 1 1. getTypeRequest : replaced return value with "" for com/jsql/util/ConnectionUtil::getTypeRequest → NO_COVERAGE
        return this.typeRequest;
349
    }
350
351
    public void setTypeRequest(String typeRequest) {
352
        this.typeRequest = typeRequest;
353
    }
354
355
    /**
356
     * Default timeout used by the jcifs fix. It's the default value used usually by the JVM.
357
     */
358
    public Integer getTimeout() {
359 1 1. getTimeout : replaced Integer return value with 0 for com/jsql/util/ConnectionUtil::getTimeout → NO_COVERAGE
        return this.injectionModel.getMediatorUtils().getPreferencesUtil().countConnectionTimeout();
360
    }
361
362
    public CookieManager getCookieManager() {
363 1 1. getCookieManager : replaced return value with null for com/jsql/util/ConnectionUtil::getCookieManager → NO_COVERAGE
        return cookieManager;
364
    }
365
}

Mutations

81

1.1
Location : getHttpClient
Killed by : none
negated conditional → NO_COVERAGE

86

1.1
Location : getHttpClient
Killed by : none
negated conditional → NO_COVERAGE

90

1.1
Location : getHttpClient
Killed by : none
negated conditional → NO_COVERAGE

94

1.1
Location : getHttpClient
Killed by : none
negated conditional → NO_COVERAGE

98

1.1
Location : getPasswordAuthentication
Killed by : none
replaced return value with null for com/jsql/util/ConnectionUtil$1::getPasswordAuthentication → NO_COVERAGE

106

1.1
Location : getHttpClient
Killed by : none
replaced return value with null for com/jsql/util/ConnectionUtil::getHttpClient → NO_COVERAGE

117

1.1
Location : getHeadersMap
Killed by : none
replaced return value with Collections.emptyMap for com/jsql/util/ConnectionUtil::getHeadersMap → NO_COVERAGE

126

1.1
Location : lambda$getHeadersMap$0
Killed by : none
replaced return value with null for com/jsql/util/ConnectionUtil::lambda$getHeadersMap$0 → NO_COVERAGE

135

1.1
Location : getHeadersMap
Killed by : none
replaced return value with Collections.emptyMap for com/jsql/util/ConnectionUtil::getHeadersMap → NO_COVERAGE

151

1.1
Location : checkConnectionResponse
Killed by : none
negated conditional → NO_COVERAGE

159

1.1
Location : checkConnectionResponse
Killed by : none
negated conditional → NO_COVERAGE

161

1.1
Location : checkConnectionResponse
Killed by : none
negated conditional → NO_COVERAGE

163

1.1
Location : checkConnectionResponse
Killed by : none
negated conditional → NO_COVERAGE

184

1.1
Location : checkConnectionResponse
Killed by : none
removed call to com/jsql/util/CsrfUtil::addHeaderToken → NO_COVERAGE

185

1.1
Location : checkConnectionResponse
Killed by : none
removed call to com/jsql/util/DigestUtil::addHeaderToken → NO_COVERAGE

194

1.1
Location : checkConnectionResponse
Killed by : none
removed call to com/jsql/util/HeaderUtil::sanitizeHeaders → NO_COVERAGE

197

1.1
Location : checkConnectionResponse
Killed by : none
replaced return value with null for com/jsql/util/ConnectionUtil::checkConnectionResponse → NO_COVERAGE

208

1.1
Location : testConnection
Killed by : none
negated conditional → NO_COVERAGE

2.2
Location : testConnection
Killed by : none
negated conditional → NO_COVERAGE

209

1.1
Location : testConnection
Killed by : none
negated conditional → NO_COVERAGE

211

1.1
Location : testConnection
Killed by : none
negated conditional → NO_COVERAGE

212

1.1
Location : testConnection
Killed by : none
negated conditional → NO_COVERAGE

215

1.1
Location : testConnection
Killed by : none
negated conditional → NO_COVERAGE

217

1.1
Location : testConnection
Killed by : none
negated conditional → NO_COVERAGE

223

1.1
Location : testConnection
Killed by : none
changed conditional boundary → NO_COVERAGE

2.2
Location : testConnection
Killed by : none
negated conditional → NO_COVERAGE

3.3
Location : testConnection
Killed by : none
negated conditional → NO_COVERAGE

243

1.1
Location : getSource
Killed by : none
negated conditional → NO_COVERAGE

264

1.1
Location : getSource
Killed by : none
removed call to java/lang/Thread::interrupt → NO_COVERAGE

272

1.1
Location : getSource
Killed by : none
removed call to com/jsql/model/bean/util/Request::setMessage → NO_COVERAGE

273

1.1
Location : getSource
Killed by : none
removed call to com/jsql/model/bean/util/Request::setParameters → NO_COVERAGE

274

1.1
Location : getSource
Killed by : none
removed call to com/jsql/model/InjectionModel::sendToViews → NO_COVERAGE

277

1.1
Location : getSource
Killed by : none
replaced return value with "" for com/jsql/util/ConnectionUtil::getSource → NO_COVERAGE

286

1.1
Location : getSourceLineFeed
Killed by : none
replaced return value with "" for com/jsql/util/ConnectionUtil::getSourceLineFeed → NO_COVERAGE

290

1.1
Location : getSource
Killed by : none
replaced return value with "" for com/jsql/util/ConnectionUtil::getSource → NO_COVERAGE

294

1.1
Location : setCustomUserAgent
Killed by : none
negated conditional → NO_COVERAGE

298

1.1
Location : lambda$setCustomUserAgent$4
Killed by : none
replaced boolean return with true for com/jsql/util/ConnectionUtil::lambda$setCustomUserAgent$4 → NO_COVERAGE

2.2
Location : lambda$setCustomUserAgent$4
Killed by : none
negated conditional → NO_COVERAGE

312

1.1
Location : withMethodInjection
Killed by : none
replaced return value with null for com/jsql/util/ConnectionUtil::withMethodInjection → NO_COVERAGE

317

1.1
Location : withTypeRequest
Killed by : none
replaced return value with null for com/jsql/util/ConnectionUtil::withTypeRequest → NO_COVERAGE

324

1.1
Location : getUrlByUser
Killed by : none
replaced return value with "" for com/jsql/util/ConnectionUtil::getUrlByUser → NO_COVERAGE

332

1.1
Location : getUrlBase
Killed by : none
replaced return value with "" for com/jsql/util/ConnectionUtil::getUrlBase → SURVIVED

340

1.1
Location : getMethodInjection
Killed by : ParameterUtilSpock.[engine:spock]/[spec:ParameterUtilSpock]/[feature:$spock_feature_0_1]
replaced return value with null for com/jsql/util/ConnectionUtil::getMethodInjection → KILLED

348

1.1
Location : getTypeRequest
Killed by : none
replaced return value with "" for com/jsql/util/ConnectionUtil::getTypeRequest → NO_COVERAGE

359

1.1
Location : getTimeout
Killed by : none
replaced Integer return value with 0 for com/jsql/util/ConnectionUtil::getTimeout → NO_COVERAGE

363

1.1
Location : getCookieManager
Killed by : none
replaced return value with null for com/jsql/util/ConnectionUtil::getCookieManager → NO_COVERAGE

Active mutators

Tests examined


Report generated by PIT 1.16.1