io.undertow.servlet.handlers.ServletRequestContext Maven / Gradle / Ivy
/*
* JBoss, Home of Professional Open Source.
* Copyright 2014 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.undertow.servlet.handlers;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.util.List;
import io.undertow.UndertowMessages;
import io.undertow.server.HttpServerExchange;
import io.undertow.servlet.api.Deployment;
import io.undertow.servlet.api.ServletStackTraces;
import io.undertow.servlet.api.TransportGuaranteeType;
import io.undertow.servlet.api.SingleConstraintMatch;
import io.undertow.servlet.spec.HttpServletRequestImpl;
import io.undertow.servlet.spec.HttpServletResponseImpl;
import io.undertow.servlet.spec.HttpSessionImpl;
import io.undertow.servlet.spec.ServletContextImpl;
import io.undertow.util.AttachmentKey;
import io.undertow.util.Headers;
import jakarta.servlet.DispatcherType;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
/**
* All the information that servlet needs to attach to the exchange.
*
* This is all stored under this class, rather than using individual attachments, as
* this approach has significant performance advantages.
*
* The {@link ServletInitialHandler} also pushed this information to the {@link #CURRENT}
* thread local, which allows it to be access even if the request or response have been
* wrapped with non-compliant wrapper classes.
*
* @author Stuart Douglas
*/
public class ServletRequestContext {
private static final RuntimePermission GET_CURRENT_REQUEST = new RuntimePermission("io.undertow.servlet.GET_CURRENT_REQUEST");
private static final RuntimePermission SET_CURRENT_REQUEST = new RuntimePermission("io.undertow.servlet.SET_CURRENT_REQUEST");
private static final ThreadLocal CURRENT = new ThreadLocal<>();
public static void setCurrentRequestContext(ServletRequestContext servletRequestContext) {
SecurityManager sm = System.getSecurityManager();
if(sm != null) {
sm.checkPermission(SET_CURRENT_REQUEST);
}
CURRENT.set(servletRequestContext);
}
public static void clearCurrentServletAttachments() {
SecurityManager sm = System.getSecurityManager();
if(sm != null) {
sm.checkPermission(SET_CURRENT_REQUEST);
}
CURRENT.remove();
}
/**
* Gets the {@link ServletRequestContext} assigned to the current thread.
*
* @return The current {@link ServletRequestContext} based on the calling thread
* @throws IllegalStateException if the calling thread does not have a {@link ServletRequestContext} set
* @see ServletRequestContext#current()
*/
public static ServletRequestContext requireCurrent() {
ServletRequestContext attachments = current();
if (attachments == null) {
throw UndertowMessages.MESSAGES.noRequestActive();
}
return attachments;
}
/**
* Gets the current threads {@link ServletRequestContext} if set, otherwise null.
*
* @return The current {@link ServletRequestContext} based on the calling thread, or null if unavailable
*/
public static ServletRequestContext current() {
SecurityManager sm = System.getSecurityManager();
if(sm != null) {
sm.checkPermission(GET_CURRENT_REQUEST);
}
return CURRENT.get();
}
public static final AttachmentKey ATTACHMENT_KEY = AttachmentKey.create(ServletRequestContext.class);
private final Deployment deployment;
private final HttpServletRequestImpl originalRequest;
private final HttpServletResponseImpl originalResponse;
private final ServletPathMatch originalServletPathMatch;
private ServletResponse servletResponse;
private ServletRequest servletRequest;
private DispatcherType dispatcherType;
private ServletChain currentServlet;
private ServletPathMatch servletPathMatch;
private List requiredConstrains;
private TransportGuaranteeType transportGuarenteeType;
private HttpSessionImpl session;
private ServletContextImpl currentServletContext;
private String overridenSessionId;
/**
* If this is true the request is running inside the context of ServletInitialHandler
*/
private boolean runningInsideHandler = false;
private int errorCode = -1;
private String errorMessage;
private boolean asyncSupported = true;
public ServletRequestContext(final Deployment deployment, final HttpServletRequestImpl originalRequest, final HttpServletResponseImpl originalResponse, final ServletPathMatch originalServletPathMatch) {
this.deployment = deployment;
this.originalRequest = originalRequest;
this.originalResponse = originalResponse;
this.servletRequest = originalRequest;
this.servletResponse = originalResponse;
this.originalServletPathMatch = originalServletPathMatch;
this.currentServletContext = deployment.getServletContext();
}
public Deployment getDeployment() {
return deployment;
}
public ServletChain getCurrentServlet() {
return currentServlet;
}
public void setCurrentServlet(ServletChain currentServlet) {
this.currentServlet = currentServlet;
}
public ServletPathMatch getServletPathMatch() {
return servletPathMatch;
}
public void setServletPathMatch(ServletPathMatch servletPathMatch) {
this.servletPathMatch = servletPathMatch;
}
public List getRequiredConstrains() {
return requiredConstrains;
}
public void setRequiredConstrains(List requiredConstrains) {
this.requiredConstrains = requiredConstrains;
}
public TransportGuaranteeType getTransportGuarenteeType() {
return transportGuarenteeType;
}
public void setTransportGuarenteeType(TransportGuaranteeType transportGuarenteeType) {
this.transportGuarenteeType = transportGuarenteeType;
}
public ServletResponse getServletResponse() {
return servletResponse;
}
public void setServletResponse(ServletResponse servletResponse) {
this.servletResponse = servletResponse;
}
public ServletRequest getServletRequest() {
return servletRequest;
}
public void setServletRequest(ServletRequest servletRequest) {
this.servletRequest = servletRequest;
}
public DispatcherType getDispatcherType() {
return dispatcherType;
}
public void setDispatcherType(DispatcherType dispatcherType) {
this.dispatcherType = dispatcherType;
}
public HttpServletRequestImpl getOriginalRequest() {
return originalRequest;
}
public HttpServletResponseImpl getOriginalResponse() {
return originalResponse;
}
public HttpSessionImpl getSession() {
return session;
}
public void setSession(final HttpSessionImpl session) {
this.session = session;
}
public HttpServerExchange getExchange() {
return originalRequest.getExchange();
}
public ServletPathMatch getOriginalServletPathMatch() {
return originalServletPathMatch;
}
public ServletContextImpl getCurrentServletContext() {
return currentServletContext;
}
public void setCurrentServletContext(ServletContextImpl currentServletContext) {
this.currentServletContext = currentServletContext;
}
public boolean displayStackTraces() {
ServletStackTraces mode = deployment.getDeploymentInfo().getServletStackTraces();
if (mode == ServletStackTraces.NONE) {
return false;
} else if (mode == ServletStackTraces.ALL) {
return true;
} else {
InetSocketAddress localAddress = getExchange().getSourceAddress();
if(localAddress == null) {
return false;
}
InetAddress address = localAddress.getAddress();
if(address == null) {
return false;
}
if(!address.isLoopbackAddress()) {
return false;
}
return !getExchange().getRequestHeaders().contains(Headers.X_FORWARDED_FOR);
}
}
public void setError(int sc, String msg) {
this.errorCode = sc;
this.errorMessage = msg;
}
public int getErrorCode() {
return errorCode;
}
public String getErrorMessage() {
return errorMessage;
}
public boolean isRunningInsideHandler() {
return runningInsideHandler;
}
public void setRunningInsideHandler(boolean runningInsideHandler) {
this.runningInsideHandler = runningInsideHandler;
}
public boolean isAsyncSupported() {
return asyncSupported;
}
public String getOverridenSessionId() {
return overridenSessionId;
}
public void setOverridenSessionId(String overridenSessionId) {
this.overridenSessionId = overridenSessionId;
}
public void setAsyncSupported(boolean asyncSupported) {
this.asyncSupported = asyncSupported;
}
}