1
18
19 package io.undertow.servlet.spec;
20
21 import io.undertow.security.api.SecurityContext;
22 import io.undertow.security.idm.Account;
23 import io.undertow.server.HttpServerExchange;
24 import io.undertow.server.RequestTooBigException;
25 import io.undertow.server.handlers.form.FormData;
26 import io.undertow.server.handlers.form.FormDataParser;
27 import io.undertow.server.handlers.form.MultiPartParserDefinition;
28 import io.undertow.server.protocol.http.HttpAttachments;
29 import io.undertow.server.session.Session;
30 import io.undertow.server.session.SessionConfig;
31 import io.undertow.servlet.UndertowServletMessages;
32 import io.undertow.servlet.api.AuthorizationManager;
33 import io.undertow.servlet.api.Deployment;
34 import io.undertow.servlet.api.InstanceFactory;
35 import io.undertow.servlet.api.InstanceHandle;
36 import io.undertow.servlet.core.ManagedServlet;
37 import io.undertow.servlet.core.ServletUpgradeListener;
38 import io.undertow.servlet.handlers.ServletChain;
39 import io.undertow.servlet.handlers.ServletPathMatch;
40 import io.undertow.servlet.handlers.ServletRequestContext;
41 import io.undertow.servlet.util.EmptyEnumeration;
42 import io.undertow.servlet.util.IteratorEnumeration;
43 import io.undertow.util.AttachmentKey;
44 import io.undertow.util.CanonicalPathUtils;
45 import io.undertow.util.DateUtils;
46 import io.undertow.util.HeaderMap;
47 import io.undertow.util.HeaderValues;
48 import io.undertow.util.Headers;
49 import io.undertow.util.HttpString;
50 import io.undertow.util.LocaleUtils;
51
52 import java.io.BufferedReader;
53 import java.io.IOException;
54 import java.io.InputStreamReader;
55 import java.io.UnsupportedEncodingException;
56 import java.net.InetAddress;
57 import java.net.InetSocketAddress;
58 import java.nio.charset.Charset;
59 import java.nio.charset.StandardCharsets;
60 import java.nio.charset.UnsupportedCharsetException;
61 import java.security.AccessController;
62 import java.security.Principal;
63 import java.util.ArrayList;
64 import java.util.Collection;
65 import java.util.Collections;
66 import java.util.Date;
67 import java.util.Deque;
68 import java.util.Enumeration;
69 import java.util.HashMap;
70 import java.util.HashSet;
71 import java.util.Iterator;
72 import java.util.List;
73 import java.util.Locale;
74 import java.util.Map;
75 import java.util.Set;
76 import javax.servlet.AsyncContext;
77 import javax.servlet.DispatcherType;
78 import javax.servlet.MultipartConfigElement;
79 import javax.servlet.RequestDispatcher;
80 import javax.servlet.ServletException;
81 import javax.servlet.ServletInputStream;
82 import javax.servlet.ServletRequest;
83 import javax.servlet.ServletRequestWrapper;
84 import javax.servlet.ServletResponse;
85 import javax.servlet.ServletResponseWrapper;
86 import javax.servlet.http.Cookie;
87 import javax.servlet.http.HttpServletMapping;
88 import javax.servlet.http.HttpServletRequest;
89 import javax.servlet.http.HttpServletResponse;
90 import javax.servlet.http.HttpSession;
91 import javax.servlet.http.HttpUpgradeHandler;
92 import javax.servlet.http.Part;
93 import javax.servlet.http.PushBuilder;
94
95
100 public final class HttpServletRequestImpl implements HttpServletRequest {
101
102 @Deprecated
103 public static final AttachmentKey<Boolean> SECURE_REQUEST = HttpServerExchange.SECURE_REQUEST;
104
105 static final AttachmentKey<Boolean> REQUESTED_SESSION_ID_SET = AttachmentKey.create(Boolean.class);
106 static final AttachmentKey<String> REQUESTED_SESSION_ID = AttachmentKey.create(String.class);
107
108 private final HttpServerExchange exchange;
109 private final ServletContextImpl originalServletContext;
110 private ServletContextImpl servletContext;
111
112 private Map<String, Object> attributes = null;
113
114 private ServletInputStream servletInputStream;
115 private BufferedReader reader;
116
117 private Cookie[] cookies;
118 private List<Part> parts = null;
119 private volatile boolean asyncStarted = false;
120 private volatile AsyncContextImpl asyncContext = null;
121 private Map<String, Deque<String>> queryParameters;
122 private FormData parsedFormData;
123 private RuntimeException formParsingException;
124 private Charset characterEncoding;
125 private boolean readStarted;
126 private SessionConfig.SessionCookieSource sessionCookieSource;
127
128 public HttpServletRequestImpl(final HttpServerExchange exchange, final ServletContextImpl servletContext) {
129 this.exchange = exchange;
130 this.servletContext = servletContext;
131 this.originalServletContext = servletContext;
132 }
133
134 public HttpServerExchange getExchange() {
135 return exchange;
136 }
137
138 @Override
139 public String getAuthType() {
140 SecurityContext securityContext = exchange.getSecurityContext();
141
142 return securityContext != null ? securityContext.getMechanismName() : null;
143 }
144
145 @Override
146 public Cookie[] getCookies() {
147 if (cookies == null) {
148 Map<String, io.undertow.server.handlers.Cookie> cookies = exchange.getRequestCookies();
149 if (cookies.isEmpty()) {
150 return null;
151 }
152 int count = cookies.size();
153 Cookie[] value = new Cookie[count];
154 int i = 0;
155 for (Map.Entry<String, io.undertow.server.handlers.Cookie> entry : cookies.entrySet()) {
156 io.undertow.server.handlers.Cookie cookie = entry.getValue();
157 try {
158 Cookie c = new Cookie(cookie.getName(), cookie.getValue());
159 if (cookie.getDomain() != null) {
160 c.setDomain(cookie.getDomain());
161 }
162 c.setHttpOnly(cookie.isHttpOnly());
163 if (cookie.getMaxAge() != null) {
164 c.setMaxAge(cookie.getMaxAge());
165 }
166 if (cookie.getPath() != null) {
167 c.setPath(cookie.getPath());
168 }
169 c.setSecure(cookie.isSecure());
170 c.setVersion(cookie.getVersion());
171 value[i++] = c;
172 } catch (IllegalArgumentException e) {
173
174 }
175 }
176 if( i < count ) {
177 Cookie[] shrunkCookies = new Cookie[i];
178 System.arraycopy(value, 0, shrunkCookies, 0, i);
179 value = shrunkCookies;
180 }
181 this.cookies = value;
182 }
183 return cookies;
184 }
185
186 @Override
187 public long getDateHeader(final String name) {
188 String header = exchange.getRequestHeaders().getFirst(name);
189 if (header == null) {
190 return -1;
191 }
192 Date date = DateUtils.parseDate(header);
193 if (date == null) {
194 throw UndertowServletMessages.MESSAGES.headerCannotBeConvertedToDate(header);
195 }
196 return date.getTime();
197 }
198
199 @Override
200 public String getHeader(final String name) {
201 HeaderMap headers = exchange.getRequestHeaders();
202 return headers.getFirst(name);
203 }
204
205 public String getHeader(final HttpString name) {
206 HeaderMap headers = exchange.getRequestHeaders();
207 return headers.getFirst(name);
208 }
209
210
211 @Override
212 public Enumeration<String> getHeaders(final String name) {
213 List<String> headers = exchange.getRequestHeaders().get(name);
214 if (headers == null) {
215 return EmptyEnumeration.instance();
216 }
217 return new IteratorEnumeration<>(headers.iterator());
218 }
219
220 @Override
221 public Enumeration<String> getHeaderNames() {
222 final Set<String> headers = new HashSet<>();
223 for (final HttpString i : exchange.getRequestHeaders().getHeaderNames()) {
224 headers.add(i.toString());
225 }
226 return new IteratorEnumeration<>(headers.iterator());
227 }
228
229 @Override
230 public HttpServletMapping getHttpServletMapping() {
231 ServletRequestContext src = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
232 ServletPathMatch match = src.getOriginalServletPathMatch();
233 if(getDispatcherType() == DispatcherType.FORWARD) {
234 match = src.getServletPathMatch();
235 }
236 String matchValue;
237 switch (match.getMappingMatch()) {
238 case EXACT:
239 matchValue = match.getMatched();
240 if(matchValue.startsWith("/")) {
241 matchValue = matchValue.substring(1);
242 }
243 break;
244 case DEFAULT:
245 case CONTEXT_ROOT:
246 matchValue = "";
247 break;
248 case PATH:
249 matchValue = match.getRemaining();
250 if(matchValue.startsWith("/")) {
251 matchValue = matchValue.substring(1);
252 }
253 break;
254 case EXTENSION:
255 matchValue = match.getMatched().substring(0, match.getMatched().length() - match.getMatchString().length() + 1);
256 if(matchValue.startsWith("/")) {
257 matchValue = matchValue.substring(1);
258 }
259 break;
260 default:
261 matchValue = match.getRemaining();
262 }
263 return new MappingImpl(matchValue, match.getMatchString(), match.getMappingMatch(), match.getServletChain().getManagedServlet().getServletInfo().getName());
264 }
265
266 @Override
267 public int getIntHeader(final String name) {
268 String header = getHeader(name);
269 if (header == null) {
270 return -1;
271 }
272 return Integer.parseInt(header);
273 }
274
275 @Override
276 public String getMethod() {
277 return exchange.getRequestMethod().toString();
278 }
279
280 @Override
281 public String getPathInfo() {
282 ServletPathMatch match = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY).getServletPathMatch();
283 if (match != null) {
284 return match.getRemaining();
285 }
286 return null;
287 }
288
289 @Override
290 public String getPathTranslated() {
291 return getRealPath(getPathInfo());
292 }
293
294 @Override
295 public String getContextPath() {
296 return servletContext.getContextPath();
297 }
298
299 @Override
300 public String getQueryString() {
301 return exchange.getQueryString().isEmpty() ? null : exchange.getQueryString();
302 }
303
304 @Override
305 public String getRemoteUser() {
306 Principal userPrincipal = getUserPrincipal();
307
308 return userPrincipal != null ? userPrincipal.getName() : null;
309 }
310
311 @Override
312 public boolean isUserInRole(final String role) {
313 if (role == null) {
314 return false;
315 }
316
317 if (role.equals("*")) {
318 return false;
319 }
320 SecurityContext sc = exchange.getSecurityContext();
321 Account account = sc.getAuthenticatedAccount();
322 if (account == null) {
323 return false;
324 }
325 ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
326
327 if (role.equals("**")) {
328 Set<String> roles = servletRequestContext.getDeployment().getDeploymentInfo().getSecurityRoles();
329 if (!roles.contains("**")) {
330 return true;
331 }
332 }
333
334 final ServletChain servlet = servletRequestContext.getCurrentServlet();
335 final Deployment deployment = servletContext.getDeployment();
336 final AuthorizationManager authorizationManager = deployment.getDeploymentInfo().getAuthorizationManager();
337 return authorizationManager.isUserInRole(role, account, servlet.getManagedServlet().getServletInfo(), this, deployment);
338 }
339
340 @Override
341 public Principal getUserPrincipal() {
342 SecurityContext securityContext = exchange.getSecurityContext();
343 Principal result = null;
344 Account account = null;
345 if (securityContext != null && (account = securityContext.getAuthenticatedAccount()) != null) {
346 result = account.getPrincipal();
347 }
348 return result;
349 }
350
351 @Override
352 public String getRequestedSessionId() {
353 Boolean isRequestedSessionIdSaved = exchange.getAttachment(REQUESTED_SESSION_ID_SET);
354 if (isRequestedSessionIdSaved != null && isRequestedSessionIdSaved) {
355 return exchange.getAttachment(REQUESTED_SESSION_ID);
356 }
357 SessionConfig config = originalServletContext.getSessionConfig();
358 if(config instanceof ServletContextImpl.ServletContextSessionConfig) {
359 return ((ServletContextImpl.ServletContextSessionConfig)config).getDelegate().findSessionId(exchange);
360 }
361 return config.findSessionId(exchange);
362 }
363
364 @Override
365 public String changeSessionId() {
366 HttpSessionImpl session = servletContext.getSession(originalServletContext, exchange, false);
367 if (session == null) {
368 throw UndertowServletMessages.MESSAGES.noSession();
369 }
370 String oldId = session.getId();
371 Session underlyingSession;
372 if(System.getSecurityManager() == null) {
373 underlyingSession = session.getSession();
374 } else {
375 underlyingSession = AccessController.doPrivileged(new HttpSessionImpl.UnwrapSessionAction(session));
376 }
377 String newId = underlyingSession.changeSessionId(exchange, originalServletContext.getSessionConfig());
378 servletContext.getDeployment().getApplicationListeners().httpSessionIdChanged(session, oldId);
379 return newId;
380 }
381
382 @Override
383 public String getRequestURI() {
384
385 if(exchange.isHostIncludedInRequestURI()) {
386
387 String uri = exchange.getRequestURI();
388 int slashes =0;
389 for(int i = 0; i < uri.length(); ++i) {
390 if(uri.charAt(i) == '/') {
391 if(++slashes == 3) {
392 return uri.substring(i);
393 }
394 }
395 }
396 return "/";
397 } else {
398 return exchange.getRequestURI();
399 }
400 }
401
402 @Override
403 public StringBuffer getRequestURL() {
404 return new StringBuffer(exchange.getRequestURL());
405 }
406
407 @Override
408 public String getServletPath() {
409 ServletPathMatch match = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY).getServletPathMatch();
410 if (match != null) {
411 return match.getMatched();
412 }
413 return "";
414 }
415
416 @Override
417 public HttpSession getSession(final boolean create) {
418 return servletContext.getSession(originalServletContext, exchange, create);
419 }
420
421 @Override
422 public HttpSession getSession() {
423 return getSession(true);
424 }
425
426
427 @Override
428 public boolean isRequestedSessionIdValid() {
429 HttpSessionImpl session = servletContext.getSession(originalServletContext, exchange, false);
430 if(session == null) {
431 return false;
432 }
433 if(session.isInvalid()) {
434 return false;
435 }
436 return session.getId().equals(getRequestedSessionId());
437 }
438
439 @Override
440 public boolean isRequestedSessionIdFromCookie() {
441 return sessionCookieSource() == SessionConfig.SessionCookieSource.COOKIE;
442 }
443
444 @Override
445 public boolean isRequestedSessionIdFromURL() {
446 return sessionCookieSource() == SessionConfig.SessionCookieSource.URL;
447 }
448
449 @Override
450 public boolean isRequestedSessionIdFromUrl() {
451 return isRequestedSessionIdFromURL();
452 }
453
454 @Override
455 public boolean authenticate(final HttpServletResponse response) throws IOException, ServletException {
456 if (response.isCommitted()) {
457 throw UndertowServletMessages.MESSAGES.responseAlreadyCommited();
458 }
459
460 SecurityContext sc = exchange.getSecurityContext();
461 sc.setAuthenticationRequired();
462
463
464 if (sc.authenticate()) {
465 if (sc.isAuthenticated()) {
466 return true;
467 } else {
468 throw UndertowServletMessages.MESSAGES.authenticationFailed();
469 }
470 } else {
471 if(!exchange.isResponseStarted() && exchange.getStatusCode() == 200) {
472 throw UndertowServletMessages.MESSAGES.authenticationFailed();
473 } else {
474 return false;
475 }
476 }
477 }
478
479 @Override
480 public void login(final String username, final String password) throws ServletException {
481 if (username == null || password == null) {
482 throw UndertowServletMessages.MESSAGES.loginFailed();
483 }
484 SecurityContext sc = exchange.getSecurityContext();
485 if (sc.isAuthenticated()) {
486 throw UndertowServletMessages.MESSAGES.userAlreadyLoggedIn();
487 }
488 boolean login = false;
489 try {
490 login = sc.login(username, password);
491 }
492 catch (SecurityException se) {
493 if (se.getCause() instanceof ServletException)
494 throw (ServletException) se.getCause();
495 throw new ServletException(se);
496 }
497 if (!login) {
498 throw UndertowServletMessages.MESSAGES.loginFailed();
499 }
500 }
501
502 @Override
503 public void logout() throws ServletException {
504 SecurityContext sc = exchange.getSecurityContext();
505 sc.logout();
506 if(servletContext.getDeployment().getDeploymentInfo().isInvalidateSessionOnLogout()) {
507 HttpSession session = getSession(false);
508 if(session != null) {
509 session.invalidate();
510 }
511 }
512 }
513
514 @Override
515 public Collection<Part> getParts() throws IOException, ServletException {
516 verifyMultipartServlet();
517 if (parts == null) {
518 loadParts();
519 }
520 return parts;
521 }
522
523 private void verifyMultipartServlet() {
524 ServletRequestContext src = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
525 MultipartConfigElement multipart = src.getServletPathMatch().getServletChain().getManagedServlet().getMultipartConfig();
526 if(multipart == null) {
527 throw UndertowServletMessages.MESSAGES.multipartConfigNotPresent();
528 }
529 }
530
531 @Override
532 public Part getPart(final String name) throws IOException, ServletException {
533 verifyMultipartServlet();
534 if (parts == null) {
535 loadParts();
536 }
537 for (Part part : parts) {
538 if (part.getName().equals(name)) {
539 return part;
540 }
541 }
542 return null;
543 }
544
545 @Override
546 public <T extends HttpUpgradeHandler> T upgrade(final Class<T> handlerClass) throws IOException {
547 try {
548 InstanceFactory<T> factory = servletContext.getDeployment().getDeploymentInfo().getClassIntrospecter().createInstanceFactory(handlerClass);
549 final InstanceHandle<T> instance = factory.createInstance();
550 exchange.upgradeChannel(new ServletUpgradeListener<>(instance, servletContext.getDeployment(), exchange));
551 return instance.getInstance();
552 } catch (InstantiationException e) {
553 throw new RuntimeException(e);
554 } catch (NoSuchMethodException e) {
555 throw new RuntimeException(e);
556 }
557 }
558
559 private void loadParts() throws IOException, ServletException {
560 final ServletRequestContext requestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
561
562 if (parts == null) {
563 final List<Part> parts = new ArrayList<>();
564 String mimeType = exchange.getRequestHeaders().getFirst(Headers.CONTENT_TYPE);
565 if (mimeType != null && mimeType.startsWith(MultiPartParserDefinition.MULTIPART_FORM_DATA)) {
566
567 FormData formData = parseFormData();
568 if(formData != null) {
569 for (final String namedPart : formData) {
570 for (FormData.FormValue part : formData.get(namedPart)) {
571 parts.add(new PartImpl(namedPart,
572 part,
573 requestContext.getOriginalServletPathMatch().getServletChain().getManagedServlet().getMultipartConfig(),
574 servletContext, this));
575 }
576 }
577 }
578 } else {
579 throw UndertowServletMessages.MESSAGES.notAMultiPartRequest();
580 }
581 this.parts = parts;
582 }
583 }
584
585 @Override
586 public Object getAttribute(final String name) {
587 if (attributes == null) {
588 return null;
589 }
590 return attributes.get(name);
591 }
592
593 @Override
594 public Enumeration<String> getAttributeNames() {
595 if (attributes == null) {
596 return EmptyEnumeration.instance();
597 }
598 return new IteratorEnumeration<>(attributes.keySet().iterator());
599 }
600
601 @Override
602 public String getCharacterEncoding() {
603 if (characterEncoding != null) {
604 return characterEncoding.name();
605 }
606
607 String characterEncodingFromHeader = getCharacterEncodingFromHeader();
608 if (characterEncodingFromHeader != null) {
609 return characterEncodingFromHeader;
610 }
611
612 if (servletContext.getDeployment().getDeploymentInfo().getDefaultRequestEncoding() != null) {
613 return servletContext.getDeployment().getDeploymentInfo().getDefaultRequestEncoding();
614 }
615
616 if (servletContext.getDeployment().getDeploymentInfo().getDefaultEncoding() != null) {
617 return servletContext.getDeployment().getDeploymentInfo().getDefaultEncoding();
618 }
619 return null;
620 }
621
622 private String getCharacterEncodingFromHeader() {
623 String contentType = exchange.getRequestHeaders().getFirst(Headers.CONTENT_TYPE);
624 if (contentType == null) {
625 return null;
626 }
627
628 return Headers.extractQuotedValueFromHeader(contentType, "charset");
629 }
630
631 @Override
632 public void setCharacterEncoding(final String env) throws UnsupportedEncodingException {
633 if (readStarted) {
634 return;
635 }
636 try {
637 characterEncoding = Charset.forName(env);
638
639 final ManagedServlet originalServlet = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY).getOriginalServletPathMatch().getServletChain().getManagedServlet();
640 final FormDataParser parser = originalServlet.getFormParserFactory().createParser(exchange);
641 if (parser != null) {
642 parser.setCharacterEncoding(env);
643 }
644 } catch (UnsupportedCharsetException e) {
645 throw new UnsupportedEncodingException();
646 }
647 }
648
649 @Override
650 public int getContentLength() {
651 long length = getContentLengthLong();
652 if(length > Integer.MAX_VALUE) {
653 return -1;
654 }
655 return (int)length;
656 }
657
658 @Override
659 public long getContentLengthLong() {
660 final String contentLength = getHeader(Headers.CONTENT_LENGTH);
661 if (contentLength == null || contentLength.isEmpty()) {
662 return -1;
663 }
664 return Long.parseLong(contentLength);
665 }
666
667 @Override
668 public String getContentType() {
669 return getHeader(Headers.CONTENT_TYPE);
670 }
671
672 @Override
673 public ServletInputStream getInputStream() throws IOException {
674 if (reader != null) {
675 throw UndertowServletMessages.MESSAGES.getReaderAlreadyCalled();
676 }
677 if(servletInputStream == null) {
678 servletInputStream = new ServletInputStreamImpl(this);
679 }
680 readStarted = true;
681 return servletInputStream;
682 }
683
684 public void closeAndDrainRequest() throws IOException {
685 try {
686 if (reader != null) {
687 reader.close();
688 }
689 if (servletInputStream == null) {
690 servletInputStream = new ServletInputStreamImpl(this);
691 }
692 servletInputStream.close();
693 } finally {
694 clearAttributes();
695 }
696 }
697
698
702 public void freeResources() throws IOException {
703 try {
704 if(reader != null) {
705 reader.close();
706 }
707 if(servletInputStream != null) {
708 servletInputStream.close();
709 }
710 } finally {
711 clearAttributes();
712 }
713 }
714
715 @Override
716 public String getParameter(final String name) {
717 if(queryParameters == null) {
718 queryParameters = exchange.getQueryParameters();
719 }
720 Deque<String> params = queryParameters.get(name);
721 if (params == null) {
722 final FormData parsedFormData = parseFormData();
723 if (parsedFormData != null) {
724 FormData.FormValue res = parsedFormData.getFirst(name);
725 if (res == null || res.isFileItem()) {
726 return null;
727 } else {
728 return res.getValue();
729 }
730 }
731 return null;
732 }
733 return params.getFirst();
734 }
735
736 @Override
737 public Enumeration<String> getParameterNames() {
738 if (queryParameters == null) {
739 queryParameters = exchange.getQueryParameters();
740 }
741 final Set<String> parameterNames = new HashSet<>(queryParameters.keySet());
742 final FormData parsedFormData = parseFormData();
743 if (parsedFormData != null) {
744 Iterator<String> it = parsedFormData.iterator();
745 while (it.hasNext()) {
746 String name = it.next();
747 for(FormData.FormValue param : parsedFormData.get(name)) {
748 if(!param.isFileItem()) {
749 parameterNames.add(name);
750 break;
751 }
752 }
753 }
754 }
755 return new IteratorEnumeration<>(parameterNames.iterator());
756 }
757
758 @Override
759 public String[] getParameterValues(final String name) {
760 if (queryParameters == null) {
761 queryParameters = exchange.getQueryParameters();
762 }
763 final List<String> ret = new ArrayList<>();
764 Deque<String> params = queryParameters.get(name);
765 if (params != null) {
766 for (String param : params) {
767 ret.add(param);
768 }
769 }
770 final FormData parsedFormData = parseFormData();
771 if (parsedFormData != null) {
772 Deque<FormData.FormValue> res = parsedFormData.get(name);
773 if (res != null) {
774 for (FormData.FormValue value : res) {
775 if(!value.isFileItem()) {
776 ret.add(value.getValue());
777 }
778 }
779 }
780 }
781 if (ret.isEmpty()) {
782 return null;
783 }
784 return ret.toArray(new String[ret.size()]);
785 }
786
787 @Override
788 public Map<String, String[]> getParameterMap() {
789 if (queryParameters == null) {
790 queryParameters = exchange.getQueryParameters();
791 }
792 final Map<String, ArrayList<String>> arrayMap = new HashMap<>();
793 for (Map.Entry<String, Deque<String>> entry : queryParameters.entrySet()) {
794 arrayMap.put(entry.getKey(), new ArrayList<>(entry.getValue()));
795 }
796
797 final FormData parsedFormData = parseFormData();
798 if (parsedFormData != null) {
799 Iterator<String> it = parsedFormData.iterator();
800 while (it.hasNext()) {
801 final String name = it.next();
802 Deque<FormData.FormValue> val = parsedFormData.get(name);
803 if (arrayMap.containsKey(name)) {
804 ArrayList<String> existing = arrayMap.get(name);
805 for (final FormData.FormValue v : val) {
806 if(!v.isFileItem()) {
807 existing.add(v.getValue());
808 }
809 }
810 } else {
811 final ArrayList<String> values = new ArrayList<>();
812 for (final FormData.FormValue v : val) {
813 if(!v.isFileItem()) {
814 values.add(v.getValue());
815 }
816 }
817 if (!values.isEmpty()) {
818 arrayMap.put(name, values);
819 }
820 }
821 }
822 }
823 final Map<String, String[]> ret = new HashMap<>();
824 for(Map.Entry<String, ArrayList<String>> entry : arrayMap.entrySet()) {
825 ret.put(entry.getKey(), entry.getValue().toArray(new String[entry.getValue().size()]));
826 }
827 return ret;
828 }
829
830 private FormData parseFormData() {
831 if(formParsingException != null) {
832 throw formParsingException;
833 }
834 if (parsedFormData == null) {
835 if (readStarted) {
836 return null;
837 }
838 final ManagedServlet originalServlet = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY).getCurrentServlet().getManagedServlet();
839 final FormDataParser parser = originalServlet.getFormParserFactory().createParser(exchange);
840 if (parser == null) {
841 return null;
842 }
843 readStarted = true;
844 try {
845 return parsedFormData = parser.parseBlocking();
846 } catch (RequestTooBigException | MultiPartParserDefinition.FileTooLargeException e) {
847 throw formParsingException = new IllegalStateException(e);
848 } catch (RuntimeException e) {
849 throw formParsingException = e;
850 } catch (IOException e) {
851 throw formParsingException = new RuntimeException(e);
852 }
853 }
854 return parsedFormData;
855 }
856
857 @Override
858 public String getProtocol() {
859 return exchange.getProtocol().toString();
860 }
861
862 @Override
863 public String getScheme() {
864 return exchange.getRequestScheme();
865 }
866
867 @Override
868 public String getServerName() {
869 return exchange.getHostName();
870 }
871
872 @Override
873 public int getServerPort() {
874 return exchange.getHostPort();
875 }
876
877 @Override
878 public BufferedReader getReader() throws IOException {
879 if (reader == null) {
880 if (servletInputStream != null) {
881 throw UndertowServletMessages.MESSAGES.getInputStreamAlreadyCalled();
882 }
883 Charset charSet = null;
884 if (this.characterEncoding != null) {
885 charSet = this.characterEncoding;
886 } else {
887 final String c = getCharacterEncoding();
888 if (c != null) {
889 try {
890 charSet = Charset.forName(c);
891 } catch (UnsupportedCharsetException e) {
892 throw new UnsupportedEncodingException(e.getMessage());
893 }
894 }
895 }
896
897 reader = new BufferedReader(charSet == null ? new InputStreamReader(exchange.getInputStream(), StandardCharsets.ISO_8859_1)
898 : new InputStreamReader(exchange.getInputStream(), charSet));
899 }
900 readStarted = true;
901 return reader;
902 }
903
904 @Override
905 public String getRemoteAddr() {
906 InetSocketAddress sourceAddress = exchange.getSourceAddress();
907 if(sourceAddress == null) {
908 return "";
909 }
910 InetAddress address = sourceAddress.getAddress();
911 if(address == null) {
912
913
914
915 return sourceAddress.getHostString();
916 }
917 return address.getHostAddress();
918 }
919
920 @Override
921 public String getRemoteHost() {
922 InetSocketAddress sourceAddress = exchange.getSourceAddress();
923 if(sourceAddress == null) {
924 return "";
925 }
926 return sourceAddress.getHostString();
927 }
928
929 @Override
930 public void setAttribute(final String name, final Object object) {
931 if(object == null) {
932 removeAttribute(name);
933 return;
934 }
935 if (attributes == null) {
936 attributes = new HashMap<>();
937 }
938 Object existing = attributes.put(name, object);
939 if (existing != null) {
940 servletContext.getDeployment().getApplicationListeners().servletRequestAttributeReplaced(this, name, existing);
941 } else {
942 servletContext.getDeployment().getApplicationListeners().servletRequestAttributeAdded(this, name, object);
943 }
944 }
945
946 @Override
947 public void removeAttribute(final String name) {
948 if (attributes == null) {
949 return;
950 }
951 Object exiting = attributes.remove(name);
952 servletContext.getDeployment().getApplicationListeners().servletRequestAttributeRemoved(this, name, exiting);
953 }
954
955 @Override
956 public Locale getLocale() {
957 return getLocales().nextElement();
958 }
959
960 @Override
961 public Enumeration<Locale> getLocales() {
962 final List<String> acceptLanguage = exchange.getRequestHeaders().get(Headers.ACCEPT_LANGUAGE);
963 List<Locale> ret = LocaleUtils.getLocalesFromHeader(acceptLanguage);
964 if(ret.isEmpty()) {
965 return new IteratorEnumeration<>(Collections.singletonList(Locale.getDefault()).iterator());
966 }
967 return new IteratorEnumeration<>(ret.iterator());
968 }
969
970 @Override
971 public boolean isSecure() {
972 return exchange.isSecure();
973 }
974
975 @Override
976 public RequestDispatcher getRequestDispatcher(final String path) {
977 String realPath;
978 if (path.startsWith("/")) {
979 realPath = path;
980 } else {
981 String current = exchange.getRelativePath();
982 int lastSlash = current.lastIndexOf("/");
983 if (lastSlash != -1) {
984 current = current.substring(0, lastSlash + 1);
985 }
986 realPath = CanonicalPathUtils.canonicalize(current + path);
987 }
988 return new RequestDispatcherImpl(realPath, servletContext);
989 }
990
991 @Override
992 public String getRealPath(final String path) {
993 return servletContext.getRealPath(path);
994 }
995
996 @Override
997 public int getRemotePort() {
998 return exchange.getSourceAddress().getPort();
999 }
1000
1001
1008 @Override
1009 public String getLocalName() {
1010 return exchange.getDestinationAddress().getHostName();
1011 }
1012
1013 @Override
1014 public String getLocalAddr() {
1015 InetSocketAddress destinationAddress = exchange.getDestinationAddress();
1016 if (destinationAddress == null) {
1017 return "";
1018 }
1019 InetAddress address = destinationAddress.getAddress();
1020 if (address == null) {
1021
1022 return destinationAddress.getHostString();
1023 }
1024 return address.getHostAddress();
1025 }
1026
1027 @Override
1028 public int getLocalPort() {
1029 return exchange.getDestinationAddress().getPort();
1030 }
1031
1032 @Override
1033 public ServletContextImpl getServletContext() {
1034 return servletContext;
1035 }
1036
1037 @Override
1038 public AsyncContext startAsync() throws IllegalStateException {
1039 if (!isAsyncSupported()) {
1040 throw UndertowServletMessages.MESSAGES.startAsyncNotAllowed();
1041 } else if (asyncStarted) {
1042 throw UndertowServletMessages.MESSAGES.asyncAlreadyStarted();
1043 }
1044 asyncStarted = true;
1045 final ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
1046 return asyncContext = new AsyncContextImpl(exchange, servletRequestContext.getServletRequest(), servletRequestContext.getServletResponse(), servletRequestContext, false, asyncContext);
1047 }
1048
1049 @Override
1050 public AsyncContext startAsync(final ServletRequest servletRequest, final ServletResponse servletResponse) throws IllegalStateException {
1051 final ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
1052 if (!servletContext.getDeployment().getDeploymentInfo().isAllowNonStandardWrappers()) {
1053 if (servletRequestContext.getOriginalRequest() != servletRequest) {
1054 if (!(servletRequest instanceof ServletRequestWrapper)) {
1055 throw UndertowServletMessages.MESSAGES.requestWasNotOriginalOrWrapper(servletRequest);
1056 }
1057 }
1058 if (servletRequestContext.getOriginalResponse() != servletResponse) {
1059 if (!(servletResponse instanceof ServletResponseWrapper)) {
1060 throw UndertowServletMessages.MESSAGES.responseWasNotOriginalOrWrapper(servletResponse);
1061 }
1062 }
1063 }
1064 if (!isAsyncSupported()) {
1065 throw UndertowServletMessages.MESSAGES.startAsyncNotAllowed();
1066 } else if (asyncStarted) {
1067 throw UndertowServletMessages.MESSAGES.asyncAlreadyStarted();
1068 }
1069 asyncStarted = true;
1070 servletRequestContext.setServletRequest(servletRequest);
1071 servletRequestContext.setServletResponse(servletResponse);
1072 return asyncContext = new AsyncContextImpl(exchange, servletRequest, servletResponse, servletRequestContext, true, asyncContext);
1073 }
1074
1075 @Override
1076 public boolean isAsyncStarted() {
1077 return asyncStarted;
1078 }
1079
1080 @Override
1081 public boolean isAsyncSupported() {
1082 return exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY).isAsyncSupported();
1083 }
1084
1085 @Override
1086 public AsyncContextImpl getAsyncContext() {
1087 if (!isAsyncStarted()) {
1088 throw UndertowServletMessages.MESSAGES.asyncNotStarted();
1089 }
1090 return asyncContext;
1091 }
1092
1093 public AsyncContextImpl getAsyncContextInternal() {
1094 return asyncContext;
1095 }
1096
1097 @Override
1098 public DispatcherType getDispatcherType() {
1099 return exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY).getDispatcherType();
1100 }
1101
1102
1103 public Map<String, Deque<String>> getQueryParameters() {
1104 if (queryParameters == null) {
1105 queryParameters = exchange.getQueryParameters();
1106 }
1107 return queryParameters;
1108 }
1109
1110 public void setQueryParameters(final Map<String, Deque<String>> queryParameters) {
1111 this.queryParameters = queryParameters;
1112 }
1113
1114 public void setServletContext(final ServletContextImpl servletContext) {
1115 this.servletContext = servletContext;
1116 }
1117
1118 void asyncRequestDispatched() {
1119 asyncStarted = false;
1120 }
1121
1122 public String getOriginalRequestURI() {
1123 String uri = (String) getAttribute(RequestDispatcher.FORWARD_REQUEST_URI);
1124 if(uri != null) {
1125 return uri;
1126 }
1127 uri = (String) getAttribute(AsyncContext.ASYNC_REQUEST_URI);
1128 if(uri != null) {
1129 return uri;
1130 }
1131 return getRequestURI();
1132 }
1133
1134
1135 public String getOriginalServletPath() {
1136 String uri = (String) getAttribute(RequestDispatcher.FORWARD_SERVLET_PATH);
1137 if(uri != null) {
1138 return uri;
1139 }
1140 uri = (String) getAttribute(AsyncContext.ASYNC_SERVLET_PATH);
1141 if(uri != null) {
1142 return uri;
1143 }
1144 return getServletPath();
1145 }
1146
1147 public String getOriginalPathInfo() {
1148 String uri = (String) getAttribute(RequestDispatcher.FORWARD_PATH_INFO);
1149 if(uri != null) {
1150 return uri;
1151 }
1152 uri = (String) getAttribute(AsyncContext.ASYNC_PATH_INFO);
1153 if(uri != null) {
1154 return uri;
1155 }
1156 return getPathInfo();
1157 }
1158
1159 public String getOriginalContextPath() {
1160 String uri = (String) getAttribute(RequestDispatcher.FORWARD_CONTEXT_PATH);
1161 if(uri != null) {
1162 return uri;
1163 }
1164 uri = (String) getAttribute(AsyncContext.ASYNC_CONTEXT_PATH);
1165 if(uri != null) {
1166 return uri;
1167 }
1168 return getContextPath();
1169 }
1170
1171 public String getOriginalQueryString() {
1172 String uri = (String) getAttribute(RequestDispatcher.FORWARD_QUERY_STRING);
1173 if(uri != null) {
1174 return uri;
1175 }
1176 uri = (String) getAttribute(AsyncContext.ASYNC_QUERY_STRING);
1177 if(uri != null) {
1178 return uri;
1179 }
1180 return getQueryString();
1181 }
1182
1183 private SessionConfig.SessionCookieSource sessionCookieSource() {
1184 HttpSession session = getSession(false);
1185 if(session == null) {
1186 return SessionConfig.SessionCookieSource.NONE;
1187 }
1188 if(sessionCookieSource == null) {
1189 sessionCookieSource = originalServletContext.getSessionConfig().sessionCookieSource(exchange);
1190 }
1191 return sessionCookieSource;
1192 }
1193
1194 @Override
1195 public String toString() {
1196 return "HttpServletRequestImpl [ " + getMethod() + ' ' + getRequestURI() + " ]";
1197 }
1198
1199 public void clearAttributes() {
1200 if(attributes != null) {
1201 this.attributes.clear();
1202 }
1203 }
1204
1205 @Override
1206 public PushBuilder newPushBuilder() {
1207 if(exchange.getConnection().isPushSupported()) {
1208 return new PushBuilderImpl(this);
1209 }
1210 return null;
1211 }
1212
1213 @Override
1214 public Map<String, String> getTrailerFields() {
1215 HeaderMap trailers = exchange.getAttachment(HttpAttachments.REQUEST_TRAILERS);
1216 if(trailers == null) {
1217 return Collections.emptyMap();
1218 }
1219 Map<String, String> ret = new HashMap<>();
1220 for(HeaderValues entry : trailers) {
1221 ret.put(entry.getHeaderName().toString().toLowerCase(Locale.ENGLISH), entry.getFirst());
1222 }
1223 return ret;
1224 }
1225
1226 @Override
1227 public boolean isTrailerFieldsReady() {
1228 if(exchange.isRequestComplete()) {
1229 return true;
1230 }
1231 return !exchange.getConnection().isRequestTrailerFieldsSupported();
1232 }
1233 }
1234