TA的每日心情 | 开心 2021-12-13 21:45 |
---|
签到天数: 15 天 [LV.4]偶尔看看III
|
tomcat进行http request解析的时候报错,并将错误返回给客户端了,具体的错误如下:
- org.apache.coyote.http11.AbstractHttp11Processor.process Error parsing HTTP request header
- Note: further occurrences of HTTP header parsing errors will be logged at DEBUG level.
复制代码
查看对应的类代码,其中涉及的方法如下:
- 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() &&
- 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());
- // 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);
- break;
- case DEBUG:
- getLog().debug(message);
- }
- }
- // 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);
- 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() && (
- 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) {
- // 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 if (expectation &&
- (response.getStatus() < 200 || response.getStatus() > 299)) {
- // Client sent Expect: 100-continue but received a
- // non-2xx final response. Disable keep-alive (if enabled)
- // to ensure that the connection is closed. Some clients may
- // still send the body, some may send the next request.
- // No way to differentiate, so close the connection to
- // force the client to send the next request.
- getInputBuffer().setSwallowInput(false);
- keepAlive = 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 (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()) {
- 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;
- }
- }
- }
- }
复制代码
而报错的地方则是在:
- // 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块代码如下:
- 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);
- break;
- case DEBUG:
- getLog().debug(message);
- }
- }
- // 400 - Bad Request
- response.setStatus(400);
- setErrorState(ErrorState.CLOSE_CLEAN, t);
- getAdapter().log(request, response, 0);
- }
复制代码
错误日志的输出,是配置在LocalStrings.properties中的,相关的两个属性:
- http11processor.fallToDebug=\n Note\: further occurrences of HTTP header parsing errors will be logged at DEBUG level.
- http11processor.header.parse=Error parsing HTTP request header
复制代码
找到对应的 getInputBuffer().parseHeaders()
- public boolean parseHeaders()
- throws IOException {
- if (!parsingHeader) {
- throw new IllegalStateException(
- sm.getString("iib.parseheaders.ise.error"));
- }
- HeaderParseStatus status = HeaderParseStatus.HAVE_MORE_HEADERS;
- do {
- status = parseHeader();
- // Checking that
- // (1) Headers plus request line size does not exceed its limit
- // (2) There are enough bytes to avoid expanding the buffer when
- // reading body
- // Technically, (2) is technical limitation, (1) is logical
- // limitation to enforce the meaning of headerBufferSize
- // From the way how buf is allocated and how blank lines are being
- // read, it should be enough to check (1) only.
- if (pos > headerBufferSize
- || buf.length - pos < socketReadBufferSize) {
- throw new IllegalArgumentException(
- sm.getString("iib.requestheadertoolarge.error"));
- }
- } while ( status == HeaderParseStatus.HAVE_MORE_HEADERS );
- if (status == HeaderParseStatus.DONE) {
- parsingHeader = false;
- end = pos;
- return true;
- } else {
- return false;
- }
- }
复制代码
- 可知此处涉及了两个缓冲区大小,headerBufferSize和socketReadBufferSize,如果读取时数据的长度大于这两个值,就会报iib.requestheadertoolarge.error即Request header is too large,在网上搜索时,有的是因为这个设置导致的400,解决方法就是修改Tomcat的server.xml,
- 在<Connector port="8080" protocol="HTTP/1.1"
- connectionTimeout="20000" redirectPort="8443" />的配置中增加maxHttpHeaderSize的配置
复制代码
在org.apache.coyote.http11.AbstractHttp11Protocol类中定义了其默认值:
- /**
- Maximum size of the HTTP message header. */
- private int maxHttpHeaderSize = 8 * 1024;
- /**
- Maximum size of the post which will be saved when processing certain requests, such as a POST. */
- private int maxSavePostSize = 4 * 1024;
- /**
- * Specifies a different (usually longer) connection timeout during data upload. */
- private int connectionUploadTimeout = 300000;
- /**
- Maximum size of trailing headers in bytes */
- private int maxTrailerSize = 8192;
- /**
- Maximum size of extension information in chunked encoding */
- private int maxExtensionSize = 8192;
- /**Maximum amount of request body to swallow.*/
- private int maxSwallowSize = 2 * 1024 * 1024;
复制代码
其他参数设置介绍: http://tomcat.apache.org/tomcat-8.0-doc/config/ajp.html
|
|