org.mobicents.io.undertow.servlet.handlers.ConvergedServletInitialHandler Maven / Gradle / Ivy
/*
* TeleStax, Open Source Cloud Communications
* Copyright 2011-2015, Telestax Inc and individual contributors
* by the @authors tag.
*
* This program is free software: you can redistribute it and/or modify
* under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation; either version 3 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see
*/
package org.mobicents.io.undertow.servlet.handlers;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.security.AccessController;
import java.security.PrivilegedExceptionAction;
import java.util.concurrent.Executor;
import javax.servlet.DispatcherType;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.mobicents.io.undertow.servlet.spec.ConvergedHttpServletRequestFacade;
import org.mobicents.io.undertow.servlet.spec.ConvergedHttpServletResponseFacade;
import org.mobicents.servlet.sip.startup.ConvergedServletContextImpl;
import org.xnio.BufferAllocator;
import org.xnio.ByteBufferSlicePool;
import org.xnio.ChannelListener;
import org.xnio.Option;
import org.xnio.OptionMap;
import org.xnio.Pool;
import org.xnio.StreamConnection;
import org.xnio.XnioIoThread;
import org.xnio.XnioWorker;
import org.xnio.channels.ConnectedChannel;
import org.xnio.conduits.ConduitStreamSinkChannel;
import org.xnio.conduits.ConduitStreamSourceChannel;
import org.xnio.conduits.StreamSinkConduit;
import io.undertow.UndertowMessages;
import io.undertow.connector.ByteBufferPool;
import io.undertow.server.DefaultByteBufferPool;
import io.undertow.server.HttpHandler;
import io.undertow.server.HttpServerExchange;
import io.undertow.server.HttpUpgradeListener;
import io.undertow.server.SSLSessionInfo;
import io.undertow.server.ServerConnection;
import io.undertow.server.XnioBufferPoolAdaptor;
import io.undertow.servlet.core.CompositeThreadSetupAction;
import io.undertow.servlet.core.ServletBlockingHttpExchange;
import io.undertow.servlet.handlers.ServletChain;
import io.undertow.servlet.handlers.ServletInitialHandler;
import io.undertow.servlet.handlers.ServletPathMatch;
import io.undertow.servlet.handlers.ServletPathMatches;
import io.undertow.servlet.handlers.ServletRequestContext;
import io.undertow.servlet.spec.HttpServletRequestImpl;
import io.undertow.servlet.spec.HttpServletResponseImpl;
import io.undertow.util.Headers;
import io.undertow.util.HttpString;
import io.undertow.util.Protocols;
import io.undertow.util.RedirectBuilder;
import io.undertow.util.StatusCodes;
/**
* This class extends io.undertow.servlet.handlers.ServletInitialHandler to create ConvergedServletRequestContext with
* ConvergedHttpServletRequestFacade and ConvergedHttpServletResponseFacade instead of plain ServletRequestContex.
*
* @author [email protected]
* @author [email protected]
* */
public class ConvergedServletInitialHandler extends ServletInitialHandler{
private static final String HTTP2_UPGRADE_PREFIX = "h2";
private final ConvergedServletContextImpl convergedServletContext;
public ConvergedServletInitialHandler(final ServletPathMatches paths,final HttpHandler next,final CompositeThreadSetupAction setupAction,
final ConvergedServletContextImpl servletContext) {
super(paths, next, setupAction, servletContext.getDelegatedContext());
this.convergedServletContext = servletContext;
}
@Override
public void handleRequest(final HttpServerExchange exchange) throws Exception {
ServletPathMatches paths=null;
try{
//lets get access of superclass private fields using reflection:
Field pathsField = ServletInitialHandler.class.getDeclaredField("paths");
pathsField.setAccessible(true);
paths = (ServletPathMatches)pathsField.get(this);
pathsField.setAccessible(false);
}catch(NoSuchFieldException | IllegalAccessException e){
throw new ServletException(e);
}
final String path = exchange.getRelativePath();
if(isForbiddenPath(path)) {
exchange.setResponseCode(StatusCodes.NOT_FOUND);
return;
}
final ServletPathMatch info = paths.getServletHandlerByPath(path);
//https://issues.jboss.org/browse/WFLY-3439
//if the request is an upgrade request then we don't want to redirect
//as there is a good chance the web socket client won't understand the redirect
//we make an exception for HTTP2 upgrade requests, as this would have already be handled at
//the connector level if it was going to be handled.
String upgradeString = exchange.getRequestHeaders().getFirst(Headers.UPGRADE);
boolean isUpgradeRequest = upgradeString != null && !upgradeString.startsWith(HTTP2_UPGRADE_PREFIX);
if (info.getType() == ServletPathMatch.Type.REDIRECT && !isUpgradeRequest) {
//UNDERTOW-89
//we redirect on GET requests to the root context to add an / to the end
exchange.setResponseCode(StatusCodes.TEMPORARY_REDIRECT);
exchange.getResponseHeaders().put(Headers.LOCATION, RedirectBuilder.redirect(exchange, exchange.getRelativePath() + "/", true));
return;
} else if (info.getType() == ServletPathMatch.Type.REWRITE) {
//this can only happen if the path ends with a /
//otherwise there would be a rewrite instead
exchange.setRelativePath(exchange.getRelativePath() + info.getRewriteLocation());
exchange.setRequestURI(exchange.getRequestURI() + info.getRewriteLocation());
exchange.setRequestPath(exchange.getRequestPath() + info.getRewriteLocation());
}
final HttpServletResponseImpl response = new HttpServletResponseImpl(exchange, convergedServletContext.getDelegatedContext());
final HttpServletRequestImpl request = new HttpServletRequestImpl(exchange, convergedServletContext.getDelegatedContext());
final ConvergedHttpServletResponseFacade convergedResponse = new ConvergedHttpServletResponseFacade(response,convergedServletContext);
final ConvergedHttpServletRequestFacade convergedRequest = new ConvergedHttpServletRequestFacade(request,convergedServletContext);
final ServletRequestContext servletRequestContext = new ConvergedServletRequestContext(convergedServletContext.getDeployment(), convergedRequest, convergedResponse, info);
//set the max request size if applicable
if (info.getServletChain().getManagedServlet().getMaxRequestSize() > 0) {
exchange.setMaxEntitySize(info.getServletChain().getManagedServlet().getMaxRequestSize());
}
exchange.putAttachment(ServletRequestContext.ATTACHMENT_KEY, servletRequestContext);
exchange.startBlocking(new ServletBlockingHttpExchange(exchange));
servletRequestContext.setServletPathMatch(info);
Executor executor = info.getServletChain().getExecutor();
if (executor == null) {
executor = convergedServletContext.getDeployment().getExecutor();
}
if (exchange.isInIoThread() || executor != null) {
//either the exchange has not been dispatched yet, or we need to use a special executor
exchange.dispatch(executor, new HttpHandler() {
@Override
public void handleRequest(final HttpServerExchange exchange) throws Exception {
if(System.getSecurityManager() == null) {
dispatchRequest(exchange, servletRequestContext, info.getServletChain(), DispatcherType.REQUEST);
} else {
//sometimes thread pools inherit some random
AccessController.doPrivileged(new PrivilegedExceptionAction
© 2015 - 2025 Weber Informatics LLC | Privacy Policy