Search in sources :

Example 11 with MimeHeaders

use of org.apache.tomcat.util.http.MimeHeaders in project tomcat by apache.

the class AjpProcessor method prepareRequest.

/**
     * After reading the request headers, we have to setup the request filters.
     */
private void prepareRequest() {
    // Translate the HTTP method code to a String.
    byte methodCode = requestHeaderMessage.getByte();
    if (methodCode != Constants.SC_M_JK_STORED) {
        String methodName = Constants.getMethodForCode(methodCode - 1);
        request.method().setString(methodName);
    }
    requestHeaderMessage.getBytes(request.protocol());
    requestHeaderMessage.getBytes(request.requestURI());
    requestHeaderMessage.getBytes(request.remoteAddr());
    requestHeaderMessage.getBytes(request.remoteHost());
    requestHeaderMessage.getBytes(request.localName());
    request.setLocalPort(requestHeaderMessage.getInt());
    boolean isSSL = requestHeaderMessage.getByte() != 0;
    if (isSSL) {
        request.scheme().setString("https");
    }
    // Decode headers
    MimeHeaders headers = request.getMimeHeaders();
    // Set this every time in case limit has been changed via JMX
    headers.setLimit(protocol.getMaxHeaderCount());
    boolean contentLengthSet = false;
    int hCount = requestHeaderMessage.getInt();
    for (int i = 0; i < hCount; i++) {
        String hName = null;
        // Header names are encoded as either an integer code starting
        // with 0xA0, or as a normal string (in which case the first
        // two bytes are the length).
        int isc = requestHeaderMessage.peekInt();
        int hId = isc & 0xFF;
        MessageBytes vMB = null;
        isc &= 0xFF00;
        if (0xA000 == isc) {
            // To advance the read position
            requestHeaderMessage.getInt();
            hName = Constants.getHeaderForCode(hId - 1);
            vMB = headers.addValue(hName);
        } else {
            // reset hId -- if the header currently being read
            // happens to be 7 or 8 bytes long, the code below
            // will think it's the content-type header or the
            // content-length header - SC_REQ_CONTENT_TYPE=7,
            // SC_REQ_CONTENT_LENGTH=8 - leading to unexpected
            // behaviour.  see bug 5861 for more information.
            hId = -1;
            requestHeaderMessage.getBytes(tmpMB);
            ByteChunk bc = tmpMB.getByteChunk();
            vMB = headers.addValue(bc.getBuffer(), bc.getStart(), bc.getLength());
        }
        requestHeaderMessage.getBytes(vMB);
        if (hId == Constants.SC_REQ_CONTENT_LENGTH || (hId == -1 && tmpMB.equalsIgnoreCase("Content-Length"))) {
            long cl = vMB.getLong();
            if (contentLengthSet) {
                response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
                setErrorState(ErrorState.CLOSE_CLEAN, null);
            } else {
                contentLengthSet = true;
                // Set the content-length header for the request
                request.setContentLength(cl);
            }
        } else if (hId == Constants.SC_REQ_CONTENT_TYPE || (hId == -1 && tmpMB.equalsIgnoreCase("Content-Type"))) {
            // just read the content-type header, so set it
            ByteChunk bchunk = vMB.getByteChunk();
            request.contentType().setBytes(bchunk.getBytes(), bchunk.getOffset(), bchunk.getLength());
        }
    }
    // Decode extra attributes
    String requiredSecret = protocol.getRequiredSecret();
    boolean secret = false;
    byte attributeCode;
    while ((attributeCode = requestHeaderMessage.getByte()) != Constants.SC_A_ARE_DONE) {
        switch(attributeCode) {
            case Constants.SC_A_REQ_ATTRIBUTE:
                requestHeaderMessage.getBytes(tmpMB);
                String n = tmpMB.toString();
                requestHeaderMessage.getBytes(tmpMB);
                String v = tmpMB.toString();
                /*
                 * AJP13 misses to forward the local IP address and the
                 * remote port. Allow the AJP connector to add this info via
                 * private request attributes.
                 * We will accept the forwarded data and remove it from the
                 * public list of request attributes.
                 */
                if (n.equals(Constants.SC_A_REQ_LOCAL_ADDR)) {
                    request.localAddr().setString(v);
                } else if (n.equals(Constants.SC_A_REQ_REMOTE_PORT)) {
                    try {
                        request.setRemotePort(Integer.parseInt(v));
                    } catch (NumberFormatException nfe) {
                    // Ignore invalid value
                    }
                } else if (n.equals(Constants.SC_A_SSL_PROTOCOL)) {
                    request.setAttribute(SSLSupport.PROTOCOL_VERSION_KEY, v);
                } else {
                    request.setAttribute(n, v);
                }
                break;
            case Constants.SC_A_CONTEXT:
                requestHeaderMessage.getBytes(tmpMB);
                // nothing
                break;
            case Constants.SC_A_SERVLET_PATH:
                requestHeaderMessage.getBytes(tmpMB);
                // nothing
                break;
            case Constants.SC_A_REMOTE_USER:
                boolean tomcatAuthorization = protocol.getTomcatAuthorization();
                if (tomcatAuthorization || !protocol.getTomcatAuthentication()) {
                    // Implies tomcatAuthentication == false
                    requestHeaderMessage.getBytes(request.getRemoteUser());
                    request.setRemoteUserNeedsAuthorization(tomcatAuthorization);
                } else {
                    // Ignore user information from reverse proxy
                    requestHeaderMessage.getBytes(tmpMB);
                }
                break;
            case Constants.SC_A_AUTH_TYPE:
                if (protocol.getTomcatAuthentication()) {
                    // ignore server
                    requestHeaderMessage.getBytes(tmpMB);
                } else {
                    requestHeaderMessage.getBytes(request.getAuthType());
                }
                break;
            case Constants.SC_A_QUERY_STRING:
                requestHeaderMessage.getBytes(request.queryString());
                break;
            case Constants.SC_A_JVM_ROUTE:
                requestHeaderMessage.getBytes(tmpMB);
                // nothing
                break;
            case Constants.SC_A_SSL_CERT:
                // SSL certificate extraction is lazy, moved to JkCoyoteHandler
                requestHeaderMessage.getBytes(certificates);
                break;
            case Constants.SC_A_SSL_CIPHER:
                requestHeaderMessage.getBytes(tmpMB);
                request.setAttribute(SSLSupport.CIPHER_SUITE_KEY, tmpMB.toString());
                break;
            case Constants.SC_A_SSL_SESSION:
                requestHeaderMessage.getBytes(tmpMB);
                request.setAttribute(SSLSupport.SESSION_ID_KEY, tmpMB.toString());
                break;
            case Constants.SC_A_SSL_KEY_SIZE:
                request.setAttribute(SSLSupport.KEY_SIZE_KEY, Integer.valueOf(requestHeaderMessage.getInt()));
                break;
            case Constants.SC_A_STORED_METHOD:
                requestHeaderMessage.getBytes(request.method());
                break;
            case Constants.SC_A_SECRET:
                requestHeaderMessage.getBytes(tmpMB);
                if (requiredSecret != null) {
                    secret = true;
                    if (!tmpMB.equals(requiredSecret)) {
                        response.setStatus(403);
                        setErrorState(ErrorState.CLOSE_CLEAN, null);
                    }
                }
                break;
            default:
                // Ignore unknown attribute for backward compatibility
                break;
        }
    }
    // Check if secret was submitted if required
    if ((requiredSecret != null) && !secret) {
        response.setStatus(403);
        setErrorState(ErrorState.CLOSE_CLEAN, null);
    }
    // Check for a full URI (including protocol://host:port/)
    ByteChunk uriBC = request.requestURI().getByteChunk();
    if (uriBC.startsWithIgnoreCase("http", 0)) {
        int pos = uriBC.indexOf("://", 0, 3, 4);
        int uriBCStart = uriBC.getStart();
        int slashPos = -1;
        if (pos != -1) {
            byte[] uriB = uriBC.getBytes();
            slashPos = uriBC.indexOf('/', pos + 3);
            if (slashPos == -1) {
                slashPos = uriBC.getLength();
                // Set URI as "/"
                request.requestURI().setBytes(uriB, uriBCStart + pos + 1, 1);
            } else {
                request.requestURI().setBytes(uriB, uriBCStart + slashPos, uriBC.getLength() - slashPos);
            }
            MessageBytes hostMB = headers.setValue("host");
            hostMB.setBytes(uriB, uriBCStart + pos + 3, slashPos - pos - 3);
        }
    }
    MessageBytes valueMB = request.getMimeHeaders().getValue("host");
    parseHost(valueMB);
    if (getErrorState().isError()) {
        getAdapter().log(request, response, 0);
    }
}
Also used : MimeHeaders(org.apache.tomcat.util.http.MimeHeaders) ByteChunk(org.apache.tomcat.util.buf.ByteChunk) MessageBytes(org.apache.tomcat.util.buf.MessageBytes)

Example 12 with MimeHeaders

use of org.apache.tomcat.util.http.MimeHeaders in project tomcat by apache.

the class Http11Processor method prepareRequest.

/**
     * After reading the request headers, we have to setup the request filters.
     */
private void prepareRequest() {
    http11 = true;
    http09 = false;
    contentDelimitation = false;
    sendfileData = null;
    if (protocol.isSSLEnabled()) {
        request.scheme().setString("https");
    }
    MessageBytes protocolMB = request.protocol();
    if (protocolMB.equals(Constants.HTTP_11)) {
        http11 = true;
        protocolMB.setString(Constants.HTTP_11);
    } else if (protocolMB.equals(Constants.HTTP_10)) {
        http11 = false;
        keepAlive = false;
        protocolMB.setString(Constants.HTTP_10);
    } else if (protocolMB.equals("")) {
        // HTTP/0.9
        http09 = true;
        http11 = false;
        keepAlive = false;
    } else {
        // Unsupported protocol
        http11 = false;
        // Send 505; Unsupported HTTP version
        response.setStatus(505);
        setErrorState(ErrorState.CLOSE_CLEAN, null);
        if (log.isDebugEnabled()) {
            log.debug(sm.getString("http11processor.request.prepare") + " Unsupported HTTP version \"" + protocolMB + "\"");
        }
    }
    MimeHeaders headers = request.getMimeHeaders();
    // Check connection header
    MessageBytes connectionValueMB = headers.getValue(Constants.CONNECTION);
    if (connectionValueMB != null) {
        ByteChunk connectionValueBC = connectionValueMB.getByteChunk();
        if (findBytes(connectionValueBC, Constants.CLOSE_BYTES) != -1) {
            keepAlive = false;
        } else if (findBytes(connectionValueBC, Constants.KEEPALIVE_BYTES) != -1) {
            keepAlive = true;
        }
    }
    if (http11) {
        MessageBytes expectMB = headers.getValue("expect");
        if (expectMB != null) {
            if (expectMB.indexOfIgnoreCase("100-continue", 0) != -1) {
                inputBuffer.setSwallowInput(false);
                request.setExpectation(true);
            } else {
                response.setStatus(HttpServletResponse.SC_EXPECTATION_FAILED);
                setErrorState(ErrorState.CLOSE_CLEAN, null);
            }
        }
    }
    // Check user-agent header
    Pattern restrictedUserAgents = protocol.getRestrictedUserAgentsPattern();
    if (restrictedUserAgents != null && (http11 || keepAlive)) {
        MessageBytes userAgentValueMB = headers.getValue("user-agent");
        // and keepAlive flags accordingly
        if (userAgentValueMB != null) {
            String userAgentValue = userAgentValueMB.toString();
            if (restrictedUserAgents.matcher(userAgentValue).matches()) {
                http11 = false;
                keepAlive = false;
            }
        }
    }
    // Check for a full URI (including protocol://host:port/)
    ByteChunk uriBC = request.requestURI().getByteChunk();
    if (uriBC.startsWithIgnoreCase("http", 0)) {
        int pos = uriBC.indexOf("://", 0, 3, 4);
        int uriBCStart = uriBC.getStart();
        int slashPos = -1;
        if (pos != -1) {
            byte[] uriB = uriBC.getBytes();
            slashPos = uriBC.indexOf('/', pos + 3);
            if (slashPos == -1) {
                slashPos = uriBC.getLength();
                // Set URI as "/"
                request.requestURI().setBytes(uriB, uriBCStart + pos + 1, 1);
            } else {
                request.requestURI().setBytes(uriB, uriBCStart + slashPos, uriBC.getLength() - slashPos);
            }
            MessageBytes hostMB = headers.setValue("host");
            hostMB.setBytes(uriB, uriBCStart + pos + 3, slashPos - pos - 3);
        }
    }
    // Input filter setup
    InputFilter[] inputFilters = inputBuffer.getFilters();
    // Parse transfer-encoding header
    if (http11) {
        MessageBytes transferEncodingValueMB = headers.getValue("transfer-encoding");
        if (transferEncodingValueMB != null) {
            String transferEncodingValue = transferEncodingValueMB.toString();
            // Parse the comma separated list. "identity" codings are ignored
            int startPos = 0;
            int commaPos = transferEncodingValue.indexOf(',');
            String encodingName = null;
            while (commaPos != -1) {
                encodingName = transferEncodingValue.substring(startPos, commaPos);
                addInputFilter(inputFilters, encodingName);
                startPos = commaPos + 1;
                commaPos = transferEncodingValue.indexOf(',', startPos);
            }
            encodingName = transferEncodingValue.substring(startPos);
            addInputFilter(inputFilters, encodingName);
        }
    }
    // Parse content-length header
    long contentLength = request.getContentLengthLong();
    if (contentLength >= 0) {
        if (contentDelimitation) {
            // contentDelimitation being true at this point indicates that
            // chunked encoding is being used but chunked encoding should
            // not be used with a content length. RFC 2616, section 4.4,
            // bullet 3 states Content-Length must be ignored in this case -
            // so remove it.
            headers.removeHeader("content-length");
            request.setContentLength(-1);
        } else {
            inputBuffer.addActiveFilter(inputFilters[Constants.IDENTITY_FILTER]);
            contentDelimitation = true;
        }
    }
    MessageBytes valueMB = headers.getValue("host");
    // Check host header
    if (http11 && (valueMB == null)) {
        // 400 - Bad request
        response.setStatus(400);
        setErrorState(ErrorState.CLOSE_CLEAN, null);
        if (log.isDebugEnabled()) {
            log.debug(sm.getString("http11processor.request.prepare") + " host header missing");
        }
    }
    parseHost(valueMB);
    if (!contentDelimitation) {
        // If there's no content length
        // (broken HTTP/1.0 or HTTP/1.1), assume
        // the client is not broken and didn't send a body
        inputBuffer.addActiveFilter(inputFilters[Constants.VOID_FILTER]);
        contentDelimitation = true;
    }
    if (getErrorState().isError()) {
        getAdapter().log(request, response, 0);
    }
}
Also used : MimeHeaders(org.apache.tomcat.util.http.MimeHeaders) Pattern(java.util.regex.Pattern) VoidInputFilter(org.apache.coyote.http11.filters.VoidInputFilter) BufferedInputFilter(org.apache.coyote.http11.filters.BufferedInputFilter) IdentityInputFilter(org.apache.coyote.http11.filters.IdentityInputFilter) ChunkedInputFilter(org.apache.coyote.http11.filters.ChunkedInputFilter) SavedRequestInputFilter(org.apache.coyote.http11.filters.SavedRequestInputFilter) ByteChunk(org.apache.tomcat.util.buf.ByteChunk) MessageBytes(org.apache.tomcat.util.buf.MessageBytes)

Example 13 with MimeHeaders

use of org.apache.tomcat.util.http.MimeHeaders in project tomcat by apache.

the class Http11Processor method prepareResponse.

/**
     * When committing the response, we have to validate the set of headers, as
     * well as setup the response filters.
     */
@Override
protected final void prepareResponse() throws IOException {
    boolean entityBody = true;
    contentDelimitation = false;
    OutputFilter[] outputFilters = outputBuffer.getFilters();
    if (http09 == true) {
        // HTTP/0.9
        outputBuffer.addActiveFilter(outputFilters[Constants.IDENTITY_FILTER]);
        outputBuffer.commit();
        return;
    }
    int statusCode = response.getStatus();
    if (statusCode < 200 || statusCode == 204 || statusCode == 205 || statusCode == 304) {
        // No entity body
        outputBuffer.addActiveFilter(outputFilters[Constants.VOID_FILTER]);
        entityBody = false;
        contentDelimitation = true;
    }
    MessageBytes methodMB = request.method();
    if (methodMB.equals("HEAD")) {
        // No entity body
        outputBuffer.addActiveFilter(outputFilters[Constants.VOID_FILTER]);
        contentDelimitation = true;
    }
    // Sendfile support
    boolean sendingWithSendfile = false;
    if (protocol.getUseSendfile()) {
        sendingWithSendfile = prepareSendfile(outputFilters);
    }
    // Check for compression
    boolean isCompressable = false;
    boolean useCompression = false;
    if (entityBody && (protocol.getCompressionLevel() > 0) && !sendingWithSendfile) {
        isCompressable = isCompressable();
        if (isCompressable) {
            useCompression = useCompression();
        }
        // Change content-length to -1 to force chunking
        if (useCompression) {
            response.setContentLength(-1);
        }
    }
    MimeHeaders headers = response.getMimeHeaders();
    if (!entityBody) {
        response.setContentLength(-1);
    }
    // A SC_NO_CONTENT response may include entity headers
    if (entityBody || statusCode == HttpServletResponse.SC_NO_CONTENT) {
        String contentType = response.getContentType();
        if (contentType != null) {
            headers.setValue("Content-Type").setString(contentType);
        }
        String contentLanguage = response.getContentLanguage();
        if (contentLanguage != null) {
            headers.setValue("Content-Language").setString(contentLanguage);
        }
    }
    long contentLength = response.getContentLengthLong();
    boolean connectionClosePresent = false;
    if (contentLength != -1) {
        headers.setValue("Content-Length").setLong(contentLength);
        outputBuffer.addActiveFilter(outputFilters[Constants.IDENTITY_FILTER]);
        contentDelimitation = true;
    } else {
        // If the response code supports an entity body and we're on
        // HTTP 1.1 then we chunk unless we have a Connection: close header
        connectionClosePresent = isConnectionClose(headers);
        if (entityBody && http11 && !connectionClosePresent) {
            outputBuffer.addActiveFilter(outputFilters[Constants.CHUNKED_FILTER]);
            contentDelimitation = true;
            headers.addValue(Constants.TRANSFERENCODING).setString(Constants.CHUNKED);
        } else {
            outputBuffer.addActiveFilter(outputFilters[Constants.IDENTITY_FILTER]);
        }
    }
    if (useCompression) {
        outputBuffer.addActiveFilter(outputFilters[Constants.GZIP_FILTER]);
        headers.setValue("Content-Encoding").setString("gzip");
    }
    // If it might be compressed, set the Vary header
    if (isCompressable) {
        // Make Proxies happy via Vary (from mod_deflate)
        MessageBytes vary = headers.getValue("Vary");
        if (vary == null) {
            // Add a new Vary header
            headers.setValue("Vary").setString("Accept-Encoding");
        } else if (vary.equals("*")) {
        // No action required
        } else {
            // Merge into current header
            headers.setValue("Vary").setString(vary.getString() + ",Accept-Encoding");
        }
    }
    // Caching Filter)
    if (headers.getValue("Date") == null) {
        headers.addValue("Date").setString(FastHttpDateFormat.getCurrentDate());
    }
    if ((entityBody) && (!contentDelimitation)) {
        // Mark as close the connection after the request, and add the
        // connection: close header
        keepAlive = false;
    }
    // This may disabled keep-alive to check before working out the
    // Connection header.
    checkExpectationAndResponseStatus();
    // Connection: close header.
    if (keepAlive && statusDropsConnection(statusCode)) {
        keepAlive = false;
    }
    if (!keepAlive) {
        // Avoid adding the close header twice
        if (!connectionClosePresent) {
            headers.addValue(Constants.CONNECTION).setString(Constants.CLOSE);
        }
    } else if (!http11 && !getErrorState().isError()) {
        headers.addValue(Constants.CONNECTION).setString(Constants.KEEPALIVE);
    }
    // Add server header
    String server = protocol.getServer();
    if (server == null) {
        if (protocol.getServerRemoveAppProvidedValues()) {
            headers.removeHeader("server");
        }
    } else {
        // server always overrides anything the app might set
        headers.setValue("Server").setString(server);
    }
    // Build the response header
    try {
        outputBuffer.sendStatus();
        int size = headers.size();
        for (int i = 0; i < size; i++) {
            outputBuffer.sendHeader(headers.getName(i), headers.getValue(i));
        }
        outputBuffer.endHeaders();
    } catch (Throwable t) {
        ExceptionUtils.handleThrowable(t);
        // If something goes wrong, reset the header buffer so the error
        // response can be written instead.
        outputBuffer.resetHeaderBuffer();
        throw t;
    }
    outputBuffer.commit();
}
Also used : ChunkedOutputFilter(org.apache.coyote.http11.filters.ChunkedOutputFilter) IdentityOutputFilter(org.apache.coyote.http11.filters.IdentityOutputFilter) GzipOutputFilter(org.apache.coyote.http11.filters.GzipOutputFilter) VoidOutputFilter(org.apache.coyote.http11.filters.VoidOutputFilter) MimeHeaders(org.apache.tomcat.util.http.MimeHeaders) MessageBytes(org.apache.tomcat.util.buf.MessageBytes)

Example 14 with MimeHeaders

use of org.apache.tomcat.util.http.MimeHeaders in project tomcat by apache.

the class Http2UpgradeHandler method prepareHeaders.

protected void prepareHeaders(Response coyoteResponse) {
    MimeHeaders headers = coyoteResponse.getMimeHeaders();
    int statusCode = coyoteResponse.getStatus();
    // Add the pseudo header for status
    headers.addValue(":status").setString(Integer.toString(statusCode));
    // Check to see if a response body is present
    if (!(statusCode < 200 || statusCode == 205 || statusCode == 304)) {
        String contentType = coyoteResponse.getContentType();
        if (contentType != null) {
            headers.setValue("content-type").setString(contentType);
        }
        String contentLanguage = coyoteResponse.getContentLanguage();
        if (contentLanguage != null) {
            headers.setValue("content-language").setString(contentLanguage);
        }
    }
    // Add date header unless the application has already set one
    if (headers.getValue("date") == null) {
        headers.addValue("date").setString(FastHttpDateFormat.getCurrentDate());
    }
}
Also used : MimeHeaders(org.apache.tomcat.util.http.MimeHeaders)

Example 15 with MimeHeaders

use of org.apache.tomcat.util.http.MimeHeaders in project tomcat by apache.

the class ChunkedInputFilter method parseHeader.

private boolean parseHeader() throws IOException {
    MimeHeaders headers = request.getMimeHeaders();
    byte chr = 0;
    // Read new bytes if needed
    if (readChunk == null || readChunk.position() >= readChunk.limit()) {
        if (readBytes() < 0) {
            throwEOFException(sm.getString("chunkedInputFilter.eosTrailer"));
        }
    }
    // readBytes() above will set readChunk unless it returns a value < 0
    chr = readChunk.get(readChunk.position());
    // CRLF terminates the request
    if (chr == Constants.CR || chr == Constants.LF) {
        parseCRLF(false);
        return false;
    }
    // Mark the current buffer position
    int startPos = trailingHeaders.getEnd();
    //
    // Reading the header name
    // Header name is always US-ASCII
    //
    boolean colon = false;
    while (!colon) {
        // Read new bytes if needed
        if (readChunk == null || readChunk.position() >= readChunk.limit()) {
            if (readBytes() < 0) {
                throwEOFException(sm.getString("chunkedInputFilter.eosTrailer"));
            }
        }
        // readBytes() above will set readChunk unless it returns a value < 0
        chr = readChunk.get(readChunk.position());
        if ((chr >= Constants.A) && (chr <= Constants.Z)) {
            chr = (byte) (chr - Constants.LC_OFFSET);
        }
        if (chr == Constants.COLON) {
            colon = true;
        } else {
            trailingHeaders.append(chr);
        }
        readChunk.position(readChunk.position() + 1);
    }
    int colonPos = trailingHeaders.getEnd();
    //
    // Reading the header value (which can be spanned over multiple lines)
    //
    boolean eol = false;
    boolean validLine = true;
    int lastSignificantChar = 0;
    while (validLine) {
        boolean space = true;
        // Skipping spaces
        while (space) {
            // Read new bytes if needed
            if (readChunk == null || readChunk.position() >= readChunk.limit()) {
                if (readBytes() < 0) {
                    throwEOFException(sm.getString("chunkedInputFilter.eosTrailer"));
                }
            }
            chr = readChunk.get(readChunk.position());
            if ((chr == Constants.SP) || (chr == Constants.HT)) {
                readChunk.position(readChunk.position() + 1);
                // If we swallow whitespace, make sure it counts towards the
                // limit placed on trailing header size
                int newlimit = trailingHeaders.getLimit() - 1;
                if (trailingHeaders.getEnd() > newlimit) {
                    throwIOException(sm.getString("chunkedInputFilter.maxTrailer"));
                }
                trailingHeaders.setLimit(newlimit);
            } else {
                space = false;
            }
        }
        // Reading bytes until the end of the line
        while (!eol) {
            // Read new bytes if needed
            if (readChunk == null || readChunk.position() >= readChunk.limit()) {
                if (readBytes() < 0) {
                    throwEOFException(sm.getString("chunkedInputFilter.eosTrailer"));
                }
            }
            chr = readChunk.get(readChunk.position());
            if (chr == Constants.CR || chr == Constants.LF) {
                parseCRLF(true);
                eol = true;
            } else if (chr == Constants.SP) {
                trailingHeaders.append(chr);
            } else {
                trailingHeaders.append(chr);
                lastSignificantChar = trailingHeaders.getEnd();
            }
            if (!eol) {
                readChunk.position(readChunk.position() + 1);
            }
        }
        // Read new bytes if needed
        if (readChunk == null || readChunk.position() >= readChunk.limit()) {
            if (readBytes() < 0) {
                throwEOFException(sm.getString("chunkedInputFilter.eosTrailer"));
            }
        }
        chr = readChunk.get(readChunk.position());
        if ((chr != Constants.SP) && (chr != Constants.HT)) {
            validLine = false;
        } else {
            eol = false;
            // Copying one extra space in the buffer (since there must
            // be at least one space inserted between the lines)
            trailingHeaders.append(chr);
        }
    }
    String headerName = new String(trailingHeaders.getBytes(), startPos, colonPos - startPos, StandardCharsets.ISO_8859_1);
    if (allowedTrailerHeaders.contains(headerName.toLowerCase(Locale.ENGLISH))) {
        MessageBytes headerValue = headers.addValue(headerName);
        // Set the header value
        headerValue.setBytes(trailingHeaders.getBytes(), colonPos, lastSignificantChar - colonPos);
    }
    return true;
}
Also used : MimeHeaders(org.apache.tomcat.util.http.MimeHeaders) MessageBytes(org.apache.tomcat.util.buf.MessageBytes)

Aggregations

MimeHeaders (org.apache.tomcat.util.http.MimeHeaders)18 MessageBytes (org.apache.tomcat.util.buf.MessageBytes)6 ByteBuffer (java.nio.ByteBuffer)3 ByteChunk (org.apache.tomcat.util.buf.ByteChunk)3 Test (org.junit.Test)2 IOException (java.io.IOException)1 InputStream (java.io.InputStream)1 ArrayList (java.util.ArrayList)1 LinkedList (java.util.LinkedList)1 Locale (java.util.Locale)1 Pattern (java.util.regex.Pattern)1 Cookie (javax.servlet.http.Cookie)1 BufferedInputFilter (org.apache.coyote.http11.filters.BufferedInputFilter)1 ChunkedInputFilter (org.apache.coyote.http11.filters.ChunkedInputFilter)1 ChunkedOutputFilter (org.apache.coyote.http11.filters.ChunkedOutputFilter)1 GzipOutputFilter (org.apache.coyote.http11.filters.GzipOutputFilter)1 IdentityInputFilter (org.apache.coyote.http11.filters.IdentityInputFilter)1 IdentityOutputFilter (org.apache.coyote.http11.filters.IdentityOutputFilter)1 SavedRequestInputFilter (org.apache.coyote.http11.filters.SavedRequestInputFilter)1 VoidInputFilter (org.apache.coyote.http11.filters.VoidInputFilter)1