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

hazendaz / httpunit / 636

05 Dec 2025 03:27AM UTC coverage: 80.509%. Remained the same
636

push

github

hazendaz
Cleanup more old since tags

you guessed it, at this point going to jautodoc the rest so the warnings on builds go away ;)

3213 of 4105 branches covered (78.27%)

Branch coverage included in aggregate %.

8249 of 10132 relevant lines covered (81.42%)

0.81 hits per line

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

89.53
/src/main/java/com/meterware/httpunit/WebWindow.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 com.meterware.httpunit.scripting.ScriptingHandler;
23

24
import java.io.IOException;
25
import java.net.HttpURLConnection;
26
import java.net.MalformedURLException;
27
import java.net.URL;
28
import java.util.Hashtable;
29
import java.util.List;
30
import java.util.Map;
31

32
import org.xml.sax.SAXException;
33

34
/**
35
 * A window managed by a {@link com.meterware.httpunit.WebClient WebClient}.
36
 **/
37
public class WebWindow {
38

39
    /** The client which created this window. **/
40
    private WebClient _client;
41

42
    /** A map of frame names to current contents. **/
43
    private FrameHolder _frameContents;
44

45
    /** The name of the window, set via JavaScript. **/
46
    private String _name = "";
1✔
47

48
    /** The web response containing the reference that opened this window **/
49
    private WebResponse _opener;
50

51
    /** True if this window has been closed. **/
52
    private boolean _closed;
53

54
    static final String NO_NAME = "$$HttpUnit_Window$$_";
55

56
    /**
57
     * The urls that have been encountered as redirect locations in the course of a single client-initiated request
58
     */
59
    private final Map _redirects;
60

61
    /**
62
     * True if seen initial request
63
     */
64
    private boolean _isInitialRequest = true;
1✔
65

66
    /**
67
     * Cache the initial client request to ensure that the _redirects structure gets reset.
68
     */
69
    private WebRequest _initialRequest;
70

71
    /**
72
     * Returns the web client associated with this window.
73
     */
74
    public WebClient getClient() {
75
        return _client;
1✔
76
    }
77

78
    /**
79
     * Returns true if this window has been closed.
80
     */
81
    public boolean isClosed() {
82
        return _closed;
1✔
83
    }
84

85
    /**
86
     * Closes this window.
87
     */
88
    public void close() {
89
        if (!_closed) {
1!
90
            _client.close(this);
1✔
91
        }
92
        _closed = true;
1✔
93
    }
1✔
94

95
    /**
96
     * Returns the name of this window. Windows created through normal HTML or browser commands have empty names, but
97
     * JavaScript can set the name. A name may be used as a target for a request.
98
     */
99
    public String getName() {
100
        return _name;
1✔
101
    }
102

103
    /**
104
     * Returns the web response that contained the script which opened this window.
105
     */
106
    public WebResponse getOpener() {
107
        return _opener;
1✔
108
    }
109

110
    /**
111
     * Submits a GET method request and returns a response.
112
     *
113
     * @exception SAXException
114
     *                thrown if there is an error parsing the retrieved page
115
     **/
116
    public WebResponse getResponse(String urlString) throws IOException, SAXException {
117
        return getResponse(new GetMethodWebRequest(urlString));
1✔
118
    }
119

120
    /**
121
     * Submits a web request and returns a response. This is an alternate name for the getResponse method.
122
     *
123
     * @return the WebResponse or null
124
     **/
125
    public WebResponse sendRequest(WebRequest request) throws IOException, SAXException {
126
        return getResponse(request);
1✔
127
    }
128

129
    /**
130
     * Submits a web request and returns a response, using all state developed so far as stored in cookies as requested
131
     * by the server. see patch [ 1155415 ] Handle redirect instructions which can lead to a loop
132
     *
133
     * @exception SAXException
134
     *                thrown if there is an error parsing the retrieved page
135
     *
136
     * @return the WebResponse or null
137
     **/
138
    public WebResponse getResponse(WebRequest request) throws IOException, SAXException {
139
        // Need to have some sort of ExecuteAroundMethod to ensure that the
140
        // redirects data structure gets cleared down upon exit - not
141
        // straightforward, since this could be a recursive call
142
        if (_isInitialRequest) {
1✔
143
            _initialRequest = request;
1✔
144
            _isInitialRequest = false;
1✔
145
        }
146

147
        WebResponse result = null;
1✔
148

149
        try {
150
            final RequestContext requestContext = new RequestContext();
1✔
151
            final WebResponse response = getSubframeResponse(request, requestContext);
1✔
152
            requestContext.runScripts();
1✔
153
            // javascript might replace the response in its frame
154
            result = response == null ? null : response.getWindow().getFrameContents(response.getFrame());
1✔
155
        } finally {
156
            if (null != request && request.equals(_initialRequest)) {
1!
157
                _redirects.clear();
1✔
158
                _initialRequest = null;
1✔
159
                _isInitialRequest = true;
1✔
160
            }
161
        }
162
        return result;
1✔
163
    }
164

165
    /**
166
     * get a Response from a SubFrame
167
     *
168
     * @param request
169
     * @param requestContext
170
     *
171
     * @return the WebResponse or null
172
     *
173
     * @throws IOException
174
     * @throws SAXException
175
     */
176
    WebResponse getSubframeResponse(WebRequest request, RequestContext requestContext)
177
            throws IOException, SAXException {
178
        WebResponse response = getResource(request);
1✔
179

180
        return response == null ? null : updateWindow(request.getTarget(), response, requestContext);
1✔
181
    }
182

183
    /**
184
     * Updates this web client based on a received response. This includes updating cookies and frames.
185
     **/
186
    WebResponse updateWindow(String requestTarget, WebResponse response, RequestContext requestContext)
187
            throws IOException, SAXException {
188
        _client.updateClient(response);
1✔
189
        if (getClient().getClientProperties().isAutoRefresh() && response.getRefreshRequest() != null) {
1✔
190
            WebRequest request = response.getRefreshRequest();
1✔
191
            return getResponse(request);
1✔
192
        }
193
        if (shouldFollowRedirect(response)) {
1✔
194
            delay(HttpUnitOptions.getRedirectDelay());
1✔
195
            return getResponse(new RedirectWebRequest(response));
1✔
196
        }
197
        _client.updateFrameContents(this, requestTarget, response, requestContext);
1✔
198
        return response;
1✔
199
    }
200

201
    /**
202
     * Returns the resource specified by the request. Does not update the window or load included framesets. May return
203
     * null if the resource is a JavaScript URL which would normally leave the client unchanged.
204
     */
205
    public WebResponse getResource(WebRequest request) throws IOException {
206
        _client.tellListeners(request);
1✔
207

208
        WebResponse response = null;
1✔
209
        String urlString = request.getURLString().trim();
1✔
210
        FrameSelector targetFrame = _frameContents.getTargetFrame(request);
1✔
211
        if (urlString.startsWith("about:")) {
1✔
212
            response = new DefaultWebResponse(_client, targetFrame, null, "");
1✔
213
        } else if (!HttpUnitUtils.isJavaScriptURL(urlString)) {
1✔
214
            response = _client.createResponse(request, targetFrame);
1✔
215
        } else {
216
            ScriptingHandler handler = request.getSourceScriptingHandler();
1✔
217
            if (handler == null) {
1!
218
                handler = getCurrentPage().getScriptingHandler();
1✔
219
            }
220
            Object result = handler.evaluateExpression(urlString);
1✔
221
            if (result != null) {
1✔
222
                response = new DefaultWebResponse(_client, targetFrame, request.getURL(), result.toString());
1✔
223
            }
224
        }
225

226
        if (response != null) {
1✔
227
            _client.tellListeners(response);
1✔
228
        }
229
        return response;
1✔
230
    }
231

232
    /**
233
     * Returns the name of the currently active frames.
234
     **/
235
    public String[] getFrameNames() {
236
        final List<String> names = _frameContents.getActiveFrameNames();
1✔
237
        return names.toArray(new String[names.size()]);
1✔
238
    }
239

240
    /**
241
     * Returns true if the specified frame name is defined in this window.
242
     */
243
    public boolean hasFrame(String frameName) {
244
        return _frameContents.get(frameName) != null;
×
245
    }
246

247
    boolean hasFrame(FrameSelector frame) {
248
        return _frameContents.get(frame) != null;
1✔
249
    }
250

251
    /**
252
     * Returns the response associated with the specified frame name. Throws a runtime exception if no matching frame is
253
     * defined.
254
     **/
255
    public WebResponse getFrameContents(String frameName) {
256
        WebResponse response = _frameContents.get(frameName);
1✔
257
        if (response == null) {
1!
258
            throw new NoSuchFrameException(frameName);
×
259
        }
260
        return response;
1✔
261
    }
262

263
    /**
264
     * Returns the response associated with the specified frame target. Throws a runtime exception if no matching frame
265
     * is defined.
266
     **/
267
    WebResponse getFrameContents(FrameSelector targetFrame) {
268
        return _frameContents.getFrameContents(targetFrame);
1✔
269
    }
270

271
    WebResponse getSubframeContents(FrameSelector frame, String subFrameName) {
272
        return _frameContents.getSubframeContents(frame, subFrameName);
1✔
273
    }
274

275
    WebResponse getParentFrameContents(FrameSelector frame) {
276
        return _frameContents.getParentFrameContents(frame);
1✔
277
    }
278

279
    /**
280
     * Returns the response representing the main page in this window.
281
     */
282
    public WebResponse getCurrentPage() {
283
        return getFrameContents(WebRequest.TOP_FRAME);
1✔
284
    }
285

286
    /**
287
     * construct a WebWindow from a given client
288
     *
289
     * @param client
290
     *            - the client to construct me from
291
     */
292
    WebWindow(WebClient client) {
1✔
293
        _client = client;
1✔
294
        _frameContents = new FrameHolder(this);
1✔
295
        _name = NO_NAME + _client.getOpenWindows().length;
1✔
296
        _redirects = new Hashtable<>();
1✔
297
    }
1✔
298

299
    WebWindow(WebClient client, WebResponse opener) {
300
        this(client);
1✔
301
        _opener = opener;
1✔
302
    }
1✔
303

304
    void updateFrameContents(WebResponse response, RequestContext requestContext) throws IOException, SAXException {
305
        response.setWindow(this);
1✔
306
        _frameContents.updateFrames(response, response.getFrame(), requestContext);
1✔
307
    }
1✔
308

309
    void setName(String name) {
310
        _name = name;
1✔
311
    }
1✔
312

313
    /**
314
     * Delays the specified amount of time.
315
     **/
316
    private void delay(int numMilliseconds) {
317
        if (numMilliseconds == 0) {
1!
318
            return;
1✔
319
        }
320
        try {
321
            Thread.sleep(numMilliseconds);
×
322
        } catch (InterruptedException e) {
×
323
            // ignore the exception
324
            Thread.interrupted();
×
325
        }
×
326
    }
×
327

328
    /**
329
     * check whether redirect is configured
330
     *
331
     * @param response
332
     *
333
     * @return
334
     */
335
    private boolean redirectConfigured(WebResponse response) {
336
        boolean isAutoredirect = getClient().getClientProperties().isAutoRedirect();
1✔
337
        boolean hasLocation = response.getHeaderField("Location") != null;
1✔
338
        int responseCode = response.getResponseCode();
1✔
339
        return isAutoredirect && responseCode >= HttpURLConnection.HTTP_MOVED_PERM
1!
340
                && responseCode <= HttpURLConnection.HTTP_MOVED_TEMP && hasLocation;
341
    }
342

343
    /**
344
     * check wether we should follow the redirect given in the response make sure we don't run into a recursion
345
     *
346
     * @param response
347
     *
348
     * @return
349
     */
350
    private boolean shouldFollowRedirect(WebResponse response) {
351
        // first check whether redirect is configured for this response
352
        // this is the old pre [ 1155415 ] Handle redirect instructions which can lead to a loop
353
        // shouldFollowRedirect method - just renamed
354
        if (!redirectConfigured(response)) {
1✔
355
            return false;
1✔
356
        }
357
        // now do the recursion check
358
        String redirectLocation = response.getHeaderField("Location");
1✔
359

360
        URL url = null;
1✔
361

362
        try {
363
            if (redirectLocation != null) {
1!
364
                url = new URL(response.getURL(), redirectLocation);
1✔
365
            }
366
        } catch (MalformedURLException e) {
1✔
367
            // Fall through and allow existing exception handling code deal
368
            // with any exception - we don't know at this stage whether it is
369
            // a redirect instruction, although it is highly likely, given
370
            // there is a location header present in the response!
371
        }
1✔
372

373
        switch (response.getResponseCode()) {
1!
374
            case HttpURLConnection.HTTP_MOVED_PERM:
375
            case HttpURLConnection.HTTP_MOVED_TEMP: // Fall through
376
                int count = 0;
1✔
377
                if (null != url) {
1✔
378
                    Integer value = (Integer) _redirects.get(url);
1✔
379
                    if (null != value) {
1✔
380
                        // We have already been instructed to redirect to that
381
                        // location in the course of this attempt to resolve the
382
                        // resource
383

384
                        count = value.intValue();
1✔
385

386
                        int maxRedirects = getClient().getClientProperties().getMaxRedirects();
1✔
387

388
                        if (count == maxRedirects) {
1✔
389
                            throw new RecursiveRedirectionException(url, "Maximum number of redirects exceeded");
1✔
390
                        }
391
                    }
392

393
                    count++;
1✔
394
                    _redirects.put(url, Integer.valueOf(count));
1✔
395
                }
396
                break;
397
        }
398
        return redirectLocation != null;
1!
399
    }
400

401
    FrameSelector getTopFrame() {
402
        return _frameContents.getTopFrame();
1✔
403
    }
404

405
    FrameSelector getFrame(String target) {
406
        return _frameContents.getFrame(target);
1✔
407
    }
408

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