浅析Tomcat之Processor及其实现类

Coyote连接器的org.apache.coyote.Processor<S>是主要负责请求的预处理.并通过它将请求转发给Adapter.不同的Protocol有不同的实现方式,那么自然其对应的Processor实现也不同.其中AbstractProcessor对为这些不同的Processor提供了一个基础的实现.它实现了HTTP和AJP所需要的共同功能和属性.

首先看下Processor是一个接口.它定义了几个重要的方法.

/**
 * Common interface for processors of all protocols.
 */
public interface Processor<S> {
    Executor getExecutor();

    SocketState process(SocketWrapper<S> socketWrapper) throws IOException;

    SocketState event(SocketStatus status) throws IOException;

    SocketState asyncDispatch(SocketStatus status);
    SocketState asyncPostProcess();

    UpgradeInbound getUpgradeInbound();
    SocketState upgradeDispatch() throws IOException;

    boolean isComet();
    boolean isAsync();
    boolean isUpgrade();

    Request getRequest();

    void recycle(boolean socketClosing);

    void setSslSupport(SSLSupport sslSupport);
}

 Processor定义了请求的处理等方法.AbstractProcessor最主要还是最一些协议共有的属性进行封装.而没有对方法进行实现.目前具体的实现只针对AJP和HTTP.这两个类分别为AbstractAjpProcessor和AbstractHttp11Processor它们对协议的方法请求处理方式进行了实现.以AbstractHttp11Processor的process方法为例.

public SocketState process(SocketWrapper<S> socketWrapper)
	throws IOException {

	.....

	while (!error && keepAlive && !comet && !isAsync() &&
			upgradeInbound == 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);
				error = true;
			} else {
				request.setStartTime(System.currentTimeMillis());
				keptAlive = true;
				// Set this every time in case limit has been changed via JMX
				request.getMimeHeaders().setLimit(endpoint.getMaxHeaderCount());
				// 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) {
			...
		} catch (Throwable t) {
			....
		}

		if (!error) {
			// 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);
				}
				// 400 - Internal Server Error
				response.setStatus(400);
				adapter.log(request, response, 0);
				error = true;
			}
		}

		....

		// Process the request in the adapter
		if (!error) {
			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 && !error) { // Avoid checking twice.
					error = response.getErrorException() != null ||
							(!isAsync() &&
							statusDropsConnection(response.getStatus()));
				}
				setCometTimeouts(socketWrapper);
			} catch (InterruptedIOException e) {
				error = true;
			} catch (HeadersTooLargeException e) {
				error = true;
				// The response should not have been committed but check it
				// anyway to be safe
				if (!response.isCommitted()) {
					response.reset();
					response.setStatus(500);
					response.setHeader("Connection", "close");
				}
			} catch (Throwable t) {
				ExceptionUtils.handleThrowable(t);
				getLog().error(sm.getString(
						"http11processor.request.process"), t);
				// 500 - Internal Server Error
				response.setStatus(500);
				adapter.log(request, response, 0);
				error = true;
			}
		}

		// Finish the handling of the request
		rp.setStage(org.apache.coyote.Constants.STAGE_ENDINPUT);

		if (!isAsync() && !comet) {
			if (error) {
				// 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);
			}
			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 (error) {
			response.setStatus(500);
		}
		request.updateCounters();

		if (!isAsync() && !comet || error) {
			getInputBuffer().nextRequest();
			getOutputBuffer().nextRequest();
		}

		if (!disableUploadTimeout) {
			setSocketTimeout(endpoint.getSoTimeout());
		}

		rp.setStage(org.apache.coyote.Constants.STAGE_KEEPALIVE);

		if (breakKeepAliveLoop(socketWrapper)) {
			break;
		}
	}

	rp.setStage(org.apache.coyote.Constants.STAGE_ENDED);

	if (error || endpoint.isPaused()) {
		return SocketState.CLOSED;
	} else if (isAsync() || comet) {
		return SocketState.LONG;
	} else if (isUpgrade()) {
		return SocketState.UPGRADING;
	} else {
		if (sendfileInProgress) {
			return SocketState.SENDFILE;
		} else {
			if (openSocket) {
				if (readComplete) {
					return SocketState.OPEN;
				} else {
					return SocketState.LONG;
				}
			} else {
				return SocketState.CLOSED;
			}
		}
	}
}

   上述process方法的作用有3点,第一是解析请求header也就是HTTP协议的报文头.主要是通过调用方法prepareRequest.在该方法中会检查HTTP协议报文头的user-agent,transfer-encoding以及URI等.此部分处理会倘若异常的话则返回400 – Internal Server Error.这是通过设置response状态来实现的,即语句response.setStatus(400).第二就是通过调用连接适配器的service方法,来处理请求(具体如何处理后续说明).最后,当请求处理完成以后.则使用endRequest方法来结束请求,且返回处理状态,也就是Protocol能识别的状态SocketStatus.

AbstractAjpProcessor和AbstractHttp11Processor只是针对AJP和HTTP协议通用处理方式进行实现.但是针对这2个协议的具体实现版本处理的Processor需要进行特性补充处理.如AbstractHttp11Processor的子类Http11Processor,Http11NioProcessor,Http11AprProcessor分别对应了Java Old IO,NIO,APR的协议实现方式的Processor,有兴趣可以详细阅读.

 

 

首发于泛泛之辈 - http://www.lihongkun.com/archives/132

猜你喜欢

转载自lihkstyle.iteye.com/blog/1944405