版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/a040600145/article/details/68946877
http1.1的Connector的protocolHandler为org.apache.coyote.http11.Http11Protocol。Http11Protocol的endpoint为JIoEndpoint。JIoEndpoint的handler为Http11Protocol.Http11ConnectionHandler。
以url为http://127.0.0.1:8080/为例线程栈的信息如下:
1.JIoEndpoint在start时会先创建Executor线程池用来执行SocketProcessor处理接收的请求,然后会创建一个接收请求线程组。
- public void startInternal() throws Exception {
- if (!running) {
- running = true;
- paused = false;
- // Create worker collection
- if (getExecutor() == null) {
- createExecutor();
- }
- initializeConnectionLatch();
- startAcceptorThreads();
- // Start async timeout thread
- Thread timeoutThread = new Thread(new AsyncTimeout(), getName() + "-AsyncTimeout");
- timeoutThread.setPriority(threadPriority);
- timeoutThread.setDaemon(true);
- timeoutThread.start();
- }
- }
- public void createExecutor() {
- internalExecutor = true;
- TaskQueue taskqueue = new TaskQueue();
- TaskThreadFactory tf = new TaskThreadFactory(getName() + "-exec-", daemon, getThreadPriority());
- executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), 60, TimeUnit.SECONDS,taskqueue, tf);
- taskqueue.setParent( (ThreadPoolExecutor) executor);
- }
- protected final void startAcceptorThreads() {
- int count = getAcceptorThreadCount();
- acceptors = new Acceptor[count];
- for (int i = 0; i < count; i++) {
- acceptors[i] = createAcceptor();
- String threadName = getName() + "-Acceptor-" + i;
- acceptors[i].setThreadName(threadName);
- Thread t = new Thread(acceptors[i], threadName);
- t.setPriority(getAcceptorThreadPriority());
- t.setDaemon(getDaemon());
- t.start();
- }
- }
2.Acceptor讲接收到的请求socke后调用processSocketWithOptions包装成SocketWrapper并调用线程池运行SocketProcessor。
- public void run() {
- int errorDelay = 0;
- // Loop until we receive a shutdown command
- while (running) {
- // Loop if endpoint is paused
- while (paused && running) {
- state = AcceptorState.PAUSED;
- try {
- Thread.sleep(50);
- } catch (InterruptedException e) {
- // Ignore
- }
- }
- if (!running) {
- break;
- }
- state = AcceptorState.RUNNING;
- try {
- //if we have reached max connections, wait
- countUpOrAwaitConnection();
- Socket socket = null;
- try {
- // Accept the next incoming connection from the server
- // socket
- socket = serverSocketFactory.acceptSocket(serverSocket);
- } catch (IOException ioe) {
- countDownConnection();
- // Introduce delay if necessary
- errorDelay = handleExceptionWithDelay(errorDelay);
- // re-throw
- throw ioe;
- }
- // Successful accept, reset the error delay
- errorDelay = 0;
- // Configure the socket
- if (running && !paused && setSocketOptions(socket)) {
- // Hand this socket off to an appropriate processor
- if (!processSocket(socket)) {
- countDownConnection();
- // Close socket right away
- closeSocket(socket);
- }
- } else {
- countDownConnection();
- // Close socket right away
- closeSocket(socket);
- }
- } catch (IOException x) {
- if (running) {
- log.error(sm.getString("endpoint.accept.fail"), x);
- }
- } catch (NullPointerException npe) {
- if (running) {
- log.error(sm.getString("endpoint.accept.fail"), npe);
- }
- } catch (Throwable t) {
- ExceptionUtils.handleThrowable(t);
- log.error(sm.getString("endpoint.accept.fail"), t);
- }
- }
- state = AcceptorState.ENDED;
- }
- protected boolean processSocket(Socket socket) {
- // Process the request from this socket
- try {
- SocketWrapper<Socket> wrapper = new SocketWrapper<Socket>(socket);
- wrapper.setKeepAliveLeft(getMaxKeepAliveRequests());
- wrapper.setSecure(isSSLEnabled());
- // During shutdown, executor may be null - avoid NPE
- if (!running) {
- return false;
- }
- getExecutor().execute(new SocketProcessor(wrapper));
- } catch (RejectedExecutionException x) {
- log.warn("Socket processing request was rejected for:" + socket, x);
- return false;
- } catch (Throwable t) {
- ExceptionUtils.handleThrowable(t);
- // This means we got an OOM or similar creating a thread, or that
- // the pool and its queue are full
- log.error(sm.getString("endpoint.process.fail"), t);
- return false;
- }
- return true;
- }
3.SocketProcessor会调用handler的process。
- public void run() {
- boolean launch = false;
- synchronized (socket) {
- try {
- SocketState state = SocketState.OPEN;
- try {
- // SSL handshake
- serverSocketFactory.handshake(socket.getSocket());
- } catch (Throwable t) {
- ExceptionUtils.handleThrowable(t);
- if (log.isDebugEnabled()) {
- log.debug(sm.getString("endpoint.err.handshake"), t);
- }
- // Tell to close the socket
- state = SocketState.CLOSED;
- }
- if ((state != SocketState.CLOSED)) {
- if (status == null) {
- state = handler.process(socket, SocketStatus.OPEN_READ);
- } else {
- state = handler.process(socket, status);
- }
- }
- if (state == SocketState.CLOSED) {
- // Close socket
- if (log.isTraceEnabled()) {
- log.trace("Closing socket:" + socket);
- }
- countDownConnection();
- try {
- socket.getSocket().close();
- } catch (IOException e) {
- // Ignore
- }
- } else if (state == SocketState.OPEN || state == SocketState.UPGRADING
- || state == SocketState.UPGRADING_TOMCAT || state == SocketState.UPGRADED) {
- socket.setKeptAlive(true);
- socket.access();
- launch = true;
- } else if (state == SocketState.LONG) {
- socket.access();
- waitingRequests.add(socket);
- }
- } finally {
- if (launch) {
- try {
- getExecutor().execute(new SocketProcessor(socket, SocketStatus.OPEN_READ));
- } catch (RejectedExecutionException x) {
- log.warn("Socket reprocessing request was rejected for:" + socket, x);
- try {
- //unable to handle connection at this time
- handler.process(socket, SocketStatus.DISCONNECT);
- } finally {
- countDownConnection();
- }
- } catch (NullPointerException npe) {
- if (running) {
- log.error(sm.getString("endpoint.launch.fail"), npe);
- }
- }
- }
- }
- }
- socket = null;
- // Finish up this request
- }
- }
4.Http11Protocol.Http11ConnectionHandler又会调用Processor的process方法
- public SocketState process(SocketWrapper<S> wrapper,
- SocketStatus status) {
- if (wrapper == null) {
- // Nothing to do. Socket has been closed.
- return SocketState.CLOSED;
- }
- S socket = wrapper.getSocket();
- if (socket == null) {
- // Nothing to do. Socket has been closed.
- return SocketState.CLOSED;
- }
- Processor<S> processor = connections.get(socket);
- if (status == SocketStatus.DISCONNECT && processor == null) {
- // Nothing to do. Endpoint requested a close and there is no
- // longer a processor associated with this socket.
- return SocketState.CLOSED;
- }
- wrapper.setAsync(false);
- ContainerThreadMarker.markAsContainerThread();
- try {
- if (processor == null) {
- processor = recycledProcessors.poll();
- }
- if (processor == null) {
- processor = createProcessor();
- }
- initSsl(wrapper, processor);
- SocketState state = SocketState.CLOSED;
- do {
- if (status == SocketStatus.DISCONNECT &&
- !processor.isComet()) {
- // Do nothing here, just wait for it to get recycled
- // Don't do this for Comet we need to generate an end
- // event (see BZ 54022)
- } else if (processor.isAsync() || state == SocketState.ASYNC_END) {
- state = processor.asyncDispatch(status);
- if (state == SocketState.OPEN) {
- // release() won't get called so in case this request
- // takes a long time to process, remove the socket from
- // the waiting requests now else the async timeout will
- // fire
- getProtocol().endpoint.removeWaitingRequest(wrapper);
- // There may be pipe-lined data to read. If the data
- // isn't processed now, execution will exit this
- // loop and call release() which will recycle the
- // processor (and input buffer) deleting any
- // pipe-lined data. To avoid this, process it now.
- state = processor.process(wrapper);
- }
- } else if (processor.isComet()) {
- state = processor.event(status);
- } else if (processor.getUpgradeInbound() != null) {
- state = processor.upgradeDispatch();
- } else if (processor.isUpgrade()) {
- state = processor.upgradeDispatch(status);
- } else {
- state = processor.process(wrapper);
- }
- if (state != SocketState.CLOSED && processor.isAsync()) {
- state = processor.asyncPostProcess();
- }
- if (state == SocketState.UPGRADING) {
- // Get the HTTP upgrade handler
- HttpUpgradeHandler httpUpgradeHandler =
- processor.getHttpUpgradeHandler();
- // Release the Http11 processor to be re-used
- release(wrapper, processor, false, false);
- // Create the upgrade processor
- processor = createUpgradeProcessor(
- wrapper, httpUpgradeHandler);
- // Mark the connection as upgraded
- wrapper.setUpgraded(true);
- // Associate with the processor with the connection
- connections.put(socket, processor);
- // Initialise the upgrade handler (which may trigger
- // some IO using the new protocol which is why the lines
- // above are necessary)
- // This cast should be safe. If it fails the error
- // handling for the surrounding try/catch will deal with
- // it.
- httpUpgradeHandler.init((WebConnection) processor);
- } else if (state == SocketState.UPGRADING_TOMCAT) {
- // Get the UpgradeInbound handler
- org.apache.coyote.http11.upgrade.UpgradeInbound inbound =
- processor.getUpgradeInbound();
- // Release the Http11 processor to be re-used
- release(wrapper, processor, false, false);
- // Create the light-weight upgrade processor
- processor = createUpgradeProcessor(wrapper, inbound);
- inbound.onUpgradeComplete();
- }
- if (getLog().isDebugEnabled()) {
- getLog().debug("Socket: [" + wrapper +
- "], Status in: [" + status +
- "], State out: [" + state + "]");
- }
- } while (state == SocketState.ASYNC_END ||
- state == SocketState.UPGRADING ||
- state == SocketState.UPGRADING_TOMCAT);
- if (state == SocketState.LONG) {
- // In the middle of processing a request/response. Keep the
- // socket associated with the processor. Exact requirements
- // depend on type of long poll
- connections.put(socket, processor);
- longPoll(wrapper, processor);
- } else if (state == SocketState.OPEN) {
- // In keep-alive but between requests. OK to recycle
- // processor. Continue to poll for the next request.
- connections.remove(socket);
- release(wrapper, processor, false, true);
- } else if (state == SocketState.SENDFILE) {
- // Sendfile in progress. If it fails, the socket will be
- // closed. If it works, the socket will be re-added to the
- // poller
- connections.remove(socket);
- release(wrapper, processor, false, false);
- } else if (state == SocketState.UPGRADED) {
- // Need to keep the connection associated with the processor
- connections.put(socket, processor);
- // Don't add sockets back to the poller if this was a
- // non-blocking write otherwise the poller may trigger
- // multiple read events which may lead to thread starvation
- // in the connector. The write() method will add this socket
- // to the poller if necessary.
- if (status != SocketStatus.OPEN_WRITE) {
- longPoll(wrapper, processor);
- }
- } else {
- // Connection closed. OK to recycle the processor. Upgrade
- // processors are not recycled.
- connections.remove(socket);
- if (processor.isUpgrade()) {
- processor.getHttpUpgradeHandler().destroy();
- } else if (processor instanceof org.apache.coyote.http11.upgrade.UpgradeProcessor) {
- // NO-OP
- } else {
- release(wrapper, processor, true, false);
- }
- }
- return state;
- } catch(java.net.SocketException e) {
- // SocketExceptions are normal
- getLog().debug(sm.getString(
- "abstractConnectionHandler.socketexception.debug"), e);
- } catch (java.io.IOException e) {
- // IOExceptions are normal
- getLog().debug(sm.getString(
- "abstractConnectionHandler.ioexception.debug"), e);
- }
- // Future developers: if you discover any other
- // rare-but-nonfatal exceptions, catch them here, and log as
- // above.
- catch (Throwable e) {
- ExceptionUtils.handleThrowable(e);
- // any other exception or error is odd. Here we log it
- // with "ERROR" level, so it will show up even on
- // less-than-verbose logs.
- getLog().error(
- sm.getString("abstractConnectionHandler.error"), e);
- }
- // Make sure socket/processor is removed from the list of current
- // connections
- connections.remove(socket);
- // Don't try to add upgrade processors back into the pool
- if (!(processor instanceof org.apache.coyote.http11.upgrade.UpgradeProcessor)
- && !processor.isUpgrade()) {
- release(wrapper, processor, true, false);
- }
- return SocketState.CLOSED;
- }
5.Http11Processor会先调用prepareRequest解析请求的头信息后调用adapter的service。
- public SocketState process(SocketWrapper<S> socketWrapper) throws IOException {
- RequestInfo rp = request.getRequestProcessor();
- rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);
- // Setting up the I/O
- setSocketWrapper(socketWrapper);
- getInputBuffer().init(socketWrapper, endpoint);
- getOutputBuffer().init(socketWrapper, endpoint);
- // Flags
- keepAlive = true;
- comet = false;
- openSocket = false;
- sendfileInProgress = false;
- readComplete = true;
- if (endpoint.getUsePolling()) {
- keptAlive = false;
- } else {
- keptAlive = socketWrapper.isKeptAlive();
- }
- if (disableKeepAlive()) {
- socketWrapper.setKeepAliveLeft(0);
- }
- while (!getErrorState().isError() && keepAlive && !comet && !isAsync() && upgradeInbound == null
- && httpUpgradeHandler == null && !endpoint.isPaused()) {
- // Parsing the request header
- try {
- setRequestLineReadTimeout();
- if (!getInputBuffer().parseRequestLine(keptAlive)) {
- if (handleIncompleteRequestLineRead()) {
- break;
- }
- }
- if (endpoint.isPaused()) {
- // 503 - Service unavailable
- response.setStatus(503);
- setErrorState(ErrorState.CLOSE_CLEAN, null);
- } else {
- keptAlive = true;
- // Set this every time in case limit has been changed via JMX
- request.getMimeHeaders().setLimit(endpoint.getMaxHeaderCount());
- request.getCookies().setLimit(getMaxCookieCount());
- // Currently only NIO will ever return false here
- if (!getInputBuffer().parseHeaders()) {
- // We've read part of the request, don't recycle it
- // instead associate it with the socket
- openSocket = true;
- readComplete = false;
- break;
- }
- if (!disableUploadTimeout) {
- setSocketTimeout(connectionUploadTimeout);
- }
- }
- } catch (IOException e) {
- if (getLog().isDebugEnabled()) {
- getLog().debug(sm.getString("http11processor.header.parse"), e);
- }
- setErrorState(ErrorState.CLOSE_NOW, e);
- break;
- } catch (Throwable t) {
- ExceptionUtils.handleThrowable(t);
- UserDataHelper.Mode logMode = userDataHelper.getNextMode();
- if (logMode != null) {
- String message = sm.getString("http11processor.header.parse");
- switch (logMode) {
- case INFO_THEN_DEBUG:
- message += sm.getString("http11processor.fallToDebug");
- //$FALL-THROUGH$
- case INFO:
- getLog().info(message, t);
- break;
- case DEBUG:
- getLog().debug(message, t);
- }
- }
- // 400 - Bad Request
- response.setStatus(400);
- setErrorState(ErrorState.CLOSE_CLEAN, t);
- getAdapter().log(request, response, 0);
- }
- if (!getErrorState().isError()) {
- // Setting up filters, and parse some request headers
- rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
- try {
- prepareRequest();
- } catch (Throwable t) {
- ExceptionUtils.handleThrowable(t);
- if (getLog().isDebugEnabled()) {
- getLog().debug(sm.getString("http11processor.request.prepare"), t);
- }
- // 500 - Internal Server Error
- response.setStatus(500);
- setErrorState(ErrorState.CLOSE_CLEAN, t);
- getAdapter().log(request, response, 0);
- }
- }
- if (maxKeepAliveRequests == 1) {
- keepAlive = false;
- } else if (maxKeepAliveRequests > 0 && socketWrapper.decrementKeepAlive() <= 0) {
- keepAlive = false;
- }
- // Process the request in the adapter
- if (!getErrorState().isError()) {
- try {
- rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
- adapter.service(request, response);
- // Handle when the response was committed before a serious
- // error occurred. Throwing a ServletException should both
- // set the status to 500 and set the errorException.
- // If we fail here, then the response is likely already
- // committed, so we can't try and set headers.
- if (keepAlive
- && !getErrorState().isError()
- && (response.getErrorException() != null || (!isAsync() && statusDropsConnection(response
- .getStatus())))) {
- setErrorState(ErrorState.CLOSE_CLEAN, null);
- }
- setCometTimeouts(socketWrapper);
- } catch (InterruptedIOException e) {
- setErrorState(ErrorState.CLOSE_NOW, e);
- } catch (HeadersTooLargeException e) {
- getLog().error(sm.getString("http11processor.request.process"), e);
- // The response should not have been committed but check it
- // anyway to be safe
- if (response.isCommitted()) {
- setErrorState(ErrorState.CLOSE_NOW, e);
- } else {
- response.reset();
- response.setStatus(500);
- setErrorState(ErrorState.CLOSE_CLEAN, e);
- response.setHeader("Connection", "close"); // TODO: Remove
- }
- } catch (Throwable t) {
- ExceptionUtils.handleThrowable(t);
- getLog().error(sm.getString("http11processor.request.process"), t);
- // 500 - Internal Server Error
- response.setStatus(500);
- setErrorState(ErrorState.CLOSE_CLEAN, t);
- getAdapter().log(request, response, 0);
- }
- }
- // Finish the handling of the request
- rp.setStage(org.apache.coyote.Constants.STAGE_ENDINPUT);
- if (!isAsync() && !comet) {
- if (getErrorState().isError()) {
- // If we know we are closing the connection, don't drain
- // input. This way uploading a 100GB file doesn't tie up the
- // thread if the servlet has rejected it.
- getInputBuffer().setSwallowInput(false);
- } else {
- // Need to check this again here in case the response was
- // committed before the error that requires the connection
- // to be closed occurred.
- checkExpectationAndResponseStatus();
- }
- endRequest();
- }
- rp.setStage(org.apache.coyote.Constants.STAGE_ENDOUTPUT);
- // If there was an error, make sure the request is counted as
- // and error, and update the statistics counter
- if (getErrorState().isError()) {
- response.setStatus(500);
- }
- request.updateCounters();
- if (!isAsync() && !comet || getErrorState().isError()) {
- if (getErrorState().isIoAllowed()) {
- getInputBuffer().nextRequest();
- getOutputBuffer().nextRequest();
- }
- }
- if (!disableUploadTimeout) {
- if (endpoint.getSoTimeout() > 0) {
- setSocketTimeout(endpoint.getSoTimeout());
- } else {
- setSocketTimeout(0);
- }
- }
- rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);
- if (breakKeepAliveLoop(socketWrapper)) {
- break;
- }
- }
- rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);
- if (getErrorState().isError() || endpoint.isPaused()) {
- System.out.println("close1:" + getErrorState().name());
- return SocketState.CLOSED;
- } else if (isAsync() || comet) {
- return SocketState.LONG;
- } else if (isUpgrade()) {
- return SocketState.UPGRADING;
- } else if (getUpgradeInbound() != null) {
- return SocketState.UPGRADING_TOMCAT;
- } else {
- if (sendfileInProgress) {
- return SocketState.SENDFILE;
- } else {
- if (openSocket) {
- if (readComplete) {
- return SocketState.OPEN;
- } else {
- return SocketState.LONG;
- }
- } else {
- System.out.println("close2");
- return SocketState.CLOSED;
- }
- }
- }
- }
6.CoyoteAdapter会先postParseRequest设置对应的Context,Wrapper解析额外的请求参数比如cookies,session等,然后调用engine的管道最终调用servlet。
- public void service(org.apache.coyote.Request req,
- org.apache.coyote.Response res)
- throws Exception {
- Request request = (Request) req.getNote(ADAPTER_NOTES);
- Response response = (Response) res.getNote(ADAPTER_NOTES);
- if (request == null) {
- // Create objects
- request = connector.createRequest();
- request.setCoyoteRequest(req);
- response = connector.createResponse();
- response.setCoyoteResponse(res);
- // Link objects
- request.setResponse(response);
- response.setRequest(request);
- // Set as notes
- req.setNote(ADAPTER_NOTES, request);
- res.setNote(ADAPTER_NOTES, response);
- // Set query string encoding
- req.getParameters().setQueryStringEncoding
- (connector.getURIEncoding());
- }
- if (connector.getXpoweredBy()) {
- response.addHeader("X-Powered-By", POWERED_BY);
- }
- boolean comet = false;
- boolean async = false;
- boolean postParseSuccess = false;
- try {
- // Parse and set Catalina and configuration specific
- // request parameters
- req.getRequestProcessor().setWorkerThreadName(Thread.currentThread().getName());
- postParseSuccess = postParseRequest(req, request, res, response);
- if (postParseSuccess) {
- //check valves if we support async
- request.setAsyncSupported(connector.getService().getContainer().getPipeline().isAsyncSupported());
- // Calling the container
- connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);
- if (request.isComet()) {
- if (!response.isClosed() && !response.isError()) {
- if (request.getAvailable() || (request.getContentLength() > 0 && (!request.isParametersParsed()))) {
- // Invoke a read event right away if there are available bytes
- if (event(req, res, SocketStatus.OPEN_READ)) {
- comet = true;
- res.action(ActionCode.COMET_BEGIN, null);
- } else {
- return;
- }
- } else {
- comet = true;
- res.action(ActionCode.COMET_BEGIN, null);
- }
- } else {
- // Clear the filter chain, as otherwise it will not be reset elsewhere
- // since this is a Comet request
- request.setFilterChain(null);
- }
- }
- }
- if (request.isAsync()) {
- async = true;
- Throwable throwable =
- (Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION);
- // If an async request was started, is not going to end once
- // this container thread finishes and an error occurred, trigger
- // the async error process
- if (!request.isAsyncCompleting() && throwable != null) {
- request.getAsyncContextInternal().setErrorState(throwable, true);
- }
- } else if (!comet) {
- try {
- request.finishRequest();
- response.finishResponse();
- } finally {
- if (postParseSuccess) {
- // Log only if processing was invoked.
- // If postParseRequest() failed, it has already logged it.
- // If context is null this was the start of a comet request
- // that failed and has already been logged.
- ((Context) request.getMappingData().context).logAccess(
- request, response,
- System.currentTimeMillis() - req.getStartTime(),
- false);
- }
- req.action(ActionCode.POST_REQUEST , null);
- }
- }
- } catch (IOException e) {
- // Ignore
- } finally {
- req.getRequestProcessor().setWorkerThreadName(null);
- AtomicBoolean error = new AtomicBoolean(false);
- res.action(ActionCode.IS_ERROR, error);
- // Recycle the wrapper request and response
- if (!comet && !async || error.get()) {
- request.recycle();
- response.recycle();
- } else {
- // Clear converters so that the minimum amount of memory
- // is used by this processor
- request.clearEncoders();
- response.clearEncoders();
- }
- }
- }
- protected boolean postParseRequest(org.apache.coyote.Request req,
- Request request,
- org.apache.coyote.Response res,
- Response response)
- throws Exception {
- // XXX the processor may have set a correct scheme and port prior to this point,
- // in ajp13 protocols dont make sense to get the port from the connector...
- // otherwise, use connector configuration
- if (! req.scheme().isNull()) {
- // use processor specified scheme to determine secure state
- request.setSecure(req.scheme().equals("https"));
- } else {
- // use connector scheme and secure configuration, (defaults to
- // "http" and false respectively)
- req.scheme().setString(connector.getScheme());
- request.setSecure(connector.getSecure());
- }
- // FIXME: the code below doesnt belongs to here,
- // this is only have sense
- // in Http11, not in ajp13..
- // At this point the Host header has been processed.
- // Override if the proxyPort/proxyHost are set
- String proxyName = connector.getProxyName();
- int proxyPort = connector.getProxyPort();
- if (proxyPort != 0) {
- req.setServerPort(proxyPort);
- }
- if (proxyName != null) {
- req.serverName().setString(proxyName);
- }
- // Copy the raw URI to the decodedURI
- MessageBytes decodedURI = req.decodedURI();
- decodedURI.duplicate(req.requestURI());
- // Parse the path parameters. This will:
- // - strip out the path parameters
- // - convert the decodedURI to bytes
- parsePathParameters(req, request);
- // URI decoding
- // %xx decoding of the URL
- try {
- req.getURLDecoder().convert(decodedURI, false);
- } catch (IOException ioe) {
- res.setStatus(400);
- res.setMessage("Invalid URI: " + ioe.getMessage());
- connector.getService().getContainer().logAccess(
- request, response, 0, true);
- return false;
- }
- // Normalization
- if (!normalize(req.decodedURI())) {
- res.setStatus(400);
- res.setMessage("Invalid URI");
- connector.getService().getContainer().logAccess(
- request, response, 0, true);
- return false;
- }
- // Character decoding
- convertURI(decodedURI, request);
- // Check that the URI is still normalized
- if (!checkNormalize(req.decodedURI())) {
- res.setStatus(400);
- res.setMessage("Invalid URI character encoding");
- connector.getService().getContainer().logAccess(
- request, response, 0, true);
- return false;
- }
- // Request mapping.
- MessageBytes serverName;
- if (connector.getUseIPVHosts()) {
- serverName = req.localName();
- if (serverName.isNull()) {
- // well, they did ask for it
- res.action(ActionCode.REQ_LOCAL_NAME_ATTRIBUTE, null);
- }
- } else {
- serverName = req.serverName();
- }
- if (request.isAsyncStarted()) {
- //TODO SERVLET3 - async
- //reset mapping data, should prolly be done elsewhere
- request.getMappingData().recycle();
- }
- // Version for the second mapping loop and
- // Context that we expect to get for that version
- String version = null;
- Context versionContext = null;
- boolean mapRequired = true;
- while (mapRequired) {
- // This will map the the latest version by default
- connector.getMapper().map(serverName, decodedURI, version,
- request.getMappingData());
- request.setContext((Context) request.getMappingData().context);
- request.setWrapper((Wrapper) request.getMappingData().wrapper);
- // If there is no context at this point, it is likely no ROOT context
- // has been deployed
- if (request.getContext() == null) {
- res.setStatus(404);
- res.setMessage("Not found");
- // No context, so use host
- Host host = request.getHost();
- // Make sure there is a host (might not be during shutdown)
- if (host != null) {
- host.logAccess(request, response, 0, true);
- }
- return false;
- }
- // Now we have the context, we can parse the session ID from the URL
- // (if any). Need to do this before we redirect in case we need to
- // include the session id in the redirect
- String sessionID;
- if (request.getServletContext().getEffectiveSessionTrackingModes()
- .contains(SessionTrackingMode.URL)) {
- // Get the session ID if there was one
- sessionID = request.getPathParameter(
- SessionConfig.getSessionUriParamName(
- request.getContext()));
- if (sessionID != null) {
- request.setRequestedSessionId(sessionID);
- request.setRequestedSessionURL(true);
- }
- }
- // Look for session ID in cookies and SSL session
- parseSessionCookiesId(req, request);
- parseSessionSslId(request);
- sessionID = request.getRequestedSessionId();
- mapRequired = false;
- if (version != null && request.getContext() == versionContext) {
- // We got the version that we asked for. That is it.
- } else {
- version = null;
- versionContext = null;
- Object[] contexts = request.getMappingData().contexts;
- // Single contextVersion means no need to remap
- // No session ID means no possibility of remap
- if (contexts != null && sessionID != null) {
- // Find the context associated with the session
- for (int i = (contexts.length); i > 0; i--) {
- Context ctxt = (Context) contexts[i - 1];
- if (ctxt.getManager().findSession(sessionID) != null) {
- // We found a context. Is it the one that has
- // already been mapped?
- if (!ctxt.equals(request.getMappingData().context)) {
- // Set version so second time through mapping
- // the correct context is found
- version = ctxt.getWebappVersion();
- versionContext = ctxt;
- // Reset mapping
- request.getMappingData().recycle();
- mapRequired = true;
- // Recycle session info in case the correct
- // context is configured with different settings
- request.recycleSessionInfo();
- }
- break;
- }
- }
- }
- }
- if (!mapRequired && request.getContext().getPaused()) {
- // Found a matching context but it is paused. Mapping data will
- // be wrong since some Wrappers may not be registered at this
- // point.
- try {
- Thread.sleep(1000);
- } catch (InterruptedException e) {
- // Should never happen
- }
- // Reset mapping
- request.getMappingData().recycle();
- mapRequired = true;
- }
- }
- // Possible redirect
- MessageBytes redirectPathMB = request.getMappingData().redirectPath;
- if (!redirectPathMB.isNull()) {
- String redirectPath = urlEncoder.encode(redirectPathMB.toString(), "UTF-8");
- String query = request.getQueryString();
- if (request.isRequestedSessionIdFromURL()) {
- // This is not optimal, but as this is not very common, it
- // shouldn't matter
- redirectPath = redirectPath + ";" +
- SessionConfig.getSessionUriParamName(
- request.getContext()) +
- "=" + request.getRequestedSessionId();
- }
- if (query != null) {
- // This is not optimal, but as this is not very common, it
- // shouldn't matter
- redirectPath = redirectPath + "?" + query;
- }
- response.sendRedirect(redirectPath);
- request.getContext().logAccess(request, response, 0, true);
- return false;
- }
- // Filter trace method
- if (!connector.getAllowTrace()
- && req.method().equalsIgnoreCase("TRACE")) {
- Wrapper wrapper = request.getWrapper();
- String header = null;
- if (wrapper != null) {
- String[] methods = wrapper.getServletMethods();
- if (methods != null) {
- for (int i=0; i<methods.length; i++) {
- if ("TRACE".equals(methods[i])) {
- continue;
- }
- if (header == null) {
- header = methods[i];
- } else {
- header += ", " + methods[i];
- }
- }
- }
- }
- res.setStatus(405);
- res.addHeader("Allow", header);
- res.setMessage("TRACE method is not allowed");
- request.getContext().logAccess(request, response, 0, true);
- return false;
- }
- doConnectorAuthenticationAuthorization(req, request);
- return true;
- }
- public String getParameter(String name) {
- if (!parametersParsed) {
- parseParameters();
- }
- return coyoteRequest.getParameters().getParameter(name);
- }
- public void setProperties(Socket socket) throws SocketException{
- if (rxBufSize != null)
- socket.setReceiveBufferSize(rxBufSize.intValue());
- if (txBufSize != null)
- socket.setSendBufferSize(txBufSize.intValue());
- if (ooBInline !=null)
- socket.setOOBInline(ooBInline.booleanValue());
- if (soKeepAlive != null)
- socket.setKeepAlive(soKeepAlive.booleanValue());
- if (performanceConnectionTime != null && performanceLatency != null &&
- performanceBandwidth != null)
- socket.setPerformancePreferences(
- performanceConnectionTime.intValue(),
- performanceLatency.intValue(),
- performanceBandwidth.intValue());
- if (soReuseAddress != null)
- socket.setReuseAddress(soReuseAddress.booleanValue());
- if (soLingerOn != null && soLingerTime != null)
- socket.setSoLinger(soLingerOn.booleanValue(),
- soLingerTime.intValue());
- if (soTimeout != null && soTimeout.intValue() >= 0)
- socket.setSoTimeout(soTimeout.intValue());
- if (tcpNoDelay != null)
- socket.setTcpNoDelay(tcpNoDelay.booleanValue());
- }