• 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

83.9
/src/main/java/com/meterware/pseudoserver/WebResource.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.IOException;
25
import java.io.InputStream;
26
import java.io.OutputStream;
27
import java.net.HttpURLConnection;
28
import java.nio.charset.Charset;
29
import java.nio.charset.StandardCharsets;
30
import java.util.ArrayList;
31
import java.util.List;
32
import java.util.Locale;
33

34
/**
35
 * A resource to be returned from the simulated server.
36
 **/
37
public class WebResource {
38

39
    /** The Constant DEFAULT_CONTENT_TYPE. */
40
    static final String DEFAULT_CONTENT_TYPE = "text/html";
41

42
    /** The closes connection. */
43
    private boolean _closesConnection;
44

45
    /** The contents. */
46
    private byte[] _contents;
47

48
    /** The string. */
49
    private String _string;
50

51
    /** The stream. */
52
    private InputStream _stream;
53

54
    /** The response code. */
55
    private int _responseCode;
56

57
    /** The send character set. */
58
    private boolean _sendCharacterSet;
59

60
    /** The content type. */
61
    private String _contentType = DEFAULT_CONTENT_TYPE;
1✔
62

63
    /** The character set. */
64
    private String _characterSet = StandardCharsets.ISO_8859_1.name();
1✔
65

66
    /** The has explicit content type header. */
67
    private boolean _hasExplicitContentTypeHeader;
68

69
    /** The has explicit content length header. */
70
    private boolean _hasExplicitContentLengthHeader;
71

72
    /** The headers. */
73
    private List<String> _headers = new ArrayList<>();
1✔
74

75
    /** The is chunked. */
76
    private boolean _isChunked;
77

78
    /**
79
     * Instantiates a new web resource.
80
     *
81
     * @param contents
82
     *            the contents
83
     */
84
    public WebResource(String contents) {
85
        this(contents, DEFAULT_CONTENT_TYPE);
1✔
86
    }
1✔
87

88
    /**
89
     * Instantiates a new web resource.
90
     *
91
     * @param contents
92
     *            the contents
93
     * @param contentType
94
     *            the content type
95
     */
96
    public WebResource(String contents, String contentType) {
97
        this(contents, contentType, HttpURLConnection.HTTP_OK);
1✔
98
    }
1✔
99

100
    /**
101
     * Instantiates a new web resource.
102
     *
103
     * @param contents
104
     *            the contents
105
     * @param contentType
106
     *            the content type
107
     */
108
    public WebResource(byte[] contents, String contentType) {
109
        this(contents, contentType, HttpURLConnection.HTTP_OK);
1✔
110
    }
1✔
111

112
    /**
113
     * Adds the header.
114
     *
115
     * @param header
116
     *            the header
117
     */
118
    public void addHeader(String header) {
119
        _headers.add(header);
1✔
120
        if (header.toLowerCase(Locale.ENGLISH).startsWith("content-type")) {
1✔
121
            _hasExplicitContentTypeHeader = true;
1✔
122
        }
123
        if (header.toLowerCase(Locale.ENGLISH).startsWith("content-length")) {
1✔
124
            _hasExplicitContentLengthHeader = true;
1✔
125
        }
126
        if (header.trim().toLowerCase(Locale.ENGLISH).startsWith("connection")
1✔
127
                && header.trim().toLowerCase(Locale.ENGLISH).endsWith("close")) {
1!
128
            _closesConnection = true;
1✔
129
        }
130
        if (header.trim().toLowerCase(Locale.ENGLISH).startsWith("transfer-encoding")
1✔
131
                && header.trim().toLowerCase(Locale.ENGLISH).endsWith("chunked")) {
1!
132
            _isChunked = true;
1✔
133
        }
134
    }
1✔
135

136
    /**
137
     * Sets the character set.
138
     *
139
     * @param characterSet
140
     *            the new character set
141
     */
142
    public void setCharacterSet(String characterSet) {
143
        _characterSet = characterSet;
1✔
144
    }
1✔
145

146
    /**
147
     * Sets the send character set.
148
     *
149
     * @param enabled
150
     *            the new send character set
151
     */
152
    public void setSendCharacterSet(boolean enabled) {
153
        _sendCharacterSet = enabled;
1✔
154
    }
1✔
155

156
    /**
157
     * Suppress automatic length header.
158
     */
159
    public void suppressAutomaticLengthHeader() {
UNCOV
160
        _hasExplicitContentLengthHeader = true;
×
UNCOV
161
    }
×
162

163
    /**
164
     * Suppress automatic content type header.
165
     */
166
    public void suppressAutomaticContentTypeHeader() {
167
        _hasExplicitContentTypeHeader = true;
1✔
168
    }
1✔
169

170
    /**
171
     * Instantiates a new web resource.
172
     *
173
     * @param contents
174
     *            the contents
175
     * @param responseCode
176
     *            the response code
177
     */
178
    public WebResource(String contents, int responseCode) {
179
        this(contents, DEFAULT_CONTENT_TYPE, responseCode);
1✔
180
    }
1✔
181

182
    /**
183
     * Instantiates a new web resource.
184
     *
185
     * @param contents
186
     *            the contents
187
     * @param contentType
188
     *            the content type
189
     * @param responseCode
190
     *            the response code
191
     */
192
    public WebResource(String contents, String contentType, int responseCode) {
1✔
193
        _string = contents;
1✔
194
        _contentType = contentType;
1✔
195
        _responseCode = responseCode;
1✔
196
    }
1✔
197

198
    /**
199
     * Instantiates a new web resource.
200
     *
201
     * @param contents
202
     *            the contents
203
     * @param contentType
204
     *            the content type
205
     * @param responseCode
206
     *            the response code
207
     */
208
    public WebResource(byte[] contents, String contentType, int responseCode) {
1✔
209
        _contents = contents;
1✔
210
        _contentType = contentType;
1✔
211
        _responseCode = responseCode;
1✔
212
    }
1✔
213

214
    /**
215
     * Instantiates a new web resource.
216
     *
217
     * @param stream
218
     *            the stream
219
     * @param contentType
220
     *            the content type
221
     * @param responseCode
222
     *            the response code
223
     */
224
    public WebResource(InputStream stream, String contentType, int responseCode) {
1✔
225
        _stream = stream;
1✔
226
        _contentType = contentType;
1✔
227
        _responseCode = responseCode;
1✔
228
        addHeader("Connection: close");
1✔
229
    }
1✔
230

231
    /**
232
     * Gets the headers.
233
     *
234
     * @return the headers
235
     */
236
    String[] getHeaders() {
237
        final List<String> effectiveHeaders = new ArrayList<>(_headers);
1✔
238
        if (!_hasExplicitContentTypeHeader) {
1✔
239
            effectiveHeaders.add(getContentTypeHeader());
1✔
240
        }
241
        if (_stream == null && !_hasExplicitContentLengthHeader && !isChunked()) {
1✔
242
            effectiveHeaders.add(getContentLengthHeader());
1✔
243
        }
244
        return effectiveHeaders.toArray(new String[0]);
1✔
245
    }
246

247
    /**
248
     * Checks if is chunked.
249
     *
250
     * @return true, if is chunked
251
     */
252
    private boolean isChunked() {
253
        return _isChunked;
1✔
254
    }
255

256
    /**
257
     * Closes connection.
258
     *
259
     * @return true, if successful
260
     */
261
    boolean closesConnection() {
262
        return _closesConnection;
1✔
263
    }
264

265
    /**
266
     * Write to.
267
     *
268
     * @param outputStream
269
     *            the output stream
270
     *
271
     * @throws IOException
272
     *             Signals that an I/O exception has occurred.
273
     */
274
    void writeTo(OutputStream outputStream) throws IOException {
275
        if (_stream == null) {
1✔
276
            outputStream.write(getContentsAsBytes());
1✔
277
        } else {
278
            byte[] buffer = new byte[8 * 1024];
1✔
279
            int count = 0;
1✔
280
            do {
281
                outputStream.write(buffer, 0, count);
1✔
282
                count = _stream.read(buffer, 0, buffer.length);
1✔
283
            } while (count != -1);
1✔
284
        }
285
    }
1✔
286

287
    /**
288
     * To string.
289
     *
290
     * @param contentsAsBytes
291
     *            the contents as bytes
292
     *
293
     * @return the string
294
     */
295
    static String toString(byte[] contentsAsBytes) {
296
        StringBuilder sb = new StringBuilder();
×
297
        for (byte contentsAsByte : contentsAsBytes) {
×
UNCOV
298
            sb.append(Integer.toHexString(contentsAsByte)).append(' ');
×
299
        }
UNCOV
300
        return sb.toString();
×
301
    }
302

303
    /**
304
     * Gets the contents as bytes.
305
     *
306
     * @return the contents as bytes
307
     */
308
    private byte[] getContentsAsBytes() {
309
        if (_contents != null) {
1✔
310
            return _contents;
1✔
311
        }
312
        if (_string != null) {
1!
313
            return _string.getBytes(getCharacterSet());
1✔
314
        }
UNCOV
315
        throw new IllegalStateException("Cannot get bytes from stream");
×
316
    }
317

318
    /**
319
     * Gets the content type header.
320
     *
321
     * @return the content type header
322
     */
323
    private String getContentTypeHeader() {
324
        return "Content-Type: " + _contentType + getCharacterSetParameter();
1✔
325
    }
326

327
    /**
328
     * Gets the content length header.
329
     *
330
     * @return the content length header
331
     */
332
    private String getContentLengthHeader() {
333
        return "Content-Length: " + getContentsAsBytes().length;
1✔
334
    }
335

336
    /**
337
     * Gets the character set.
338
     *
339
     * @return the character set
340
     */
341
    Charset getCharacterSet() {
342
        return Charset.forName(HttpUnitUtils.stripQuotes(_characterSet));
1✔
343
    }
344

345
    /**
346
     * Gets the character set parameter.
347
     *
348
     * @return the character set parameter
349
     */
350
    String getCharacterSetParameter() {
351
        if (!_sendCharacterSet) {
1✔
352
            return "";
1✔
353
        }
354
        return "; charset=" + _characterSet;
1✔
355
    }
356

357
    /**
358
     * Gets the response code.
359
     *
360
     * @return the response code
361
     */
362
    int getResponseCode() {
363
        return _responseCode;
1✔
364
    }
365

366
    @Override
367
    public String toString() {
368
        return "WebResource [code=" + _responseCode + "; type = " + _contentType + "; charset = " + _characterSet
×
UNCOV
369
                + "]\n" + getContentsAsString();
×
370
    }
371

372
    /**
373
     * Gets the contents as string.
374
     *
375
     * @return the contents as string
376
     */
377
    private String getContentsAsString() {
378
        if (_string != null) {
×
UNCOV
379
            return _string;
×
380
        }
UNCOV
381
        return "<< hex bytes >>";
×
382
    }
383

384
}
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