Tomcat源码解析系列五:Tomcat处理Http请求

本文详细解析了Tomcat处理Http1.1请求的过程,包括从实例化Http11NioProtocol,NioEndPoint获取socket请求,到Http11Processor的各个阶段,如解析请求行和请求头,调用Container的Valve处理请求,以及解析请求体和写响应数据的细节。重点探讨了解析过程中如何处理拆包和粘包问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Tomcat处理Http请求

简介

本文只分析http1.1的请求,tomcat版本:8.4.45

Http请求响应报文

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cgcG8RNQ-1684649053392)(assets/image-20220726154656267.png)]

请求的处理链路

实例化Http11NioProtocol

根据server.xml中的<connector/>来实例化Http11NioProtocol

<Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
  • protocol是应用层协议名,可填参数有HTTP/1.1、org.apache.coyote.http11.Http11NioProtocol、AJP/1.3、org.apache.coyote.ajp.AjpNioProtocol,如果protocol不填,则默认为Http11NioProtocol。

实例化Http11NioProtocol

public Http11NioProtocol() {
   
   
	super(new NioEndpoint());
}

public AbstractHttp11JsseProtocol(AbstractJsseEndpoint<S> endpoint) {
   
   
  super(endpoint);
}

public AbstractHttp11Protocol(AbstractEndpoint<S> endpoint) {
   
   
  super(endpoint);
  setConnectionTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT);
  // 初始化ConnectionHandler, ConnectionHandler来获取Http11Processor
  ConnectionHandler<S> cHandler = new ConnectionHandler<>(this);
  setHandler(cHandler);
  getEndpoint().setHandler(cHandler);
}


NioEndPoint获取到socket请求

Acceptor接收到请求封装成一个SocketProcessor扔进线程池Executor后,会调用Processor从操作系统底层读取、过滤字节流,对应用层协议(HTTP/AJP)进行解析封装,生成org.apache.coyote.Request和org.apache.coyote.Response对象。不同的协议有不同的Processor,HTTP/1.1对应Http11Processor,AJP对应AjpProcessor,HTTP/1.2对应StreamProcessor,UpgradeProcessorInternal 和 UpgradeProcessorExternal用于协议升级:

SocketProcessor并不是直接调用的Processor,而是通过org.apache.coyote.AbstractProtocol.ConnectionHandler#process找到一个合适的Processor进行请求处理:根据不同协议创建Http11Processor or AjpProcessor;

详见系列二:tomcat的Reactor机制/http请求连接处理机制

根据Http11NioProtocol得到Http11Processor

protected Processor createProcessor() {
   
   
        Http11Processor processor = new Http11Processor(getMaxHttpHeaderSize(),
                getAllowHostHeaderMismatch(), getRejectIllegalHeaderName(), getEndpoint(),
                getMaxTrailerSize(), allowedTrailerHeaders, getMaxExtensionSize(),
                getMaxSwallowSize(), httpUpgradeProtocols, getSendReasonPhrase(),
                relaxedPathChars, relaxedQueryChars);
        processor.setAdapter(getAdapter());
        processor.setMaxKeepAliveRequests(getMaxKeepAliveRequests());
        processor.setConnectionUploadTimeout(getConnectionUploadTimeout());
        processor.setDisableUploadTimeout(getDisableUploadTimeout());
        processor.setCompressionMinSize(getCompressionMinSize());
        processor.setCompression(getCompression());
        processor.setNoCompressionUserAgents(getNoCompressionUserAgents());
        processor.setCompressibleMimeTypes(getCompressibleMimeTypes());
        processor.setRestrictedUserAgents(getRestrictedUserAgents());
        processor.setMaxSavePostSize(getMaxSavePostSize());
        processor.setServer(getServer());
        processor.setServerRemoveAppProvidedValues(getServerRemoveAppProvidedValues());
        return processor;
}

Http11Processor处理Http请求

public SocketState service(SocketWrapperBase<?> socketWrapper)
    throws IOException {
   
   
    RequestInfo rp = request.getRequestProcessor();
    rp.setStage(org.apache.coyote.Constants.STAGE_PARSE);

    // Setting up the I/O
    // 初始化 inputBuffer.byteBuffer
    // 初始化 outputBuffer
    setSocketWrapper(socketWrapper);

    // Flags
    // keepAlive表示客户端与服务端连接是长连接Keep-alive,就是说客户端socket连接到服务端之后,
    // 告诉服务端这个socket你别给我关了,要一直保持连接。
    keepAlive = true;
    openSocket = false;
    readComplete = true;
    boolean keptAlive = false;
    SendfileState sendfileState = SendfileState.DONE;

    while (!getErrorState().isError() && keepAlive && !isAsync() && upgradeToken == null &&
            sendfileState == SendfileState.DONE && !endpoint.isPaused()) {
   
   

        // Parsing the request header
        try {
   
   
            // 解析请求行
            if (!inputBuffer.parseRequestLine(keptAlive)) {
   
   
                if (inputBuffer.getParsingRequestLinePhase() == -1) {
   
   
                    return SocketState.UPGRADING;
                } else 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());
                // 解析请求头
                if (!inputBuffer.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) {
   
   
                    socketWrapper.setReadTimeout(connectionUploadTimeout);
                }
            }
        } catch (IOException e) {
   
   
            if (log.isDebugEnabled()) {
   
   
                log.debug(sm.getString("http11processor.header.parse"), e);
            }
            setErrorState(ErrorState.CLOSE_CONNECTION_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:
                        log.info(message, t);
                        break;
                    case DEBUG:
                        log.debug(message, t);
                }
            }
            // 400 - Bad Request
            response.setStatus(400);
            setErrorState(ErrorState.CLOSE_CLEAN, t);
        }

        // Has an upgrade been requested?
        Enumeration<String> connectionValues = request.getMimeHeaders().values("Connection");
        boolean foundUpgrade = false;
        while (connectionValues.hasMoreElements() && !foundUpgrade) {
   
   
            String connectionValue = connectionValues.nextElement();
            if (connectionValue != null) {
   
   
                foundUpgrade = connectionValue.toLowerCase(Locale.ENGLISH).contains("upgrade");
            }
        }

        if (foundUpgrade) {
   
   
            // Check the protocol
            String requestedProtocol = request.getHeader("Upgrade");

            UpgradeProtocol upgradeProtocol = httpUpgradeProtocols.get(requestedProtocol);
            if (upgradeProtocol != null) {
   
   
                if (upgradeProtocol.accept(request)) {
   
   
                    // TODO Figure out how to handle request bodies at this
                    // point.
                    response.setStatus(HttpServletResponse.SC_SWITCHING_PROTOCOLS);
                    response.setHeader("Connection", "Upgrade");
                    response.setHeader("Upgrade", requestedProtocol);
                    action(ActionCode.CLOSE,  null);
                    getAdapter().log(request, response, 0);

                    InternalHttpUpgradeHandler upgradeHandler =
                            upgradeProtocol.getInternalUpgradeHandler(
                                    getAdapter(), cloneRequest(request));
                    UpgradeToken upgradeToken = new UpgradeToken(upgradeHandler, null, null);
                    action(ActionCode.UPGRADE, upgradeToken);
                    return SocketState.UPGRADING;
                }
            }
        }

        if (getErrorState().isIoAllowed()) {
   
   
            // Setting up filters, and parse some request headers
            rp.setStage(org.apache.coyote.Constants.STAGE_PREPARE);
            try {
   
   
                // 设置ActiveFilter, 根据contextLength来选择InputFilter, 来解决拆包以及粘包问题
                prepareRequest();
            } catch (Throwable t) {
   
   
                ExceptionUtils.handleThrowable(t);
                if (log.isDebugEnabled()) {
   
   
                    log.debug(sm.getString("http11processor.request.prepare"), t);
                }
                // 500 - Internal Server Error
                response.setStatus(500);
                setErrorState(ErrorState.CLOSE_CLEAN, t);
            }
        }

        if (maxKeepAliveRequests == 1) {
   
   
            keepAlive = false;
        } else if (maxKeepAliveRequests > 0 &&
                socketWrapper.decrementKeepAlive() <= 0) {
   
   
            keepAlive = false;
        }

        // Process the request in the adapter
        if (getErrorState().isIoAllowed()) {
   
   
            try {
   
   
                rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE);
                getAdapter().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() && !isAsync() &&
                        statusDropsConnection(response.getStatus())) {
   
   
                    setErrorState(ErrorState.CLOSE_CLEAN, null);
                }
            } catch (InterruptedIOException e) {
   
   
                setErrorState(ErrorState.CLOSE_CONNECTION_NOW, e);
            } catch (HeadersTooLargeException e) {
   
   
                log.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);
                log.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()) {
   
   
            // If this is an async request then the request ends when it has
            // been completed. The AsyncContext is responsible for calling
            // endRequest() in that case.
            // 重置inputBuffer的ByteBuffer的position防止粘包
            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);
        }

        if (!isAsync() || getErrorState().isError()) {
   
   
            request.updateCounters();
            if (getErrorState().isIoAllowed()) {
   
   
                // 重置 inputBuffer.byteBuffer.position 的来准备读
                inputBuffer.nextRequest();
                outputBuffer.nextRequest();
            }
        }

        if (!disableUploadTimeout) {
   
   
            int soTimeout = endpoint.getConnectionTimeout();
            if(soTimeout > 0) {
   
   
                socketWrapper.setReadTimeout(soTimeout);
            } else {
   
   
                socketWrapper.setReadTimeout(0);
            }
        }

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

        sendfileState = processSendfile(socketWrapper);
    }

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

    if (getErrorState().isError() || endpoint.isPaused()) {
   
   
        return SocketState.CLOSED;
    } else if (isAsync()) {
   
   
        return SocketState.LONG;
    } else if (isUpgrade()) {
   
   
        return SocketState.UPGRADING;
    } else {
   
   
        if (sendfileState == SendfileState.PENDING) {
   
   
            return SocketState.SENDFILE;
        } else {
   
   
            if (openSocket) {
   
   
                if (readComplete) {
   
   
                    return SocketState.OPEN;
                } else {
   
   
                    return SocketState.LONG;
                }
            } else {
   
   
                return SocketState.CLOSED;
            }
        }
    }
}
初始化inputBuffer以及outputBuffer
protected final void setSocketWrapper(SocketWrapperBase<?> socketWrapper) {
   
   
    super.setSocketWrapper(socketWrapper);
    inputBuffer.init(socketWrapper);
    outputBuffer.init(socketWrapper);
}

org.apache.coyote.http11.Http11InputBuffer#init

void init(SocketWrapperBase<?> socketWrapper) {
   
   

  wrapper = socketWrapper;
  wrapper.setAppReadBufHandler(this);

  int bufLength = headerBufferSize +
    wrapper.getSocketBufferHandler().getReadBuffer().capacity();
  if (byteBuffer == null || byteBuffer.capacity() < bufLength) {
   
   
    byteBuffer = ByteBuffer.allocate(bufLength);
    byteBuffer.position(0).limit(0);
  }
}

org.apache.coyote.http11.Http11OutputBuffer#init

public void init(SocketWrapperBase<?> socketWrapper) {
   
   
    this.socketWrapper = socketWrapper;
}
inputBuffer解析Http请求行
boolean parseRequestLine(boolean keptAlive) throws IOException {
   
   

    // check state
    if (!parsingRequestLine) {
   
   
        return true;
    }
    //
    // Skipping blank lines
    //
    if (parsingRequestLinePhase < 2) {
   
   
        byte chr = 0;
        // 过滤掉回车换行符
        do {
   
   

            // Read new bytes if needed
            if (byteBuffer.position() >= byteBuffer.limit()) {
   
   
                if (keptAlive) {
   
   
                    // Haven't read any request data yet so use the keep-alive
                    // timeout.
                    wrapper.setReadTimeout(wrapper.getEndpoint().getKeepAliveTimeout());
                }
                // 从操作系统的输入缓冲区读取数据
                if (!fill(false)) {
   
   
                    // A read is pending, so no longer in initial state
                    parsingRequestLinePhase = 1;
                    return false;
                }
                // At least one byte of the request has been received.
                // Switch to the socket timeout.
                wrapper.setReadTimeout(wrapper.getEndpoint().getConnectionTimeout());
            }
            if (!keptAlive && byteBuffer.position() == 0 && byteBuffer.limit() >= CLIENT_PREFACE_START.length - 1) {
   
   
                boolean prefaceMatch = true;
                for (int i = 0; i < CLIENT_PREFACE_START.length && prefaceMatch; i++) {
   
   
                    if (CLIENT_PREFACE_START[i] != byteBuffer.get(i)) {
   
   
                        prefaceMatch = false;
                    }
                }
                if (prefaceMatch) {
   
   
                    // HTTP/2 preface matched
                    parsingRequestLinePhase = -1;
                    return false;
                }
            }
            // Set the start time once we start reading data (even if it is
            // just skipping blank lines)
            if (request.getStartTime() < 0) {
   
   
                request.setStartTime(System.currentTimeMillis());
            }
            chr = byteBuffer.get();
        } while ((chr == Constants.CR) || (chr == Constants.LF));
        byteBuffer.position(byteBuffer.position() - 1);

        parsingRequestLineStart = byteBuffer.position();
        parsingRequestLinePhase = 2;
        if (log.isDebugEnabled()) {
   
   
            log.debug("Received ["
                    + new String(byteBuffer.array(), byteBuffer.position(), byteBuffer.<
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值