• 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

64.29
/src/main/java/com/meterware/httpunit/HttpWebResponse.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.httpunit;
21

22
import java.io.BufferedInputStream;
23
import java.io.ByteArrayInputStream;
24
import java.io.IOException;
25
import java.io.InputStream;
26
import java.net.HttpURLConnection;
27
import java.net.URL;
28
import java.net.URLConnection;
29
import java.net.UnknownHostException;
30
import java.nio.charset.Charset;
31
import java.util.ArrayList;
32
import java.util.Enumeration;
33
import java.util.Hashtable;
34
import java.util.List;
35
import java.util.StringTokenizer;
36

37
/**
38
 * A response from a web server to an Http request.
39
 **/
40
class HttpWebResponse extends WebResponse {
41

42
    /** The referer. */
43
    private String _referer;
44

45
    /**
46
     * Constructs a response object from an input stream.
47
     *
48
     * @param client
49
     *            the client
50
     * @param frame
51
     *            the target window or frame to which the request should be directed
52
     * @param url
53
     *            the url from which the response was received
54
     * @param connection
55
     *            the URL connection from which the response can be read
56
     * @param throwExceptionOnError
57
     *            the throw exception on error
58
     *
59
     * @throws IOException
60
     *             Signals that an I/O exception has occurred.
61
     */
62
    HttpWebResponse(WebConversation client, FrameSelector frame, URL url, URLConnection connection,
63
            boolean throwExceptionOnError) throws IOException {
64
        super(client, frame, url);
1✔
65
        if (HttpUnitOptions.isLoggingHttpHeaders()) {
1!
UNCOV
66
            System.out.println("\nReceived from " + url);
×
67
        }
68
        readHeaders(connection);
1✔
69

70
        /** make sure that any IO exception for HTML received page happens here, not later. **/
71
        if (_responseCode < HttpURLConnection.HTTP_BAD_REQUEST || !throwExceptionOnError) {
1✔
72
            InputStream inputStream = getInputStream(connection);
1✔
73
            defineRawInputStream(new BufferedInputStream(inputStream));
1✔
74
            String contentType = getContentType();
1✔
75
            if (contentType.startsWith("text")) {
1✔
76
                loadResponseText();
1✔
77
            }
78
        }
79
    }
1✔
80

81
    /**
82
     * Instantiates a new http web response.
83
     *
84
     * @param client
85
     *            the client
86
     * @param frame
87
     *            the frame
88
     * @param request
89
     *            the request
90
     * @param connection
91
     *            the connection
92
     * @param throwExceptionOnError
93
     *            the throw exception on error
94
     *
95
     * @throws IOException
96
     *             Signals that an I/O exception has occurred.
97
     */
98
    HttpWebResponse(WebConversation client, FrameSelector frame, WebRequest request, URLConnection connection,
99
            boolean throwExceptionOnError) throws IOException {
100
        this(client, frame, request.getURL(), connection, throwExceptionOnError);
1✔
101
        super.setWithParse(!request.getMethod().equals("HEAD"));
1✔
102
        _referer = request.getReferer();
1✔
103
    }
1✔
104

105
    /**
106
     * get the input stream for the given connection.
107
     *
108
     * @param connection
109
     *            the connection
110
     *
111
     * @return the input stream
112
     *
113
     * @throws IOException
114
     *             Signals that an I/O exception has occurred.
115
     */
116
    private InputStream getInputStream(URLConnection connection) throws IOException {
117
        InputStream result = null;
1✔
118
        // check whether there is an error stream
119
        if (isResponseOnErrorStream(connection)) {
1✔
120
            result = ((HttpURLConnection) connection).getErrorStream();
1✔
121
        } else {
122
            // if there is no error stream it depends on the response code
123
            try {
124
                result = connection.getInputStream();
1✔
125
            } catch (java.io.FileNotFoundException fnfe) {
1✔
126
                // as of JDK 1.5 a null inputstream might have been returned here
127
                // see bug report [ 1283878 ] FileNotFoundException using Sun JDK 1.5 on empty error pages
128
                // by Roger Lindsj?
129
                if (!isErrorResponse(connection)) {
1✔
130
                    throw fnfe;
1✔
131
                }
132
                // fake an empty error stream
133
                result = new ByteArrayInputStream(new byte[0]);
1✔
134
            }
1✔
135
        }
136
        return result;
1✔
137
    }
138

139
    /**
140
     * check whether a response code >=400 was received.
141
     *
142
     * @param connection
143
     *            the connection
144
     *
145
     * @return true, if is error response
146
     */
147
    private boolean isErrorResponse(URLConnection connection) {
148
        return _responseCode >= HttpURLConnection.HTTP_BAD_REQUEST;
1✔
149
    }
150

151
    /**
152
     * check whether the response is on the error stream.
153
     *
154
     * @param connection
155
     *            the connection
156
     *
157
     * @return true, if is response on error stream
158
     */
159
    private boolean isResponseOnErrorStream(URLConnection connection) {
160
        return isErrorResponse(connection) && ((HttpURLConnection) connection).getErrorStream() != null;
1✔
161
    }
162

163
    /**
164
     * Returns the response code associated with this response.
165
     **/
166
    @Override
167
    public int getResponseCode() {
168
        return _responseCode;
1✔
169
    }
170

171
    /**
172
     * Returns the response message associated with this response.
173
     **/
174
    @Override
175
    public String getResponseMessage() {
176
        return _responseMessage;
1✔
177
    }
178

179
    @Override
180
    public String[] getHeaderFieldNames() {
181
        List<String> names = new ArrayList<>();
×
182
        for (Enumeration e = _headers.keys(); e.hasMoreElements();) {
×
UNCOV
183
            names.add((String) e.nextElement());
×
184
        }
185
        return names.toArray(new String[0]);
×
186
    }
187

188
    /**
189
     * Returns the value for the specified header field. If no such field is defined, will return null.
190
     **/
191
    @Override
192
    public String getHeaderField(String fieldName) {
193
        String[] fields = (String[]) _headers.get(fieldName.toUpperCase());
1✔
194
        return fields == null ? null : fields[0];
1✔
195
    }
196

197
    @Override
198
    public String[] getHeaderFields(String fieldName) {
199
        String[] fields = (String[]) _headers.get(fieldName.toUpperCase());
1✔
200
        return fields == null ? new String[0] : fields;
1✔
201
    }
202

203
    @Override
204
    public String toString() {
UNCOV
205
        StringBuilder sb = new StringBuilder("HttpWebResponse [url=");
×
206
        sb.append(getURL()).append("; headers=");
×
207
        for (Enumeration e = _headers.keys(); e.hasMoreElements();) {
×
208
            Object key = e.nextElement();
×
209
            String[] values = (String[]) _headers.get(key);
×
210
            for (String value : values) {
×
211
                sb.append("\n   ").append(key).append(": ").append(value);
×
212
            }
UNCOV
213
        }
×
214
        sb.append(" ]");
×
215
        return sb.toString();
×
216
    }
217

218
    @Override
219
    String getReferer() {
220
        return _referer;
1✔
221
    }
222

223
    // ------------------------------------- private members -------------------------------------
224

225
    /** The Constant FILE_ENCODING. */
226
    private static final String FILE_ENCODING = Charset.defaultCharset().displayName();
1✔
227

228
    /** The response code. */
229
    private int _responseCode = HttpURLConnection.HTTP_OK;
1✔
230

231
    /** The response message. */
232
    private String _responseMessage = "OK";
1✔
233

234
    /**
235
     * set the responseCode to the given code and message.
236
     *
237
     * @param code
238
     *            the code
239
     * @param message
240
     *            the message
241
     */
242
    private void setResponseCode(int code, String message) {
243
        _responseCode = code;
1✔
244
        _responseMessage = message;
1✔
245
    }
1✔
246

247
    /** The headers. */
248
    private Hashtable _headers = new Hashtable<>();
1✔
249

250
    /**
251
     * read the response Header for the given connection and set the response code and message accordingly.
252
     *
253
     * @param connection
254
     *            the connection
255
     *
256
     * @throws IOException
257
     *             Signals that an I/O exception has occurred.
258
     */
259
    private void readResponseHeader(HttpURLConnection connection) throws IOException {
260
        if (!needStatusWorkaround()) {
1!
261
            setResponseCode(connection.getResponseCode(), connection.getResponseMessage());
1✔
262
        } else {
UNCOV
263
            if (connection.getHeaderField(0) == null) {
×
264
                throw new UnknownHostException(connection.getURL().toExternalForm());
×
265
            }
266

UNCOV
267
            StringTokenizer st = new StringTokenizer(connection.getHeaderField(0));
×
268
            st.nextToken();
×
269
            if (!st.hasMoreTokens()) {
×
270
                setResponseCode(HttpURLConnection.HTTP_OK, "OK");
×
271
            } else {
272
                try {
UNCOV
273
                    setResponseCode(Integer.parseInt(st.nextToken()), getRemainingTokens(st));
×
274
                } catch (NumberFormatException e) {
×
275
                    setResponseCode(HttpURLConnection.HTTP_INTERNAL_ERROR, "Cannot parse response header");
×
276
                }
×
277
            }
278
        }
279
    }
1✔
280

281
    /**
282
     * Need status workaround.
283
     *
284
     * @return true, if successful
285
     */
286
    private boolean needStatusWorkaround() {
287
        final String jdkVersion = System.getProperty("java.version");
1✔
288
        return jdkVersion.startsWith("1.2") || jdkVersion.startsWith("1.3");
1!
289
    }
290

291
    /**
292
     * Gets the remaining tokens.
293
     *
294
     * @param st
295
     *            the st
296
     *
297
     * @return the remaining tokens
298
     */
299
    private String getRemainingTokens(StringTokenizer st) {
UNCOV
300
        StringBuilder messageBuffer = new StringBuilder(st.hasMoreTokens() ? st.nextToken() : "");
×
301
        while (st.hasMoreTokens()) {
×
302
            messageBuffer.append(' ').append(st.nextToken());
×
303
        }
UNCOV
304
        return messageBuffer.toString();
×
305
    }
306

307
    /**
308
     * Read headers.
309
     *
310
     * @param connection
311
     *            the connection
312
     *
313
     * @throws IOException
314
     *             Signals that an I/O exception has occurred.
315
     */
316
    private void readHeaders(URLConnection connection) throws IOException {
317
        loadHeaders(connection);
1✔
318
        if (connection instanceof HttpURLConnection) {
1✔
319
            readResponseHeader((HttpURLConnection) connection);
1✔
320
        } else {
321
            setResponseCode(HttpURLConnection.HTTP_OK, "OK");
1✔
322
            if (connection.getContentType().startsWith("text")) {
1!
323
                setContentTypeHeader(connection.getContentType() + "; charset=" + FILE_ENCODING);
1✔
324
            }
325
        }
326
    }
1✔
327

328
    /**
329
     * Load headers.
330
     *
331
     * @param connection
332
     *            the connection
333
     */
334
    private void loadHeaders(URLConnection connection) {
335
        if (HttpUnitOptions.isLoggingHttpHeaders()) {
1!
UNCOV
336
            System.out.println("Header:: " + connection.getHeaderField(0));
×
337
        }
338
        for (int i = 1; true; i++) {
1✔
339
            String headerFieldKey = connection.getHeaderFieldKey(i);
1✔
340
            String headerField = connection.getHeaderField(i);
1✔
341
            if (headerFieldKey == null || headerField == null) {
1!
UNCOV
342
                break;
×
343
            }
344
            if (HttpUnitOptions.isLoggingHttpHeaders()) {
1!
UNCOV
345
                System.out.println("Header:: " + headerFieldKey + ": " + headerField);
×
346
            }
347
            addHeader(headerFieldKey.toUpperCase(), headerField);
1✔
348
        }
349

350
        if (connection.getContentType() != null) {
1!
351
            setContentTypeHeader(connection.getContentType());
1✔
352
        }
353
    }
1✔
354

355
    /**
356
     * Adds the header.
357
     *
358
     * @param key
359
     *            the key
360
     * @param field
361
     *            the field
362
     */
363
    private void addHeader(String key, String field) {
364
        _headers.put(key, HttpUnitUtils.withNewValue((String[]) _headers.get(key), field));
1✔
365
    }
1✔
366

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