// Start our defined Connectors second synchronized (connectorsLock) { for (Connector connector: connectors) { // If it has already failed, don't try and start it if (connector.getState() != LifecycleState.FAILED) { connector.start(); } } } }
// Select the Host to be used for this Request Hosthost= request.getHost(); if (host == null) { // HTTP 0.9 or HTTP 1.0 request without a host when no default host // is defined. // Don't overwrite an existing error if (!response.isError()) { response.sendError(404); } return; } if (request.isAsyncSupported()) { request.setAsyncSupported(host.getPipeline().isAsyncSupported()); }
// Ask this Host to process this request host.getPipeline().getFirst().invoke(request, response); }
比较简单,就是调用 host 中的 pipeline 里的第一个 valve 来处理
第一个是 org.apache.catalina.valves.ErrorReportValve, 这里处理的其实是先调用了 next
// Perform the request getNext().invoke(request, response);
if (response.isCommitted()) { if (response.setErrorReported()) { // Error wasn't previously reported but we can't write an error // page because the response has already been committed.
// See if IO is allowed AtomicBooleanioAllowed=newAtomicBoolean(true); response.getCoyoteResponse().action(ActionCode.IS_IO_ALLOWED, ioAllowed);
if (ioAllowed.get()) { // I/O is currently still allowed. Flush any data that is // still to be written to the client. try { response.flushBuffer(); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); } // Now close immediately to signal to the client that // something went wrong response.getCoyoteResponse().action(ActionCode.CLOSE_NOW, request.getAttribute(RequestDispatcher.ERROR_EXCEPTION)); } } return; }
// If an async request is in progress and is not going to end once this // container thread finishes, do not process any error page here. if (request.isAsync() && !request.isAsyncCompleting()) { return; }
if (throwable != null && !response.isError()) { // Make sure that the necessary methods have been called on the // response. (It is possible a component may just have set the // Throwable. Tomcat won't do that but other components might.) // These are safe to call at this point as we know that the response // has not been committed. response.reset(); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); }
// One way or another, response.sendError() will have been called before // execution reaches this point and suspended the response. Need to // reverse that so this valve can write to the response. response.setSuspended(false);
// Select the Context to be used for this Request Contextcontext= request.getContext(); if (context == null) { // Don't overwrite an existing error if (!response.isError()) { response.sendError(404); } return; }
if (request.isAsyncSupported()) { request.setAsyncSupported(context.getPipeline().isAsyncSupported()); }
if (!asyncAtStart && !context.fireRequestInitEvent(request.getRequest())) { // Don't fire listeners during async processing (the listener // fired for the request that called startAsync()). // If a request init listener throws an exception, the request // is aborted. return; }
// Ask this Context to process this request. Requests that are // already in error must have been routed here to check for // application defined error pages so DO NOT forward them to the the // application for processing. try { if (!response.isErrorReportRequired()) { // 交给 context 去处理请求了 context.getPipeline().getFirst().invoke(request, response); } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); container.getLogger().error("Exception Processing " + request.getRequestURI(), t); // If a new error occurred while trying to report a previous // error allow the original error to be reported. if (!response.isErrorReportRequired()) { request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, t); throwable(request, response, t); } }
// Now that the request/response pair is back under container // control lift the suspension so that the error handling can // complete and/or the container can flush any remaining data response.setSuspended(false);
// Protect against NPEs if the context was destroyed during a // long running request. if (!context.getState().isAvailable()) { return; }
// Look for (and render if found) an application level error page if (response.isErrorReportRequired()) { // If an error has occurred that prevents further I/O, don't waste time // producing an error report that will never be read AtomicBooleanresult=newAtomicBoolean(false); response.getCoyoteResponse().action(ActionCode.IS_IO_ALLOWED, result); if (result.get()) { if (t != null) { throwable(request, response, t); } else { status(request, response); } } }
if (!request.isAsync() && !asyncAtStart) { context.fireRequestDestroyEvent(request.getRequest()); } } finally { // Access a session (if present) to update last accessed time, based // on a strict interpretation of the specification if (ACCESS_SESSION) { request.getSession(false); }
// Disallow any direct access to resources under WEB-INF or META-INF MessageBytesrequestPathMB= request.getRequestPathMB(); if ((requestPathMB.startsWithIgnoreCase("/META-INF/", 0)) || (requestPathMB.equalsIgnoreCase("/META-INF")) || (requestPathMB.startsWithIgnoreCase("/WEB-INF/", 0)) || (requestPathMB.equalsIgnoreCase("/WEB-INF"))) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return; }
// Select the Wrapper to be used for this Request Wrapperwrapper= request.getWrapper(); if (wrapper == null || wrapper.isUnavailable()) { response.sendError(HttpServletResponse.SC_NOT_FOUND); return; }
// Initialize local variables we may need booleanunavailable=false; Throwablethrowable=null; // This should be a Request attribute... long t1=System.currentTimeMillis(); requestCount.incrementAndGet(); StandardWrapperwrapper= (StandardWrapper) getContainer(); Servletservlet=null; Contextcontext= (Context) wrapper.getParent();
// Check for the application being marked unavailable if (!context.getState().isAvailable()) { response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, sm.getString("standardContext.isUnavailable")); unavailable = true; }
// Check for the servlet being marked unavailable if (!unavailable && wrapper.isUnavailable()) { container.getLogger().info(sm.getString("standardWrapper.isUnavailable", wrapper.getName())); longavailable= wrapper.getAvailable(); if ((available > 0L) && (available < Long.MAX_VALUE)) { response.setDateHeader("Retry-After", available); response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, sm.getString("standardWrapper.isUnavailable", wrapper.getName())); } elseif (available == Long.MAX_VALUE) { response.sendError(HttpServletResponse.SC_NOT_FOUND, sm.getString("standardWrapper.notFound", wrapper.getName())); } unavailable = true; }
// If this servlet has been marked permanently unavailable, // unload it and release this instance try { if ((servlet != null) && (wrapper.getAvailable() == Long.MAX_VALUE)) { wrapper.unload(); } } catch (Throwable e) { ExceptionUtils.handleThrowable(e); container.getLogger().error(sm.getString("standardWrapper.unloadException", wrapper.getName()), e); if (throwable == null) { exception(request, response, e); } } long t2=System.currentTimeMillis();
long time=t2-t1; processingTime += time; if( time > maxTime) { maxTime=time; } if( time < minTime) { minTime=time; } } }
@Override protectedvoiddoRun() { /* * Do not cache and re-use the value of socketWrapper.getSocket() in * this method. If the socket closes the value will be updated to * CLOSED_NIO_CHANNEL and the previous value potentially re-used for * a new connection. That can result in a stale cached value which * in turn can result in unintentionally closing currently active * connections. */ Pollerpoller= NioEndpoint.this.poller; if (poller == null) { socketWrapper.close();
protectedvoiddoRun() { /* * Do not cache and re-use the value of socketWrapper.getSocket() in * this method. If the socket closes the value will be updated to * CLOSED_NIO_CHANNEL and the previous value potentially re-used for * a new connection. That can result in a stale cached value which * in turn can result in unintentionally closing currently active * connections. */ Pollerpoller= NioEndpoint.this.poller; if (poller == null) { socketWrapper.close(); return; }
try { inthandshake= -1; try { if (socketWrapper.getSocket().isHandshakeComplete()) { // No TLS handshaking required. Let the handler // process this socket / event combination. handshake = 0; } elseif (event == SocketEvent.STOP || event == SocketEvent.DISCONNECT || event == SocketEvent.ERROR) { // Unable to complete the TLS handshake. Treat it as // if the handshake failed. handshake = -1; } else { handshake = socketWrapper.getSocket().handshake(event == SocketEvent.OPEN_READ, event == SocketEvent.OPEN_WRITE); // The handshake process reads/writes from/to the // socket. status may therefore be OPEN_WRITE once // the handshake completes. However, the handshake // happens when the socket is opened so the status // must always be OPEN_READ after it completes. It // is OK to always set this as it is only used if // the handshake completes. event = SocketEvent.OPEN_READ; } } catch (IOException x) { handshake = -1; if (log.isDebugEnabled()) { log.debug("Error during SSL handshake",x); } } catch (CancelledKeyException ckx) { handshake = -1; } if (handshake == 0) { SocketStatestate= SocketState.OPEN; // Process the request from this socket if (event == null) { state = getHandler().process(socketWrapper, SocketEvent.OPEN_READ); } else { state = getHandler().process(socketWrapper, event); } if (state == SocketState.CLOSED) { poller.cancelledKey(getSelectionKey(), socketWrapper); }
可以看到,先 new 了 StandardServer,再 new 了 StandardService,可以理解为创建 Server 后具体是由 service 进行服务, 而在 service 中就是上面的配置文件里显示的,service 包含了 connector,可以是多个connector,负责接入,具体内容可以参看上一篇 而后是 Engine,Engine 的关系是一个 Service 有一个 Engine,Engine 负责处理真正的逻辑,