• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

hazendaz / httpunit / 646

06 Dec 2025 08:11PM UTC coverage: 80.526% (+0.02%) from 80.509%
646

push

github

hazendaz
Cleanup array usage

3213 of 4105 branches covered (78.27%)

Branch coverage included in aggregate %.

4 of 4 new or added lines in 3 files covered. (100.0%)

532 existing lines in 26 files now uncovered.

8245 of 10124 relevant lines covered (81.44%)

0.81 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

71.78
/src/main/java/com/meterware/pseudoserver/PseudoServer.java
1
/*
2
 * MIT License
3
 *
4
 * Copyright 2011-2025 Russell Gold
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
7
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
8
 * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and
9
 * to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10
 *
11
 * The above copyright notice and this permission notice shall be included in all copies or substantial portions
12
 * of the Software.
13
 *
14
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
15
 * THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
17
 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
18
 * DEALINGS IN THE SOFTWARE.
19
 */
20
package com.meterware.pseudoserver;
21

22
import com.meterware.httpunit.HttpUnitUtils;
23

24
import java.io.BufferedInputStream;
25
import java.io.IOException;
26
import java.io.InputStream;
27
import java.io.InterruptedIOException;
28
import java.io.OutputStream;
29
import java.io.OutputStreamWriter;
30
import java.io.PrintStream;
31
import java.io.PrintWriter;
32
import java.net.HttpURLConnection;
33
import java.net.ServerSocket;
34
import java.net.Socket;
35
import java.nio.charset.Charset;
36
import java.nio.file.Files;
37
import java.nio.file.Path;
38
import java.util.ArrayList;
39
import java.util.Collections;
40
import java.util.Enumeration;
41
import java.util.Hashtable;
42
import java.util.Iterator;
43
import java.util.List;
44
import java.util.StringTokenizer;
45

46
/**
47
 * A basic simulated web-server for testing user agents without a web server.
48
 **/
49
public class PseudoServer {
50

51
    /**
52
     * allow factory use to be switched on and off by default the factory is not used any more since there were problems
53
     * with the test cases as of 2012-10-09.
54
     */
55
    public static final boolean useFactory = false;
56

57
    /** The Constant DEFAULT_SOCKET_TIMEOUT. */
58
    static final int DEFAULT_SOCKET_TIMEOUT = 1000;
59

60
    /** The Constant INPUT_POLL_INTERVAL. */
61
    private static final int INPUT_POLL_INTERVAL = 10;
62

63
    /** Time in msec to wait for an outstanding server socket to be released before creating a new one. **/
64
    private static int _socketReleaseWaitTime = 50;
1✔
65

66
    /** Number of outstanding server sockets that must be present before trying to wait for one to be released. **/
67
    private static int _waitThreshhold = 10;
1✔
68

69
    /** The num servers. */
70
    private static int _numServers = 0;
1✔
71

72
    /** The server num. */
73
    private int _serverNum = 0;
1✔
74

75
    /** The connection num. */
76
    private int _connectionNum = 0;
1✔
77

78
    /** The classpath dirs. */
79
    private ArrayList _classpathDirs = new ArrayList<>();
1✔
80

81
    /** The max protocol level. */
82
    private String _maxProtocolLevel = "1.1";
1✔
83

84
    /** The socket timeout. */
85
    private final int _socketTimeout;
86

87
    /**
88
     * Returns the amount of time the pseudo server will wait for a server socket to be released (in msec) before
89
     * allocating a new one. See also {@link #getWaitThreshhold getWaitThreshhold}.
90
     *
91
     * @return the socket release wait time
92
     */
93
    public static int getSocketReleaseWaitTime() {
UNCOV
94
        return _socketReleaseWaitTime;
×
95
    }
96

97
    /**
98
     * Returns the amount of time the pseudo server will wait for a server socket to be released (in msec) before
99
     * allocating a new one. See also {@link #getWaitThreshhold getWaitThreshhold}.
100
     *
101
     * @param socketReleaseWaitTime
102
     *            the new socket release wait time
103
     */
104
    public static void setSocketReleaseWaitTime(int socketReleaseWaitTime) {
105
        _socketReleaseWaitTime = socketReleaseWaitTime;
×
UNCOV
106
    }
×
107

108
    /**
109
     * Returns the number of server sockets that must have been allocated and not returned before waiting for one to be
110
     * returned.
111
     *
112
     * @return the wait threshhold
113
     */
114
    public static int getWaitThreshhold() {
UNCOV
115
        return _waitThreshhold;
×
116
    }
117

118
    /**
119
     * Specifies the number of server sockets that must have been allocated and not returned before waiting for one to
120
     * be returned.
121
     *
122
     * @param waitThreshhold
123
     *            the new wait threshhold
124
     */
125
    public static void setWaitThreshhold(int waitThreshhold) {
126
        _waitThreshhold = waitThreshhold;
×
UNCOV
127
    }
×
128

129
    /**
130
     * Instantiates a new pseudo server.
131
     */
132
    public PseudoServer() {
133
        this(DEFAULT_SOCKET_TIMEOUT);
1✔
134
    }
1✔
135

136
    /**
137
     * create a PseudoServer with the given socketTimeout.
138
     *
139
     * @param socketTimeout
140
     *            - the time out to use
141
     */
142
    public PseudoServer(int socketTimeout) {
1✔
143
        _socketTimeout = socketTimeout;
1✔
144
        _serverNum = ++_numServers;
1✔
145

146
        try {
147
            _serverSocket = new ServerSocket(0);
1✔
148
            _serverSocket.setSoTimeout(1000);
1✔
149
        } catch (IOException e) {
×
150
            System.out.println("Error while creating socket: " + e);
×
UNCOV
151
            throw new RuntimeException(e);
×
152
        }
1✔
153
        Thread t = new Thread("PseudoServer " + _serverNum) {
1✔
154
            @Override
155
            public void run() {
156
                while (_active) {
1✔
157
                    try {
158
                        handleNewConnection(_serverSocket.accept());
1✔
159
                        Thread.sleep(20);
1✔
160
                    } catch (InterruptedIOException e) {
1✔
161
                    } catch (IOException e) {
×
162
                        System.out.println("Error in pseudo server: " + e);
×
163
                        HttpUnitUtils.handleException(e);
×
164
                    } catch (InterruptedException e) {
×
165
                        Thread.interrupted();
×
166
                        System.out.println("Interrupted. Shutting down");
×
UNCOV
167
                        _active = false;
×
168
                    }
1✔
169
                }
170
                try {
171
                    _serverSocket.close();
1✔
172
                } catch (IOException e) {
×
UNCOV
173
                    System.out.println("Error while closing socket: " + e);
×
174
                }
1✔
175
                debug("Pseudoserver shutting down");
1✔
176
            }
1✔
177
        };
178
        debug("Starting pseudoserver");
1✔
179
        t.start();
1✔
180
    }
1✔
181

182
    /**
183
     * Shut down.
184
     */
185
    public void shutDown() {
186
        debug("Requested shutdown of pseudoserver");
1✔
187
        _active = false;
1✔
188
    }
1✔
189

190
    /**
191
     * Debug.
192
     *
193
     * @param message
194
     *            the message
195
     */
196
    private void debug(String message) {
197
        if (!_debug) {
1!
198
            return;
1✔
199
        }
200
        message = replaceDebugToken(message, "thread", "thread (" + Thread.currentThread().getName() + ")");
×
201
        message = replaceDebugToken(message, "server", "server " + _serverNum);
×
202
        System.out.println("** " + message);
×
UNCOV
203
    }
×
204

205
    /**
206
     * Replace debug token.
207
     *
208
     * @param message
209
     *            the message
210
     * @param token
211
     *            the token
212
     * @param replacement
213
     *            the replacement
214
     *
215
     * @return the string
216
     */
217
    private static String replaceDebugToken(String message, String token, String replacement) {
UNCOV
218
        return !message.contains(token) ? message : message.replaceFirst(token, replacement);
×
219
    }
220

221
    /**
222
     * Sets the max protocol level.
223
     *
224
     * @param majorLevel
225
     *            the major level
226
     * @param minorLevel
227
     *            the minor level
228
     */
229
    public void setMaxProtocolLevel(int majorLevel, int minorLevel) {
230
        _maxProtocolLevel = majorLevel + "." + minorLevel;
1✔
231
    }
1✔
232

233
    /**
234
     * Returns the port on which this server is listening.
235
     *
236
     * @return the connected port
237
     *
238
     * @throws IOException
239
     *             Signals that an I/O exception has occurred.
240
     */
241
    public int getConnectedPort() throws IOException {
242
        return _serverSocket.getLocalPort();
1✔
243
    }
244

245
    /**
246
     * Defines the contents of an expected resource.
247
     *
248
     * @param name
249
     *            the name
250
     * @param value
251
     *            the value
252
     */
253
    public void setResource(String name, String value) {
254
        setResource(name, value, "text/html");
1✔
255
    }
1✔
256

257
    /**
258
     * Defines the contents of an expected resource.
259
     *
260
     * @param name
261
     *            the name
262
     * @param servlet
263
     *            the servlet
264
     */
265
    public void setResource(String name, PseudoServlet servlet) {
266
        _resources.put(asResourceName(name), servlet);
1✔
267
    }
1✔
268

269
    /**
270
     * Defines the contents of an expected resource.
271
     *
272
     * @param name
273
     *            the name
274
     * @param value
275
     *            the value
276
     * @param contentType
277
     *            the content type
278
     */
279
    public void setResource(String name, String value, String contentType) {
280
        _resources.put(asResourceName(name), new WebResource(value, contentType));
1✔
281
    }
1✔
282

283
    /**
284
     * Defines the contents of an expected resource.
285
     *
286
     * @param name
287
     *            the name
288
     * @param value
289
     *            the value
290
     * @param contentType
291
     *            the content type
292
     */
293
    public void setResource(String name, byte[] value, String contentType) {
294
        _resources.put(asResourceName(name), new WebResource(value, contentType));
1✔
295
    }
1✔
296

297
    /**
298
     * Defines a resource which will result in an error message. return it for further use
299
     *
300
     * @param name
301
     *            the name
302
     * @param errorCode
303
     *            the error code
304
     * @param errorMessage
305
     *            the error message
306
     *
307
     * @return the resource
308
     */
309
    public WebResource setErrorResource(String name, int errorCode, String errorMessage) {
310
        WebResource resource = new WebResource(errorMessage, errorCode);
1✔
311
        _resources.put(asResourceName(name), resource);
1✔
312
        return resource;
1✔
313
    }
314

315
    /**
316
     * Enables the sending of the character set in the content-type header.
317
     *
318
     * @param name
319
     *            the name
320
     * @param enabled
321
     *            the enabled
322
     */
323
    public void setSendCharacterSet(String name, boolean enabled) {
324
        WebResource resource = (WebResource) _resources.get(asResourceName(name));
1✔
325
        if (resource == null) {
1!
UNCOV
326
            throw new IllegalArgumentException("No defined resource " + name);
×
327
        }
328
        resource.setSendCharacterSet(enabled);
1✔
329
    }
1✔
330

331
    /**
332
     * Specifies the character set encoding for a resource.
333
     *
334
     * @param name
335
     *            the name
336
     * @param characterSet
337
     *            the character set
338
     */
339
    public void setCharacterSet(String name, String characterSet) {
340
        WebResource resource = (WebResource) _resources.get(asResourceName(name));
1✔
341
        if (resource == null) {
1!
342
            resource = new WebResource("");
×
UNCOV
343
            _resources.put(asResourceName(name), resource);
×
344
        }
345
        resource.setCharacterSet(characterSet);
1✔
346
    }
1✔
347

348
    /**
349
     * Adds a header to a defined resource.
350
     *
351
     * @param name
352
     *            the name
353
     * @param header
354
     *            the header
355
     */
356
    public void addResourceHeader(String name, String header) {
357
        WebResource resource = (WebResource) _resources.get(asResourceName(name));
1✔
358
        if (resource == null) {
1!
359
            resource = new WebResource("");
×
UNCOV
360
            _resources.put(asResourceName(name), resource);
×
361
        }
362
        resource.addHeader(header);
1✔
363
    }
1✔
364

365
    /**
366
     * Map to classpath.
367
     *
368
     * @param directory
369
     *            the directory
370
     */
371
    public void mapToClasspath(String directory) {
372
        _classpathDirs.add(directory);
1✔
373
    }
1✔
374

375
    /**
376
     * Sets the debug.
377
     *
378
     * @param debug
379
     *            the new debug
380
     */
381
    public void setDebug(boolean debug) {
382
        _debug = debug;
×
UNCOV
383
    }
×
384

385
    // ------------------------------------- private members ---------------------------------------
386

387
    /** The resources. */
388
    private Hashtable _resources = new Hashtable<>();
1✔
389

390
    /** The active. */
391
    private boolean _active = true;
1✔
392

393
    /** The debug. */
394
    private boolean _debug = false;
1✔
395

396
    /**
397
     * As resource name.
398
     *
399
     * @param rawName
400
     *            the raw name
401
     *
402
     * @return the string
403
     */
404
    private String asResourceName(String rawName) {
405
        if (rawName.startsWith("http:") || rawName.startsWith("/")) {
1✔
406
            return escape(rawName);
1✔
407
        }
408
        return escape("/" + rawName);
1✔
409
    }
410

411
    /**
412
     * Escape.
413
     *
414
     * @param urlString
415
     *            the url string
416
     *
417
     * @return the string
418
     */
419
    private static String escape(String urlString) {
420
        if (urlString.indexOf(' ') < 0) {
1✔
421
            return urlString;
1✔
422
        }
423
        StringBuilder sb = new StringBuilder();
1✔
424

425
        int start = 0;
1✔
426
        do {
427
            int index = urlString.indexOf(' ', start);
1✔
428
            if (index < 0) {
1✔
429
                sb.append(urlString.substring(start));
1✔
430
                break;
1✔
431
            }
432
            sb.append(urlString.substring(start, index)).append("%20");
1✔
433
            start = index + 1;
1✔
434
        } while (true);
1✔
435
        return sb.toString();
1✔
436
    }
437

438
    /**
439
     * Handle new connection.
440
     *
441
     * @param socket
442
     *            the socket
443
     */
444
    private void handleNewConnection(final Socket socket) {
445
        Thread t = new Thread("PseudoServer " + _serverNum + " connection " + (++_connectionNum)) {
1✔
446
            @Override
447
            public void run() {
448
                try {
449
                    serveRequests(socket);
1✔
450
                } catch (IOException e) {
×
UNCOV
451
                    e.printStackTrace(); // To change body of catch statement use Options | File Templates.
×
452
                }
1✔
453
            }
1✔
454
        };
455
        t.start();
1✔
456
    }
1✔
457

458
    /**
459
     * Serve requests.
460
     *
461
     * @param socket
462
     *            the socket
463
     *
464
     * @throws IOException
465
     *             Signals that an I/O exception has occurred.
466
     */
467
    private void serveRequests(Socket socket) throws IOException {
468
        socket.setSoTimeout(_socketTimeout);
1✔
469
        socket.setTcpNoDelay(true);
1✔
470

471
        debug("Created server thread " + socket.getInetAddress() + ':' + socket.getPort());
1✔
472
        final BufferedInputStream inputStream = new BufferedInputStream(socket.getInputStream());
1✔
473
        final HttpResponseStream outputStream = new HttpResponseStream(socket.getOutputStream());
1✔
474

475
        try {
476
            while (_active) {
1✔
477
                HttpRequest request = new HttpRequest(inputStream);
1✔
478
                boolean keepAlive = respondToRequest(request, outputStream);
1✔
479
                if (!keepAlive) {
1✔
480
                    break;
1✔
481
                }
482
                while (_active && 0 == inputStream.available()) {
1✔
483
                    try {
484
                        Thread.sleep(INPUT_POLL_INTERVAL);
1✔
485
                    } catch (InterruptedException e) {
×
UNCOV
486
                        Thread.interrupted();
×
487
                    }
1✔
488
                }
489
            }
1✔
490
        } catch (IOException e) {
1✔
491
            outputStream.restart();
1✔
492
            outputStream.setProtocol("HTTP/1.0");
1✔
493
            outputStream.setResponse(HttpURLConnection.HTTP_BAD_REQUEST, e.toString());
1✔
494
        }
1✔
495
        debug("Closing server thread");
1✔
496
        outputStream.close();
1✔
497
        socket.close();
1✔
498
        debug("Server thread closed");
1✔
499
    }
1✔
500

501
    /**
502
     * respond to the given request.
503
     *
504
     * @param request
505
     *            - the request
506
     * @param response
507
     *            - the response stream
508
     *
509
     * @return true, if successful
510
     */
511
    private boolean respondToRequest(HttpRequest request, HttpResponseStream response) {
512
        debug("Server thread handling request: " + request);
1✔
513
        boolean keepAlive = isKeepAlive(request);
1✔
514
        WebResource resource = null;
1✔
515
        try {
516
            response.restart();
1✔
517
            response.setProtocol(getResponseProtocol(request));
1✔
518
            resource = getResource(request);
1✔
519
            if (resource == null) {
1✔
520
                // what resource could not be find?
521
                String uri = request.getURI();
1✔
522
                // 404 - Not Found error code
523
                int errorCode = HttpURLConnection.HTTP_NOT_FOUND;
1✔
524
                // typical 404 error Message
525
                String errorMessage = "unable to find " + uri;
1✔
526
                // make sure there is a resource and
527
                // next time we'll take it from the resource Cache
528
                resource = setErrorResource(uri, errorCode, errorMessage);
1✔
529
                // set the errorCode for this response
530
                response.setResponse(errorCode, errorMessage);
1✔
531
            } else if (resource.getResponseCode() != HttpURLConnection.HTTP_OK) {
1✔
532
                response.setResponse(resource.getResponseCode(), "");
1✔
533
            }
534
            if (resource.closesConnection()) {
1✔
535
                keepAlive = false;
1✔
536
            }
537
            String[] headers = resource.getHeaders();
1✔
538
            for (String header : headers) {
1✔
539
                debug("Server thread sending header: " + header);
1✔
540
                response.addHeader(header);
1✔
541
            }
542
        } catch (UnknownMethodException e) {
1✔
543
            response.setResponse(HttpURLConnection.HTTP_BAD_METHOD, "unsupported method: " + e.getMethod());
1✔
544
        } catch (Throwable t) {
×
545
            t.printStackTrace();
×
UNCOV
546
            response.setResponse(HttpURLConnection.HTTP_INTERNAL_ERROR, t.toString());
×
547
        }
1✔
548
        try {
549
            response.write(resource);
1✔
550
        } catch (IOException e) {
×
UNCOV
551
            System.out.println("*** Failed to send reply: " + e);
×
552
        }
1✔
553
        return keepAlive;
1✔
554
    }
555

556
    /**
557
     * Checks if is keep alive.
558
     *
559
     * @param request
560
     *            the request
561
     *
562
     * @return true, if is keep alive
563
     */
564
    private boolean isKeepAlive(HttpRequest request) {
565
        return request.wantsKeepAlive() && _maxProtocolLevel.equals("1.1");
1!
566
    }
567

568
    /**
569
     * Gets the response protocol.
570
     *
571
     * @param request
572
     *            the request
573
     *
574
     * @return the response protocol
575
     */
576
    private String getResponseProtocol(HttpRequest request) {
577
        return _maxProtocolLevel.equalsIgnoreCase("1.1") ? request.getProtocol() : "HTTP/1.0";
1✔
578
    }
579

580
    /**
581
     * get the resource for the given request by first trying to look it up in the cache then depending on the type of
582
     * request PseudoServlet and the method / command e.g. GET/HEAD finally the extension of the uri ".zip" ".class" and
583
     * ".jar" are handled
584
     *
585
     * @param request
586
     *            the request
587
     *
588
     * @return the WebResource or null if non of the recipes above will lead to a valid resource
589
     *
590
     * @throws IOException
591
     *             Signals that an I/O exception has occurred.
592
     */
593
    private WebResource getResource(HttpRequest request) throws IOException {
594
        Object resource = _resources.get(request.getURI());
1✔
595
        if (resource == null) {
1✔
596
            resource = _resources.get(withoutParameters(request.getURI()));
1✔
597
        }
598

599
        // check the method of the request
600
        String command = request.getCommand();
1✔
601
        if ((command.equals("GET") || command.equals("HEAD")) && resource instanceof WebResource) {
1✔
602
            return (WebResource) resource;
1✔
603
        }
604
        if (resource instanceof PseudoServlet) {
1✔
605
            return getResource((PseudoServlet) resource, request);
1✔
606
        }
607
        if (request.getURI().endsWith(".class")) {
1✔
608
            for (Iterator iterator = _classpathDirs.iterator(); iterator.hasNext();) {
1!
609
                String directory = (String) iterator.next();
1✔
610
                if (request.getURI().startsWith(directory)) {
1!
611
                    String resourceName = request.getURI().substring(directory.length() + 1);
1✔
612
                    return new WebResource(getClass().getClassLoader().getResourceAsStream(resourceName),
1✔
613
                            "application/class", 200);
614
                }
UNCOV
615
            }
×
616
        } else if (request.getURI().endsWith(".zip") || request.getURI().endsWith(".jar")) {
1!
617
            for (Iterator iterator = _classpathDirs.iterator(); iterator.hasNext();) {
×
618
                String directory = (String) iterator.next();
×
619
                if (request.getURI().startsWith(directory)) {
×
620
                    String resourceName = request.getURI().substring(directory.length() + 1);
×
621
                    String classPath = System.getProperty("java.class.path");
×
622
                    StringTokenizer st = new StringTokenizer(classPath, ":;,");
×
623
                    while (st.hasMoreTokens()) {
×
624
                        String file = st.nextToken();
×
625
                        if (file.endsWith(resourceName)) {
×
626
                            Path f = Path.of(file);
×
UNCOV
627
                            return new WebResource(Files.newInputStream(f), "application/zip", 200);
×
628
                        }
UNCOV
629
                    }
×
630
                }
UNCOV
631
            }
×
632
        }
633
        return null;
1✔
634
    }
635

636
    /**
637
     * Without parameters.
638
     *
639
     * @param uri
640
     *            the uri
641
     *
642
     * @return the string
643
     */
644
    private String withoutParameters(String uri) {
645
        return uri.indexOf('?') < 0 ? uri : uri.substring(0, uri.indexOf('?'));
1✔
646
    }
647

648
    /**
649
     * Gets the resource.
650
     *
651
     * @param servlet
652
     *            the servlet
653
     * @param request
654
     *            the request
655
     *
656
     * @return the resource
657
     *
658
     * @throws IOException
659
     *             Signals that an I/O exception has occurred.
660
     */
661
    private WebResource getResource(PseudoServlet servlet, HttpRequest request) throws IOException {
662
        servlet.init(request);
1✔
663
        return servlet.getResponse(request.getCommand());
1✔
664
    }
665

666
    /** The server socket. */
667
    private ServerSocket _serverSocket;
668

669
}
670

671
class HttpResponseStream {
672

673
    private static final String CRLF = "\r\n";
674

675
    void restart() {
676
        _headersWritten = false;
1✔
677
        _headers.clear();
1✔
678
        _responseCode = HttpURLConnection.HTTP_OK;
1✔
679
        _responseText = "OK";
1✔
680
    }
1✔
681

682
    void close() throws IOException {
683
        flushHeaders();
1✔
684
        _pw.close();
1✔
685
    }
1✔
686

687
    HttpResponseStream(OutputStream stream) {
1✔
688
        _stream = stream;
1✔
689
        setCharacterSet("us-ascii");
1✔
690
    }
1✔
691

692
    void setProtocol(String protocol) {
693
        _protocol = protocol;
1✔
694
    }
1✔
695

696
    /**
697
     * set the response to the given response Code
698
     *
699
     * @param responseCode
700
     * @param responseText
701
     */
702
    void setResponse(int responseCode, String responseText) {
703
        _responseCode = responseCode;
1✔
704
        _responseText = responseText;
1✔
705
    }
1✔
706

707
    void addHeader(String header) {
708
        _headers.add(header);
1✔
709
    }
1✔
710

711
    void write(String contents, String charset) throws IOException {
712
        flushHeaders();
×
713
        setCharacterSet(charset);
×
714
        sendText(contents);
×
UNCOV
715
    }
×
716

717
    void write(WebResource resource) throws IOException {
718
        flushHeaders();
1✔
719
        if (resource != null) {
1✔
720
            resource.writeTo(_stream);
1✔
721
        }
722
        _stream.flush();
1✔
723
    }
1✔
724

725
    private void setCharacterSet(String characterSet) {
726
        if (_pw != null) {
1!
UNCOV
727
            _pw.flush();
×
728
        }
729
        _pw = new PrintWriter(new OutputStreamWriter(_stream, Charset.forName(characterSet)));
1✔
730
    }
1✔
731

732
    private void flushHeaders() {
733
        if (!_headersWritten) {
1✔
734
            sendResponse(_responseCode, _responseText);
1✔
735
            for (Enumeration e = Collections.enumeration(_headers); e.hasMoreElements();) {
1✔
736
                sendLine((String) e.nextElement());
1✔
737
            }
738
            sendText(CRLF);
1✔
739
            _headersWritten = true;
1✔
740
            _pw.flush();
1✔
741
        }
742
    }
1✔
743

744
    private void sendResponse(int responseCode, String responseText) {
745
        sendLine(_protocol + ' ' + responseCode + ' ' + responseText);
1✔
746
    }
1✔
747

748
    private void sendLine(String text) {
749
        sendText(text);
1✔
750
        sendText(CRLF);
1✔
751
    }
1✔
752

753
    private void sendText(String text) {
754
        _pw.write(text);
1✔
755
    }
1✔
756

757
    private OutputStream _stream;
758
    private PrintWriter _pw;
759

760
    private List _headers = new ArrayList<>();
1✔
761
    private String _protocol = "HTTP/1.0";
1✔
762
    private int _responseCode = HttpURLConnection.HTTP_OK;
1✔
763
    private String _responseText = "OK";
1✔
764

765
    private boolean _headersWritten;
766

767
}
768

769
class RecordingOutputStream extends OutputStream {
770

771
    private OutputStream _nestedStream;
772
    private PrintStream _log;
773

774
    public RecordingOutputStream(OutputStream nestedStream, PrintStream log) {
×
775
        _nestedStream = nestedStream;
×
776
        _log = log;
×
UNCOV
777
    }
×
778

779
    @Override
780
    public void write(int b) throws IOException {
781
        _nestedStream.write(b);
×
782
        _log.println("sending " + Integer.toHexString(b));
×
UNCOV
783
    }
×
784

785
    @Override
786
    public void write(byte b[], int offset, int len) throws IOException {
787
        _nestedStream.write(b, offset, len);
×
788
        _log.print("sending");
×
789
        for (int i = offset; i < offset + len; i++) {
×
UNCOV
790
            _log.print(' ' + Integer.toHexString(b[i]));
×
791
        }
792
        _log.println();
×
UNCOV
793
    }
×
794
}
795

796
class RecordingInputStream extends InputStream {
797

798
    private InputStream _nestedStream;
799
    private PrintStream _log;
800

801
    public RecordingInputStream(InputStream nestedStream, PrintStream log) {
×
802
        _nestedStream = nestedStream;
×
803
        _log = log;
×
UNCOV
804
    }
×
805

806
    @Override
807
    public int read() throws IOException {
808
        int value = _nestedStream.read();
×
809
        if (value != -1) {
×
UNCOV
810
            _log.print(' ' + Integer.toHexString(value));
×
811
        }
UNCOV
812
        return value;
×
813
    }
814
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc