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

hazendaz / httpunit / 755

14 Feb 2026 07:14PM UTC coverage: 80.526%. Remained the same
755

push

github

hazendaz
[ci] Fix badge

3213 of 4105 branches covered (78.27%)

Branch coverage included in aggregate %.

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

87.79
/src/main/java/com/meterware/servletunit/InvocationContextImpl.java
1
/*
2
 * SPDX-License-Identifier: MIT
3
 * See LICENSE file for details.
4
 *
5
 * Copyright 2000-2026 Russell Gold
6
 * Copyright 2021-2000 hazendaz
7
 */
8
package com.meterware.servletunit;
9

10
import com.meterware.httpunit.AuthorizationRequiredException;
11
import com.meterware.httpunit.FrameSelector;
12
import com.meterware.httpunit.HttpException;
13
import com.meterware.httpunit.WebRequest;
14
import com.meterware.httpunit.WebResponse;
15

16
import jakarta.servlet.*;
17
import jakarta.servlet.http.Cookie;
18
import jakarta.servlet.http.HttpServletRequest;
19
import jakarta.servlet.http.HttpServletResponse;
20
import jakarta.servlet.http.HttpSession;
21

22
import java.io.IOException;
23
import java.net.MalformedURLException;
24
import java.net.URL;
25
import java.util.Dictionary;
26
import java.util.Stack;
27

28
/**
29
 * This class represents the context in which a specific servlet request is being made. It contains the objects needed
30
 * to unit test the methods of a servlet.
31
 **/
32
class InvocationContextImpl implements InvocationContext {
33

34
    /** The context stack. */
35
    private Stack _contextStack = new Stack();
1✔
36

37
    /** The effective URL. */
38
    private URL _effectiveURL;
39

40
    /** The client. */
41
    private ServletUnitClient _client;
42

43
    /** The application. */
44
    private WebApplication _application;
45

46
    /** The frame. */
47
    private FrameSelector _frame;
48

49
    /** The web response. */
50
    private WebResponse _webResponse;
51

52
    /**
53
     * Returns the request to be processed by the servlet or filter.
54
     **/
55
    @Override
56
    public HttpServletRequest getRequest() {
57
        return getContext().getRequest();
1✔
58
    }
59

60
    /**
61
     * Returns the response which the servlet or filter should modify during its operation.
62
     **/
63
    @Override
64
    public HttpServletResponse getResponse() {
65
        return getContext().getResponse();
1✔
66
    }
67

68
    /**
69
     * Invokes the current servlet or filter.
70
     */
71
    @Override
72
    public void service() throws ServletException, IOException {
73
        if (isFilterActive()) {
1✔
74
            getFilter().doFilter(getRequest(), getResponse(), getFilterChain());
1✔
75
        } else {
76
            getServlet().service(getRequest(), getResponse());
1✔
77
        }
78
    }
1✔
79

80
    /**
81
     * Returns the selected servlet, initialized to provide access to sessions and servlet context information.
82
     **/
83
    @Override
84
    public Servlet getServlet() throws ServletException {
85
        return getContext().getServlet();
1✔
86
    }
87

88
    /**
89
     * Returns the final response from the servlet. Note that this method should only be invoked after all processing
90
     * has been done to the servlet response.
91
     **/
92
    @Override
93
    public WebResponse getServletResponse() throws IOException {
94
        if (_contextStack.size() != 1) {
1!
95
            throw new IllegalStateException("Have not returned from all request dispatchers");
×
96
        }
97
        if (_webResponse == null) {
1!
98
            HttpSession session = getRequest().getSession( /* create */ false);
1✔
99
            if (session != null && session.isNew()) {
1✔
100
                Cookie cookie = new Cookie(ServletUnitHttpSession.SESSION_COOKIE_NAME, session.getId());
1✔
101
                cookie.setPath(_application.getContextPath());
1✔
102
                getResponse().addCookie(cookie);
1✔
103
            }
104
            _webResponse = new ServletUnitWebResponse(_client, _frame, _effectiveURL, getResponse(),
1✔
105
                    _client.getExceptionsThrownOnErrorStatus());
1✔
106
        }
107
        return _webResponse;
1✔
108
    }
109

110
    @Override
111
    public FrameSelector getFrame() {
112
        return _frame;
1✔
113
    }
114

115
    @Override
116
    public void pushIncludeRequest(RequestDispatcher rd, HttpServletRequest request, HttpServletResponse response)
117
            throws ServletException {
118
        if (isFilterActive()) {
1!
119
            throw new IllegalStateException("May not push an include request when no servlet is active");
×
120
        }
121
        _contextStack.push(new ExecutionContext(DispatchedRequestWrapper.createIncludeRequestWrapper(request, rd),
1✔
122
                response, ((RequestDispatcherImpl) rd).getServletMetaData()));
1✔
123
    }
1✔
124

125
    @Override
126
    public void pushForwardRequest(RequestDispatcher rd, HttpServletRequest request, HttpServletResponse response)
127
            throws ServletException {
128
        if (isFilterActive()) {
1!
129
            throw new IllegalStateException("May not push a forward request when no servlet is active");
×
130
        }
131
        _contextStack.push(new ExecutionContext(DispatchedRequestWrapper.createForwardRequestWrapper(request, rd),
1✔
132
                response, ((RequestDispatcherImpl) rd).getServletMetaData()));
1✔
133
    }
1✔
134

135
    @Override
136
    public void popRequest() {
137
        if (getContext().mayPopFilter()) {
1✔
138
            getContext().popFilter();
1✔
139
        } else if (_contextStack.size() == 1) {
1!
140
            throw new IllegalStateException("May not pop the initial request");
×
141
        } else {
142
            _contextStack.pop();
1✔
143
        }
144
    }
1✔
145

146
    @Override
147
    public boolean isFilterActive() {
148
        return getContext().isFilterActive();
1✔
149
    }
150

151
    @Override
152
    public Filter getFilter() throws ServletException {
153
        return getContext().getFilter();
1✔
154
    }
155

156
    @Override
157
    public FilterChain getFilterChain() {
158
        return (servletRequest, servletResponse) -> {
1✔
159
            pushFilter(servletRequest, servletResponse);
1✔
160
            service();
1✔
161
            popRequest();
1✔
162
        };
1✔
163
    }
164

165
    @Override
166
    public void pushFilter(ServletRequest request, ServletResponse response) {
167
        getContext().pushFilter(request, response);
1✔
168
    }
1✔
169

170
    /**
171
     * The Class AccessDeniedException.
172
     */
173
    class AccessDeniedException extends HttpException {
174

175
        /** The Constant serialVersionUID. */
176
        private static final long serialVersionUID = 1L;
177

178
        /**
179
         * Instantiates a new access denied exception.
180
         *
181
         * @param baseURL
182
         *            the base URL
183
         */
184
        public AccessDeniedException(URL baseURL) {
1✔
185
            super(403, "Access Denied", baseURL);
1✔
186
        }
1✔
187
    }
188

189
    // ------------------------------ package methods ---------------------------------------
190

191
    /**
192
     * Constructs a servlet invocation context for a specified servlet container, request, and cookie headers.
193
     *
194
     * @param client
195
     *            the client
196
     * @param runner
197
     *            the runner
198
     * @param frame
199
     *            the frame
200
     * @param request
201
     *            the request
202
     * @param clientHeaders
203
     *            the client headers
204
     * @param messageBody
205
     *            the message body
206
     *
207
     * @throws IOException
208
     *             Signals that an I/O exception has occurred.
209
     * @throws MalformedURLException
210
     *             the malformed URL exception
211
     */
212
    InvocationContextImpl(ServletUnitClient client, ServletRunner runner, FrameSelector frame, WebRequest request,
213
            Dictionary clientHeaders, byte[] messageBody) throws IOException, MalformedURLException {
1✔
214
        _client = client;
1✔
215
        _application = runner.getApplication();
1✔
216
        _frame = frame;
1✔
217

218
        URL requestURL = request.getURL();
1✔
219
        final ServletUnitHttpRequest suhr = new ServletUnitHttpRequest(_application.getServletRequest(requestURL),
1✔
220
                request, runner.getContext(), clientHeaders, messageBody);
1✔
221
        if (_application.usesBasicAuthentication()) {
1✔
222
            suhr.readBasicAuthentication();
1✔
223
        } else if (_application.usesFormAuthentication()) {
1✔
224
            suhr.readFormAuthentication();
1✔
225
        }
226

227
        HttpSession session = suhr.getSession( /* create */ false);
1✔
228
        if (session != null) {
1✔
229
            ((ServletUnitHttpSession) session).access();
1✔
230
        }
231

232
        _effectiveURL = computeEffectiveUrl(suhr, requestURL);
1✔
233
        _contextStack.push(new ExecutionContext(suhr, new ServletUnitHttpResponse(),
1✔
234
                _application.getServletRequest(_effectiveURL)));
1✔
235
    }
1✔
236

237
    /**
238
     * Compute effective url.
239
     *
240
     * @param request
241
     *            the request
242
     * @param requestURL
243
     *            the request URL
244
     *
245
     * @return the url
246
     */
247
    private URL computeEffectiveUrl(HttpServletRequest request, URL requestURL) {
248
        if (!_application.requiresAuthorization(requestURL) || userIsAuthorized(request, requestURL)) {
1✔
249
            return requestURL;
1✔
250
        }
251
        if (request.getRemoteUser() != null) {
1✔
252
            throw new AccessDeniedException(requestURL);
1✔
253
        }
254
        if (_application.usesBasicAuthentication()) {
1✔
255
            throw AuthorizationRequiredException
1✔
256
                    .createBasicAuthenticationRequiredException(_application.getAuthenticationRealm());
1✔
257
        }
258
        if (!_application.usesFormAuthentication()) {
1!
259
            throw new IllegalStateException("Authorization required but no authentication method defined");
×
260
        }
261
        ((ServletUnitHttpSession) request.getSession()).setOriginalURL(requestURL);
1✔
262
        return _application.getLoginURL();
1✔
263
    }
264

265
    /**
266
     * User is authorized.
267
     *
268
     * @param request
269
     *            the request
270
     * @param requestURL
271
     *            the request URL
272
     *
273
     * @return true, if successful
274
     */
275
    private boolean userIsAuthorized(HttpServletRequest request, URL requestURL) {
276
        String[] roles = _application.getPermittedRoles(requestURL);
1✔
277
        for (String role : roles) {
1✔
278
            if (request.isUserInRole(role)) {
1✔
279
                return true;
1✔
280
            }
281
        }
282
        return false;
1✔
283
    }
284

285
    /**
286
     * The Class ExecutionContext.
287
     */
288
    static class ExecutionContext {
289

290
        /** The response. */
291
        private HttpServletResponse _response;
292

293
        /** The request. */
294
        private HttpServletRequest _request;
295

296
        /** The meta data. */
297
        private ServletMetaData _metaData;
298

299
        /** The filter stack. */
300
        private Stack _filterStack = new Stack();
1✔
301

302
        /**
303
         * Instantiates a new execution context.
304
         *
305
         * @param request
306
         *            the request
307
         * @param response
308
         *            the response
309
         * @param metaData
310
         *            the meta data
311
         */
312
        ExecutionContext(HttpServletRequest request, HttpServletResponse response, ServletMetaData metaData) {
1✔
313
            _request = request;
1✔
314
            _response = response;
1✔
315
            _metaData = metaData;
1✔
316
        }
1✔
317

318
        /**
319
         * Checks if is filter active.
320
         *
321
         * @return true, if is filter active
322
         */
323
        boolean isFilterActive() {
324
            return getFilterIndex() < _metaData.getFilters().length;
1✔
325
        }
326

327
        /**
328
         * Gets the servlet.
329
         *
330
         * @return the servlet
331
         *
332
         * @throws ServletException
333
         *             the servlet exception
334
         */
335
        Servlet getServlet() throws ServletException {
336
            if (isFilterActive()) {
1!
337
                throw new IllegalStateException("Current context is a filter - may not request servlet.");
×
338
            }
339
            return _metaData.getServlet();
1✔
340
        }
341

342
        /**
343
         * Gets the response.
344
         *
345
         * @return the response
346
         */
347
        HttpServletResponse getResponse() {
348
            return _filterStack.isEmpty() ? _response : ((FilterContext) _filterStack.lastElement()).getResponse();
1✔
349
        }
350

351
        /**
352
         * Gets the request.
353
         *
354
         * @return the request
355
         */
356
        HttpServletRequest getRequest() {
357
            return _filterStack.isEmpty() ? _request : ((FilterContext) _filterStack.lastElement()).getRequest();
1✔
358
        }
359

360
        /**
361
         * Gets the filter.
362
         *
363
         * @return the filter
364
         *
365
         * @throws ServletException
366
         *             the servlet exception
367
         */
368
        public Filter getFilter() throws ServletException {
369
            if (!isFilterActive()) {
1!
370
                throw new IllegalStateException("Current context is a servlet - may not request filter.");
×
371
            }
372
            return _metaData.getFilters()[getFilterIndex()].getFilter();
1✔
373
        }
374

375
        /**
376
         * Push filter.
377
         *
378
         * @param request
379
         *            the request
380
         * @param response
381
         *            the response
382
         */
383
        public void pushFilter(ServletRequest request, ServletResponse response) {
384
            if (!isFilterActive()) {
1!
385
                throw new IllegalStateException("Current context is a servlet - may not push filter.");
×
386
            }
387
            if (!(request instanceof HttpServletRequest)) {
1!
388
                throw new IllegalArgumentException("HttpUnit does not support non-HTTP request wrappers");
×
389
            }
390
            if (!(response instanceof HttpServletResponse)) {
1!
391
                throw new IllegalArgumentException("HttpUnit does not support non-HTTP response wrappers");
×
392
            }
393

394
            _filterStack.push(new FilterContext((HttpServletRequest) request, (HttpServletResponse) response));
1✔
395
        }
1✔
396

397
        /**
398
         * May pop filter.
399
         *
400
         * @return true, if successful
401
         */
402
        public boolean mayPopFilter() {
403
            return getFilterIndex() > 0;
1✔
404
        }
405

406
        /**
407
         * Pop filter.
408
         */
409
        public void popFilter() {
410
            _filterStack.pop();
1✔
411
        }
1✔
412

413
        /**
414
         * Gets the filter index.
415
         *
416
         * @return the filter index
417
         */
418
        private int getFilterIndex() {
419
            return _filterStack.size();
1✔
420
        }
421
    }
422

423
    /**
424
     * The Class FilterContext.
425
     */
426
    static class FilterContext {
427

428
        /** The request. */
429
        HttpServletRequest _request;
430

431
        /** The response. */
432
        HttpServletResponse _response;
433

434
        /**
435
         * Instantiates a new filter context.
436
         *
437
         * @param request
438
         *            the request
439
         * @param response
440
         *            the response
441
         */
442
        public FilterContext(HttpServletRequest request, HttpServletResponse response) {
1✔
443
            _request = request;
1✔
444
            _response = response;
1✔
445
        }
1✔
446

447
        /**
448
         * Gets the response.
449
         *
450
         * @return the response
451
         */
452
        public HttpServletResponse getResponse() {
453
            return _response;
1✔
454
        }
455

456
        /**
457
         * Gets the request.
458
         *
459
         * @return the request
460
         */
461
        public HttpServletRequest getRequest() {
462
            return _request;
1✔
463
        }
464
    }
465

466
    /**
467
     * Gets the context.
468
     *
469
     * @return the context
470
     */
471
    private ExecutionContext getContext() {
472
        return (ExecutionContext) _contextStack.lastElement();
1✔
473
    }
474
}
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