package io.undertow.servlet.spec;
import io.undertow.security.api.SecurityContext;
import io.undertow.security.idm.Account;
import io.undertow.server.HttpServerExchange;
import io.undertow.server.RequestTooBigException;
import io.undertow.server.handlers.form.FormData;
import io.undertow.server.handlers.form.FormDataParser;
import io.undertow.server.handlers.form.MultiPartParserDefinition;
import io.undertow.server.protocol.http.HttpAttachments;
import io.undertow.server.session.Session;
import io.undertow.server.session.SessionConfig;
import io.undertow.servlet.UndertowServletMessages;
import io.undertow.servlet.api.AuthorizationManager;
import io.undertow.servlet.api.Deployment;
import io.undertow.servlet.api.InstanceFactory;
import io.undertow.servlet.api.InstanceHandle;
import io.undertow.servlet.core.ManagedServlet;
import io.undertow.servlet.core.ServletUpgradeListener;
import io.undertow.servlet.handlers.ServletChain;
import io.undertow.servlet.handlers.ServletPathMatch;
import io.undertow.servlet.handlers.ServletRequestContext;
import io.undertow.servlet.util.EmptyEnumeration;
import io.undertow.servlet.util.IteratorEnumeration;
import io.undertow.util.AttachmentKey;
import io.undertow.util.CanonicalPathUtils;
import io.undertow.util.DateUtils;
import io.undertow.util.HeaderMap;
import io.undertow.util.HeaderValues;
import io.undertow.util.Headers;
import io.undertow.util.HttpString;
import io.undertow.util.LocaleUtils;
import io.undertow.util.Methods;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
import java.security.AccessController;
import java.security.Principal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Deque;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.servlet.AsyncContext;
import javax.servlet.DispatcherType;
import javax.servlet.MultipartConfigElement;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
import javax.servlet.ServletRequest;
import javax.servlet.ServletRequestWrapper;
import javax.servlet.ServletResponse;
import javax.servlet.ServletResponseWrapper;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletMapping;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpUpgradeHandler;
import javax.servlet.http.Part;
import javax.servlet.http.PushBuilder;
public final class HttpServletRequestImpl implements HttpServletRequest {
@Deprecated
public static final AttachmentKey<Boolean> SECURE_REQUEST = HttpServerExchange.SECURE_REQUEST;
private final HttpServerExchange exchange;
private final ServletContextImpl originalServletContext;
private ServletContextImpl servletContext;
private Map<String, Object> attributes = null;
private ServletInputStream servletInputStream;
private BufferedReader reader;
private Cookie[] cookies;
private List<Part> parts = null;
private volatile boolean asyncStarted = false;
private volatile boolean asyncCancelled = false;
private volatile AsyncContextImpl asyncContext = null;
private Map<String, Deque<String>> queryParameters;
private FormData parsedFormData;
private RuntimeException formParsingException;
private Charset characterEncoding;
private boolean readStarted;
private SessionConfig.SessionCookieSource sessionCookieSource;
public HttpServletRequestImpl(final HttpServerExchange exchange, final ServletContextImpl servletContext) {
this.exchange = exchange;
this.servletContext = servletContext;
this.originalServletContext = servletContext;
}
public HttpServerExchange getExchange() {
return exchange;
}
@Override
public String getAuthType() {
SecurityContext securityContext = exchange.getSecurityContext();
return securityContext != null ? securityContext.getMechanismName() : null;
}
@Override
public Cookie[] getCookies() {
if (cookies == null) {
Map<String, io.undertow.server.handlers.Cookie> cookies = exchange.getRequestCookies();
if (cookies.isEmpty()) {
return null;
}
int count = cookies.size();
Cookie[] value = new Cookie[count];
int i = 0;
for (Map.Entry<String, io.undertow.server.handlers.Cookie> entry : cookies.entrySet()) {
io.undertow.server.handlers.Cookie cookie = entry.getValue();
try {
Cookie c = new Cookie(cookie.getName(), cookie.getValue());
if (cookie.getDomain() != null) {
c.setDomain(cookie.getDomain());
}
c.setHttpOnly(cookie.isHttpOnly());
if (cookie.getMaxAge() != null) {
c.setMaxAge(cookie.getMaxAge());
}
if (cookie.getPath() != null) {
c.setPath(cookie.getPath());
}
c.setSecure(cookie.isSecure());
c.setVersion(cookie.getVersion());
value[i++] = c;
} catch (IllegalArgumentException e) {
}
}
if( i < count ) {
Cookie[] shrunkCookies = new Cookie[i];
System.arraycopy(value, 0, shrunkCookies, 0, i);
value = shrunkCookies;
}
this.cookies = value;
}
return cookies;
}
@Override
public long (final String name) {
String header = exchange.getRequestHeaders().getFirst(name);
if (header == null) {
return -1;
}
Date date = DateUtils.parseDate(header);
if (date == null) {
throw UndertowServletMessages.MESSAGES.headerCannotBeConvertedToDate(header);
}
return date.getTime();
}
@Override
public String (final String name) {
HeaderMap headers = exchange.getRequestHeaders();
return headers.getFirst(name);
}
public String (final HttpString name) {
HeaderMap headers = exchange.getRequestHeaders();
return headers.getFirst(name);
}
@Override
public Enumeration<String> (final String name) {
List<String> headers = exchange.getRequestHeaders().get(name);
if (headers == null) {
return EmptyEnumeration.instance();
}
return new IteratorEnumeration<>(headers.iterator());
}
@Override
public Enumeration<String> () {
final Set<String> headers = new HashSet<>();
for (final HttpString i : exchange.getRequestHeaders().getHeaderNames()) {
headers.add(i.toString());
}
return new IteratorEnumeration<>(headers.iterator());
}
@Override
public HttpServletMapping getHttpServletMapping() {
ServletRequestContext src = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
ServletPathMatch match = src.getOriginalServletPathMatch();
if(getDispatcherType() == DispatcherType.FORWARD) {
match = src.getServletPathMatch();
}
String matchValue;
switch (match.getMappingMatch()) {
case EXACT:
matchValue = match.getMatched();
if(matchValue.startsWith("/")) {
matchValue = matchValue.substring(1);
}
break;
case DEFAULT:
case CONTEXT_ROOT:
matchValue = "";
break;
case PATH:
matchValue = match.getRemaining();
if(matchValue.startsWith("/")) {
matchValue = matchValue.substring(1);
}
break;
case EXTENSION:
matchValue = match.getMatched().substring(0, match.getMatched().length() - match.getMatchString().length() + 1);
if(matchValue.startsWith("/")) {
matchValue = matchValue.substring(1);
}
break;
default:
matchValue = match.getRemaining();
}
return new MappingImpl(matchValue, match.getMatchString(), match.getMappingMatch(), match.getServletChain().getManagedServlet().getServletInfo().getName());
}
@Override
public int (final String name) {
String header = getHeader(name);
if (header == null) {
return -1;
}
return Integer.parseInt(header);
}
@Override
public String getMethod() {
return exchange.getRequestMethod().toString();
}
@Override
public String getPathInfo() {
ServletPathMatch match = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY).getServletPathMatch();
if (match != null) {
return match.getRemaining();
}
return null;
}
@Override
public String getPathTranslated() {
return getRealPath(getPathInfo());
}
@Override
public String getContextPath() {
return servletContext.getContextPath();
}
@Override
public String getQueryString() {
return exchange.getQueryString().isEmpty() ? null : exchange.getQueryString();
}
@Override
public String getRemoteUser() {
Principal userPrincipal = getUserPrincipal();
return userPrincipal != null ? userPrincipal.getName() : null;
}
@Override
public boolean isUserInRole(final String role) {
if (role == null) {
return false;
}
if (role.equals("*")) {
return false;
}
SecurityContext sc = exchange.getSecurityContext();
Account account = sc.getAuthenticatedAccount();
if (account == null) {
return false;
}
ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
if (role.equals("**")) {
Set<String> roles = servletRequestContext.getDeployment().getDeploymentInfo().getSecurityRoles();
if (!roles.contains("**")) {
return true;
}
}
final ServletChain servlet = servletRequestContext.getCurrentServlet();
final Deployment deployment = servletContext.getDeployment();
final AuthorizationManager authorizationManager = deployment.getDeploymentInfo().getAuthorizationManager();
return authorizationManager.isUserInRole(role, account, servlet.getManagedServlet().getServletInfo(), this, deployment);
}
@Override
public Principal getUserPrincipal() {
SecurityContext securityContext = exchange.getSecurityContext();
Principal result = null;
Account account = null;
if (securityContext != null && (account = securityContext.getAuthenticatedAccount()) != null) {
result = account.getPrincipal();
}
return result;
}
@Override
public String getRequestedSessionId() {
SessionConfig config = originalServletContext.getSessionConfig();
if(config instanceof ServletContextImpl.ServletContextSessionConfig) {
return ((ServletContextImpl.ServletContextSessionConfig)config).getDelegate().findSessionId(exchange);
}
return config.findSessionId(exchange);
}
@Override
public String changeSessionId() {
HttpSessionImpl session = servletContext.getSession(originalServletContext, exchange, false);
if (session == null) {
throw UndertowServletMessages.MESSAGES.noSession();
}
String oldId = session.getId();
Session underlyingSession;
if(System.getSecurityManager() == null) {
underlyingSession = session.getSession();
} else {
underlyingSession = AccessController.doPrivileged(new HttpSessionImpl.UnwrapSessionAction(session));
}
String newId = underlyingSession.changeSessionId(exchange, originalServletContext.getSessionConfig());
servletContext.getDeployment().getApplicationListeners().httpSessionIdChanged(session, oldId);
return newId;
}
@Override
public String getRequestURI() {
if(exchange.isHostIncludedInRequestURI()) {
String uri = exchange.getRequestURI();
int slashes =0;
for(int i = 0; i < uri.length(); ++i) {
if(uri.charAt(i) == '/') {
if(++slashes == 3) {
return uri.substring(i);
}
}
}
return "/";
} else {
return exchange.getRequestURI();
}
}
@Override
public StringBuffer getRequestURL() {
return new StringBuffer(exchange.getRequestURL());
}
@Override
public String getServletPath() {
ServletPathMatch match = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY).getServletPathMatch();
if (match != null) {
return match.getMatched();
}
return "";
}
@Override
public HttpSession getSession(final boolean create) {
return servletContext.getSession(originalServletContext, exchange, create);
}
@Override
public HttpSession getSession() {
return getSession(true);
}
@Override
public boolean isRequestedSessionIdValid() {
HttpSessionImpl session = servletContext.getSession(originalServletContext, exchange, false);
if(session == null) {
return false;
}
if(session.isInvalid()) {
return false;
}
return session.getId().equals(getRequestedSessionId());
}
@Override
public boolean isRequestedSessionIdFromCookie() {
return sessionCookieSource() == SessionConfig.SessionCookieSource.COOKIE;
}
@Override
public boolean isRequestedSessionIdFromURL() {
return sessionCookieSource() == SessionConfig.SessionCookieSource.URL;
}
@Override
public boolean isRequestedSessionIdFromUrl() {
return isRequestedSessionIdFromURL();
}
@Override
public boolean authenticate(final HttpServletResponse response) throws IOException, ServletException {
if (response.isCommitted()) {
throw UndertowServletMessages.MESSAGES.responseAlreadyCommited();
}
SecurityContext sc = exchange.getSecurityContext();
sc.setAuthenticationRequired();
if (sc.authenticate()) {
if (sc.isAuthenticated()) {
return true;
} else {
throw UndertowServletMessages.MESSAGES.authenticationFailed();
}
} else {
if(!exchange.isResponseStarted() && exchange.getStatusCode() == 200) {
throw UndertowServletMessages.MESSAGES.authenticationFailed();
} else {
return false;
}
}
}
@Override
public void login(final String username, final String password) throws ServletException {
if (username == null || password == null) {
throw UndertowServletMessages.MESSAGES.loginFailed();
}
SecurityContext sc = exchange.getSecurityContext();
if (sc.isAuthenticated()) {
throw UndertowServletMessages.MESSAGES.userAlreadyLoggedIn();
}
boolean login = false;
try {
login = sc.login(username, password);
}
catch (SecurityException se) {
if (se.getCause() instanceof ServletException)
throw (ServletException) se.getCause();
throw new ServletException(se);
}
if (!login) {
throw UndertowServletMessages.MESSAGES.loginFailed();
}
}
@Override
public void logout() throws ServletException {
SecurityContext sc = exchange.getSecurityContext();
sc.logout();
if(servletContext.getDeployment().getDeploymentInfo().isInvalidateSessionOnLogout()) {
HttpSession session = getSession(false);
if(session != null) {
session.invalidate();
}
}
}
@Override
public Collection<Part> getParts() throws IOException, ServletException {
verifyMultipartServlet();
if (parts == null) {
loadParts();
}
return parts;
}
private void verifyMultipartServlet() {
ServletRequestContext src = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
MultipartConfigElement multipart = src.getServletPathMatch().getServletChain().getManagedServlet().getMultipartConfig();
if(multipart == null) {
throw UndertowServletMessages.MESSAGES.multipartConfigNotPresent();
}
}
@Override
public Part getPart(final String name) throws IOException, ServletException {
verifyMultipartServlet();
if (parts == null) {
loadParts();
}
for (Part part : parts) {
if (part.getName().equals(name)) {
return part;
}
}
return null;
}
@Override
public <T extends HttpUpgradeHandler> T upgrade(final Class<T> handlerClass) throws IOException {
try {
InstanceFactory<T> factory = servletContext.getDeployment().getDeploymentInfo().getClassIntrospecter().createInstanceFactory(handlerClass);
final InstanceHandle<T> instance = factory.createInstance();
exchange.upgradeChannel(new ServletUpgradeListener<>(instance, servletContext.getDeployment(), exchange));
return instance.getInstance();
} catch (InstantiationException e) {
throw new RuntimeException(e);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
private void loadParts() throws IOException, ServletException {
final ServletRequestContext requestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
if (parts == null) {
final List<Part> parts = new ArrayList<>();
String mimeType = exchange.getRequestHeaders().getFirst(Headers.CONTENT_TYPE);
if (mimeType != null && mimeType.startsWith(MultiPartParserDefinition.MULTIPART_FORM_DATA)) {
FormData formData = parseFormData();
if(formData != null) {
for (final String namedPart : formData) {
for (FormData.FormValue part : formData.get(namedPart)) {
parts.add(new PartImpl(namedPart,
part,
requestContext.getOriginalServletPathMatch().getServletChain().getManagedServlet().getMultipartConfig(),
servletContext, this));
}
}
}
} else {
throw UndertowServletMessages.MESSAGES.notAMultiPartRequest();
}
this.parts = parts;
}
}
@Override
public Object getAttribute(final String name) {
if (attributes == null) {
return null;
}
return attributes.get(name);
}
@Override
public Enumeration<String> getAttributeNames() {
if (attributes == null) {
return EmptyEnumeration.instance();
}
return new IteratorEnumeration<>(attributes.keySet().iterator());
}
@Override
public String getCharacterEncoding() {
if (characterEncoding != null) {
return characterEncoding.name();
}
String characterEncodingFromHeader = getCharacterEncodingFromHeader();
if (characterEncodingFromHeader != null) {
return characterEncodingFromHeader;
}
if (servletContext.getDeployment().getDeploymentInfo().getDefaultRequestEncoding() != null ||
servletContext.getDeployment().getDeploymentInfo().getDefaultEncoding() != null) {
return servletContext.getDeployment().getDefaultRequestCharset().name();
}
return null;
}
private String () {
String contentType = exchange.getRequestHeaders().getFirst(Headers.CONTENT_TYPE);
if (contentType == null) {
return null;
}
return Headers.extractQuotedValueFromHeader(contentType, "charset");
}
@Override
public void setCharacterEncoding(final String env) throws UnsupportedEncodingException {
if (readStarted) {
return;
}
try {
characterEncoding = Charset.forName(env);
final ManagedServlet originalServlet = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY).getOriginalServletPathMatch().getServletChain().getManagedServlet();
final FormDataParser parser = originalServlet.getFormParserFactory().createParser(exchange);
if (parser != null) {
parser.setCharacterEncoding(env);
}
} catch (UnsupportedCharsetException e) {
throw new UnsupportedEncodingException();
}
}
@Override
public int getContentLength() {
long length = getContentLengthLong();
if(length > Integer.MAX_VALUE) {
return -1;
}
return (int)length;
}
@Override
public long getContentLengthLong() {
final String contentLength = getHeader(Headers.CONTENT_LENGTH);
if (contentLength == null || contentLength.isEmpty()) {
return -1;
}
return Long.parseLong(contentLength);
}
@Override
public String getContentType() {
return getHeader(Headers.CONTENT_TYPE);
}
@Override
public ServletInputStream getInputStream() throws IOException {
if (reader != null) {
throw UndertowServletMessages.MESSAGES.getReaderAlreadyCalled();
}
if(servletInputStream == null) {
servletInputStream = new ServletInputStreamImpl(this);
}
readStarted = true;
return servletInputStream;
}
public void closeAndDrainRequest() throws IOException {
if(reader != null) {
reader.close();
}
if(servletInputStream == null) {
servletInputStream = new ServletInputStreamImpl(this);
}
servletInputStream.close();
}
public void freeResources() throws IOException {
if(reader != null) {
reader.close();
}
if(servletInputStream != null) {
servletInputStream.close();
}
}
@Override
public String getParameter(final String name) {
if(queryParameters == null) {
queryParameters = exchange.getQueryParameters();
}
Deque<String> params = queryParameters.get(name);
if (params == null) {
final FormData parsedFormData = parseFormData();
if (parsedFormData != null) {
FormData.FormValue res = parsedFormData.getFirst(name);
if (res == null || res.isFile()) {
return null;
} else {
return res.getValue();
}
}
return null;
}
return params.getFirst();
}
@Override
public Enumeration<String> getParameterNames() {
if (queryParameters == null) {
queryParameters = exchange.getQueryParameters();
}
final Set<String> parameterNames = new HashSet<>(queryParameters.keySet());
if (exchange.getRequestMethod().equals(Methods.POST)) {
final FormData parsedFormData = parseFormData();
if (parsedFormData != null) {
Iterator<String> it = parsedFormData.iterator();
while (it.hasNext()) {
String name = it.next();
for(FormData.FormValue param : parsedFormData.get(name)) {
if(!param.isFile()) {
parameterNames.add(name);
break;
}
}
}
}
}
return new IteratorEnumeration<>(parameterNames.iterator());
}
@Override
public String[] getParameterValues(final String name) {
if (queryParameters == null) {
queryParameters = exchange.getQueryParameters();
}
final List<String> ret = new ArrayList<>();
Deque<String> params = queryParameters.get(name);
if (params != null) {
for (String param : params) {
ret.add(param);
}
}
if (exchange.getRequestMethod().equals(Methods.POST)) {
final FormData parsedFormData = parseFormData();
if (parsedFormData != null) {
Deque<FormData.FormValue> res = parsedFormData.get(name);
if (res != null) {
for (FormData.FormValue value : res) {
if(!value.isFile()) {
ret.add(value.getValue());
}
}
}
}
}
if (ret.isEmpty()) {
return null;
}
return ret.toArray(new String[ret.size()]);
}
@Override
public Map<String, String[]> getParameterMap() {
if (queryParameters == null) {
queryParameters = exchange.getQueryParameters();
}
final Map<String, ArrayList<String>> arrayMap = new HashMap<>();
for (Map.Entry<String, Deque<String>> entry : queryParameters.entrySet()) {
arrayMap.put(entry.getKey(), new ArrayList<>(entry.getValue()));
}
if (exchange.getRequestMethod().equals(Methods.POST)) {
final FormData parsedFormData = parseFormData();
if (parsedFormData != null) {
Iterator<String> it = parsedFormData.iterator();
while (it.hasNext()) {
final String name = it.next();
Deque<FormData.FormValue> val = parsedFormData.get(name);
if (arrayMap.containsKey(name)) {
ArrayList<String> existing = arrayMap.get(name);
for (final FormData.FormValue v : val) {
if(!v.isFile()) {
existing.add(v.getValue());
}
}
} else {
final ArrayList<String> values = new ArrayList<>();
for (final FormData.FormValue v : val) {
if(!v.isFile()) {
values.add(v.getValue());
}
}
arrayMap.put(name, values);
}
}
}
}
final Map<String, String[]> ret = new HashMap<>();
for(Map.Entry<String, ArrayList<String>> entry : arrayMap.entrySet()) {
ret.put(entry.getKey(), entry.getValue().toArray(new String[entry.getValue().size()]));
}
return ret;
}
private FormData parseFormData() {
if(formParsingException != null) {
throw formParsingException;
}
if (parsedFormData == null) {
if (readStarted) {
return null;
}
final ManagedServlet originalServlet = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY).getCurrentServlet().getManagedServlet();
final FormDataParser parser = originalServlet.getFormParserFactory().createParser(exchange);
if (parser == null) {
return null;
}
readStarted = true;
try {
return parsedFormData = parser.parseBlocking();
} catch (RequestTooBigException | MultiPartParserDefinition.FileTooLargeException e) {
throw formParsingException = new IllegalStateException(e);
} catch (RuntimeException e) {
throw formParsingException = e;
} catch (IOException e) {
throw formParsingException = new RuntimeException(e);
}
}
return parsedFormData;
}
@Override
public String getProtocol() {
return exchange.getProtocol().toString();
}
@Override
public String getScheme() {
return exchange.getRequestScheme();
}
@Override
public String getServerName() {
return exchange.getHostName();
}
@Override
public int getServerPort() {
return exchange.getHostPort();
}
@Override
public BufferedReader getReader() throws IOException {
if (reader == null) {
if (servletInputStream != null) {
throw UndertowServletMessages.MESSAGES.getInputStreamAlreadyCalled();
}
Charset charSet = servletContext.getDeployment().getDefaultRequestCharset();
if (characterEncoding != null) {
charSet = characterEncoding;
} else {
String c = getCharacterEncodingFromHeader();
if (c != null) {
try {
charSet = Charset.forName(c);
} catch (UnsupportedCharsetException e) {
throw new UnsupportedEncodingException();
}
}
}
reader = new BufferedReader(new InputStreamReader(exchange.getInputStream(), charSet));
}
readStarted = true;
return reader;
}
@Override
public String getRemoteAddr() {
InetSocketAddress sourceAddress = exchange.getSourceAddress();
if(sourceAddress == null) {
return "";
}
InetAddress address = sourceAddress.getAddress();
if(address == null) {
return sourceAddress.getHostString();
}
return address.getHostAddress();
}
@Override
public String getRemoteHost() {
InetSocketAddress sourceAddress = exchange.getSourceAddress();
if(sourceAddress == null) {
return "";
}
return sourceAddress.getHostString();
}
@Override
public void setAttribute(final String name, final Object object) {
if(object == null) {
removeAttribute(name);
return;
}
if (attributes == null) {
attributes = new HashMap<>();
}
Object existing = attributes.put(name, object);
if (existing != null) {
servletContext.getDeployment().getApplicationListeners().servletRequestAttributeReplaced(this, name, existing);
} else {
servletContext.getDeployment().getApplicationListeners().servletRequestAttributeAdded(this, name, object);
}
}
@Override
public void removeAttribute(final String name) {
if (attributes == null) {
return;
}
Object exiting = attributes.remove(name);
servletContext.getDeployment().getApplicationListeners().servletRequestAttributeRemoved(this, name, exiting);
}
@Override
public Locale getLocale() {
return getLocales().nextElement();
}
@Override
public Enumeration<Locale> getLocales() {
final List<String> acceptLanguage = exchange.getRequestHeaders().get(Headers.ACCEPT_LANGUAGE);
List<Locale> ret = LocaleUtils.getLocalesFromHeader(acceptLanguage);
if(ret.isEmpty()) {
return new IteratorEnumeration<>(Collections.singletonList(Locale.getDefault()).iterator());
}
return new IteratorEnumeration<>(ret.iterator());
}
@Override
public boolean isSecure() {
return exchange.isSecure();
}
@Override
public RequestDispatcher getRequestDispatcher(final String path) {
String realPath;
if (path.startsWith("/")) {
realPath = path;
} else {
String current = exchange.getRelativePath();
int lastSlash = current.lastIndexOf("/");
if (lastSlash != -1) {
current = current.substring(0, lastSlash + 1);
}
realPath = CanonicalPathUtils.canonicalize(current + path);
}
return new RequestDispatcherImpl(realPath, servletContext);
}
@Override
public String getRealPath(final String path) {
return servletContext.getRealPath(path);
}
@Override
public int getRemotePort() {
return exchange.getSourceAddress().getPort();
}
@Override
public String getLocalName() {
return exchange.getDestinationAddress().getHostString();
}
@Override
public String getLocalAddr() {
InetSocketAddress destinationAddress = exchange.getDestinationAddress();
if (destinationAddress == null) {
return "";
}
InetAddress address = destinationAddress.getAddress();
if (address == null) {
return destinationAddress.getHostString();
}
return address.getHostAddress();
}
@Override
public int getLocalPort() {
return exchange.getDestinationAddress().getPort();
}
@Override
public ServletContextImpl getServletContext() {
return servletContext;
}
@Override
public AsyncContext startAsync() throws IllegalStateException {
if (!isAsyncSupported()) {
throw UndertowServletMessages.MESSAGES.startAsyncNotAllowed();
} else if (asyncStarted) {
throw UndertowServletMessages.MESSAGES.asyncAlreadyStarted();
}
asyncStarted = true;
final ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
return asyncContext = new AsyncContextImpl(exchange, servletRequestContext.getServletRequest(), servletRequestContext.getServletResponse(), servletRequestContext, false, asyncContext);
}
@Override
public AsyncContext startAsync(final ServletRequest servletRequest, final ServletResponse servletResponse) throws IllegalStateException {
final ServletRequestContext servletRequestContext = exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY);
if (!servletContext.getDeployment().getDeploymentInfo().isAllowNonStandardWrappers()) {
if (servletRequestContext.getOriginalRequest() != servletRequest) {
if (!(servletRequest instanceof ServletRequestWrapper)) {
throw UndertowServletMessages.MESSAGES.requestWasNotOriginalOrWrapper(servletRequest);
}
}
if (servletRequestContext.getOriginalResponse() != servletResponse) {
if (!(servletResponse instanceof ServletResponseWrapper)) {
throw UndertowServletMessages.MESSAGES.responseWasNotOriginalOrWrapper(servletResponse);
}
}
}
if (!isAsyncSupported()) {
throw UndertowServletMessages.MESSAGES.startAsyncNotAllowed();
} else if (asyncStarted) {
throw UndertowServletMessages.MESSAGES.asyncAlreadyStarted();
}
asyncStarted = true;
servletRequestContext.setServletRequest(servletRequest);
servletRequestContext.setServletResponse(servletResponse);
return asyncContext = new AsyncContextImpl(exchange, servletRequest, servletResponse, servletRequestContext, true, asyncContext);
}
@Override
public boolean isAsyncStarted() {
return asyncStarted || asyncCancelled;
}
@Override
public boolean isAsyncSupported() {
return exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY).isAsyncSupported();
}
void setAsyncCancelled(boolean asyncCancelled) {
this.asyncCancelled = asyncCancelled;
}
@Override
public AsyncContextImpl getAsyncContext() {
if (!isAsyncStarted()) {
throw UndertowServletMessages.MESSAGES.asyncNotStarted();
}
return asyncContext;
}
public AsyncContextImpl getAsyncContextInternal() {
return asyncContext;
}
@Override
public DispatcherType getDispatcherType() {
return exchange.getAttachment(ServletRequestContext.ATTACHMENT_KEY).getDispatcherType();
}
public Map<String, Deque<String>> getQueryParameters() {
if (queryParameters == null) {
queryParameters = exchange.getQueryParameters();
}
return queryParameters;
}
public void setQueryParameters(final Map<String, Deque<String>> queryParameters) {
this.queryParameters = queryParameters;
}
public void setServletContext(final ServletContextImpl servletContext) {
this.servletContext = servletContext;
}
void asyncRequestDispatched() {
asyncStarted = false;
}
public String getOriginalRequestURI() {
String uri = (String) getAttribute(RequestDispatcher.FORWARD_REQUEST_URI);
if(uri != null) {
return uri;
}
uri = (String) getAttribute(AsyncContext.ASYNC_REQUEST_URI);
if(uri != null) {
return uri;
}
return getRequestURI();
}
public String getOriginalServletPath() {
String uri = (String) getAttribute(RequestDispatcher.FORWARD_SERVLET_PATH);
if(uri != null) {
return uri;
}
uri = (String) getAttribute(AsyncContext.ASYNC_SERVLET_PATH);
if(uri != null) {
return uri;
}
return getServletPath();
}
public String getOriginalPathInfo() {
String uri = (String) getAttribute(RequestDispatcher.FORWARD_PATH_INFO);
if(uri != null) {
return uri;
}
uri = (String) getAttribute(AsyncContext.ASYNC_PATH_INFO);
if(uri != null) {
return uri;
}
return getPathInfo();
}
public String getOriginalContextPath() {
String uri = (String) getAttribute(RequestDispatcher.FORWARD_CONTEXT_PATH);
if(uri != null) {
return uri;
}
uri = (String) getAttribute(AsyncContext.ASYNC_CONTEXT_PATH);
if(uri != null) {
return uri;
}
return getContextPath();
}
public String getOriginalQueryString() {
String uri = (String) getAttribute(RequestDispatcher.FORWARD_QUERY_STRING);
if(uri != null) {
return uri;
}
uri = (String) getAttribute(AsyncContext.ASYNC_QUERY_STRING);
if(uri != null) {
return uri;
}
return getQueryString();
}
private SessionConfig.SessionCookieSource sessionCookieSource() {
HttpSession session = getSession(false);
if(session == null) {
return SessionConfig.SessionCookieSource.NONE;
}
if(sessionCookieSource == null) {
sessionCookieSource = originalServletContext.getSessionConfig().sessionCookieSource(exchange);
}
return sessionCookieSource;
}
@Override
public String toString() {
return "HttpServletRequestImpl [ " + getMethod() + ' ' + getRequestURI() + " ]";
}
public void clearAttributes() {
if(attributes != null) {
this.attributes.clear();
}
}
@Override
public PushBuilder newPushBuilder() {
if(exchange.getConnection().isPushSupported()) {
return new PushBuilderImpl(this);
}
return null;
}
@Override
public Map<String, String> getTrailerFields() {
HeaderMap trailers = exchange.getAttachment(HttpAttachments.REQUEST_TRAILERS);
if(trailers == null) {
return Collections.emptyMap();
}
Map<String, String> ret = new HashMap<>();
for(HeaderValues entry : trailers) {
ret.put(entry.getHeaderName().toString().toLowerCase(Locale.ENGLISH), entry.getFirst());
}
return ret;
}
@Override
public boolean isTrailerFieldsReady() {
if(exchange.isRequestComplete()) {
return true;
}
return !exchange.getConnection().isRequestTrailerFieldsSupported();
}
}