Search in sources :

Example 26 with MessageBytes

use of org.apache.tomcat.util.buf.MessageBytes 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)

Example 27 with MessageBytes

use of org.apache.tomcat.util.buf.MessageBytes in project tomcat by apache.

the class TestCoyoteAdapter method doTestNormalize.

private void doTestNormalize(String input, String expected) {
    MessageBytes mb = MessageBytes.newInstance();
    byte[] b = input.getBytes(StandardCharsets.UTF_8);
    mb.setBytes(b, 0, b.length);
    boolean result = CoyoteAdapter.normalize(mb);
    mb.toString();
    if (expected == null) {
        Assert.assertFalse(result);
    } else {
        Assert.assertTrue(result);
        Assert.assertEquals(expected, mb.toString());
    }
}
Also used : MessageBytes(org.apache.tomcat.util.buf.MessageBytes)

Example 28 with MessageBytes

use of org.apache.tomcat.util.buf.MessageBytes in project tomcat by apache.

the class TestCookies method test.

private void test(boolean useRfc6265, String header, Cookie... expected) {
    MimeHeaders mimeHeaders = new MimeHeaders();
    ServerCookies serverCookies = new ServerCookies(4);
    CookieProcessor cookieProcessor;
    if (useRfc6265) {
        cookieProcessor = new Rfc6265CookieProcessor();
    } else {
        cookieProcessor = new LegacyCookieProcessor();
    }
    MessageBytes cookieHeaderValue = mimeHeaders.addValue("Cookie");
    byte[] bytes = header.getBytes(StandardCharsets.UTF_8);
    cookieHeaderValue.setBytes(bytes, 0, bytes.length);
    cookieProcessor.parseCookieHeader(mimeHeaders, serverCookies);
    Assert.assertEquals(expected.length, serverCookies.getCookieCount());
    for (int i = 0; i < expected.length; i++) {
        Cookie cookie = expected[i];
        ServerCookie actual = serverCookies.getCookie(i);
        Assert.assertEquals(cookie.getVersion(), actual.getVersion());
        Assert.assertEquals(cookie.getName(), actual.getName().toString());
        actual.getValue().getByteChunk().setCharset(StandardCharsets.UTF_8);
        Assert.assertEquals(cookie.getValue(), org.apache.tomcat.util.http.parser.Cookie.unescapeCookieValueRfc2109(actual.getValue().toString()));
        if (cookie.getVersion() == 1) {
            Assert.assertEquals(cookie.getDomain(), actual.getDomain().toString());
            Assert.assertEquals(cookie.getPath(), actual.getPath().toString());
        }
    }
}
Also used : Cookie(javax.servlet.http.Cookie) MessageBytes(org.apache.tomcat.util.buf.MessageBytes)

Example 29 with MessageBytes

use of org.apache.tomcat.util.buf.MessageBytes in project tomcat by apache.

the class CoyoteAdapter method postParseRequest.

// ------------------------------------------------------ Protected Methods
/**
     * Perform the necessary processing after the HTTP headers have been parsed
     * to enable the request/response pair to be passed to the start of the
     * container pipeline for processing.
     *
     * @param req      The coyote request object
     * @param request  The catalina request object
     * @param res      The coyote response object
     * @param response The catalina response object
     *
     * @return <code>true</code> if the request should be passed on to the start
     *         of the container pipeline, otherwise <code>false</code>
     *
     * @throws IOException If there is insufficient space in a buffer while
     *                     processing headers
     * @throws ServletException If the supported methods of the target servlet
     *                          cannot be determined
     */
protected boolean postParseRequest(org.apache.coyote.Request req, Request request, org.apache.coyote.Response res, Response response) throws IOException, ServletException {
    // processor hasn't set it, use the settings from the connector
    if (req.scheme().isNull()) {
        // Use connector scheme and secure configuration, (defaults to
        // "http" and false respectively)
        req.scheme().setString(connector.getScheme());
        request.setSecure(connector.getSecure());
    } else {
        // Use processor specified scheme to determine secure state
        request.setSecure(req.scheme().equals("https"));
    }
    // At this point the Host header has been processed.
    // Override if the proxyPort/proxyHost are set
    String proxyName = connector.getProxyName();
    int proxyPort = connector.getProxyPort();
    if (proxyPort != 0) {
        req.setServerPort(proxyPort);
    } else if (req.getServerPort() == -1) {
        // Not explicitly set. Use default ports based on the scheme
        if (req.scheme().equals("https")) {
            req.setServerPort(443);
        } else {
            req.setServerPort(80);
        }
    }
    if (proxyName != null) {
        req.serverName().setString(proxyName);
    }
    MessageBytes undecodedURI = req.requestURI();
    // Check for ping OPTIONS * request
    if (undecodedURI.equals("*")) {
        if (req.method().equalsIgnoreCase("OPTIONS")) {
            StringBuilder allow = new StringBuilder();
            allow.append("GET, HEAD, POST, PUT, DELETE");
            // Trace if allowed
            if (connector.getAllowTrace()) {
                allow.append(", TRACE");
            }
            // Always allow options
            allow.append(", OPTIONS");
            res.setHeader("Allow", allow.toString());
        } else {
            res.setStatus(404);
            res.setMessage("Not found");
        }
        connector.getService().getContainer().logAccess(request, response, 0, true);
        return false;
    }
    MessageBytes decodedURI = req.decodedURI();
    if (undecodedURI.getType() == MessageBytes.T_BYTES) {
        // Copy the raw URI to the decodedURI
        decodedURI.duplicate(undecodedURI);
        // Parse the path parameters. This will:
        //   - strip out the path parameters
        //   - convert the decodedURI to bytes
        parsePathParameters(req, request);
        // %xx decoding of the URL
        try {
            req.getURLDecoder().convert(decodedURI, false);
        } catch (IOException ioe) {
            res.setStatus(400);
            res.setMessage("Invalid URI: " + ioe.getMessage());
            connector.getService().getContainer().logAccess(request, response, 0, true);
            return false;
        }
        // Normalization
        if (!normalize(req.decodedURI())) {
            res.setStatus(400);
            res.setMessage("Invalid URI");
            connector.getService().getContainer().logAccess(request, response, 0, true);
            return false;
        }
        // Character decoding
        convertURI(decodedURI, request);
        // Check that the URI is still normalized
        if (!checkNormalize(req.decodedURI())) {
            res.setStatus(400);
            res.setMessage("Invalid URI character encoding");
            connector.getService().getContainer().logAccess(request, response, 0, true);
            return false;
        }
    } else {
        /* The URI is chars or String, and has been sent using an in-memory
             * protocol handler. The following assumptions are made:
             * - req.requestURI() has been set to the 'original' non-decoded,
             *   non-normalized URI
             * - req.decodedURI() has been set to the decoded, normalized form
             *   of req.requestURI()
             */
        decodedURI.toChars();
        // Remove all path parameters; any needed path parameter should be set
        // using the request object rather than passing it in the URL
        CharChunk uriCC = decodedURI.getCharChunk();
        int semicolon = uriCC.indexOf(';');
        if (semicolon > 0) {
            decodedURI.setChars(uriCC.getBuffer(), uriCC.getStart(), semicolon);
        }
    }
    // Request mapping.
    MessageBytes serverName;
    if (connector.getUseIPVHosts()) {
        serverName = req.localName();
        if (serverName.isNull()) {
            // well, they did ask for it
            res.action(ActionCode.REQ_LOCAL_NAME_ATTRIBUTE, null);
        }
    } else {
        serverName = req.serverName();
    }
    // Version for the second mapping loop and
    // Context that we expect to get for that version
    String version = null;
    Context versionContext = null;
    boolean mapRequired = true;
    while (mapRequired) {
        // This will map the the latest version by default
        connector.getService().getMapper().map(serverName, decodedURI, version, request.getMappingData());
        // has been deployed
        if (request.getContext() == null) {
            res.setStatus(404);
            res.setMessage("Not found");
            // No context, so use host
            Host host = request.getHost();
            // Make sure there is a host (might not be during shutdown)
            if (host != null) {
                host.logAccess(request, response, 0, true);
            }
            return false;
        }
        // Now we have the context, we can parse the session ID from the URL
        // (if any). Need to do this before we redirect in case we need to
        // include the session id in the redirect
        String sessionID;
        if (request.getServletContext().getEffectiveSessionTrackingModes().contains(SessionTrackingMode.URL)) {
            // Get the session ID if there was one
            sessionID = request.getPathParameter(SessionConfig.getSessionUriParamName(request.getContext()));
            if (sessionID != null) {
                request.setRequestedSessionId(sessionID);
                request.setRequestedSessionURL(true);
            }
        }
        // Look for session ID in cookies and SSL session
        parseSessionCookiesId(request);
        parseSessionSslId(request);
        sessionID = request.getRequestedSessionId();
        mapRequired = false;
        if (version != null && request.getContext() == versionContext) {
        // We got the version that we asked for. That is it.
        } else {
            version = null;
            versionContext = null;
            Context[] contexts = request.getMappingData().contexts;
            // No session ID means no possibility of remap
            if (contexts != null && sessionID != null) {
                // Find the context associated with the session
                for (int i = (contexts.length); i > 0; i--) {
                    Context ctxt = contexts[i - 1];
                    if (ctxt.getManager().findSession(sessionID) != null) {
                        // already been mapped?
                        if (!ctxt.equals(request.getMappingData().context)) {
                            // Set version so second time through mapping
                            // the correct context is found
                            version = ctxt.getWebappVersion();
                            versionContext = ctxt;
                            // Reset mapping
                            request.getMappingData().recycle();
                            mapRequired = true;
                            // Recycle cookies and session info in case the
                            // correct context is configured with different
                            // settings
                            request.recycleSessionInfo();
                            request.recycleCookieInfo(true);
                        }
                        break;
                    }
                }
            }
        }
        if (!mapRequired && request.getContext().getPaused()) {
            // point.
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
            // Should never happen
            }
            // Reset mapping
            request.getMappingData().recycle();
            mapRequired = true;
        }
    }
    // Possible redirect
    MessageBytes redirectPathMB = request.getMappingData().redirectPath;
    if (!redirectPathMB.isNull()) {
        String redirectPath = URLEncoder.DEFAULT.encode(redirectPathMB.toString(), "UTF-8");
        String query = request.getQueryString();
        if (request.isRequestedSessionIdFromURL()) {
            // This is not optimal, but as this is not very common, it
            // shouldn't matter
            redirectPath = redirectPath + ";" + SessionConfig.getSessionUriParamName(request.getContext()) + "=" + request.getRequestedSessionId();
        }
        if (query != null) {
            // This is not optimal, but as this is not very common, it
            // shouldn't matter
            redirectPath = redirectPath + "?" + query;
        }
        response.sendRedirect(redirectPath);
        request.getContext().logAccess(request, response, 0, true);
        return false;
    }
    // Filter trace method
    if (!connector.getAllowTrace() && req.method().equalsIgnoreCase("TRACE")) {
        Wrapper wrapper = request.getWrapper();
        String header = null;
        if (wrapper != null) {
            String[] methods = wrapper.getServletMethods();
            if (methods != null) {
                for (int i = 0; i < methods.length; i++) {
                    if ("TRACE".equals(methods[i])) {
                        continue;
                    }
                    if (header == null) {
                        header = methods[i];
                    } else {
                        header += ", " + methods[i];
                    }
                }
            }
        }
        res.setStatus(405);
        res.addHeader("Allow", header);
        res.setMessage("TRACE method is not allowed");
        request.getContext().logAccess(request, response, 0, true);
        return false;
    }
    doConnectorAuthenticationAuthorization(req, request);
    return true;
}
Also used : Context(org.apache.catalina.Context) Wrapper(org.apache.catalina.Wrapper) MessageBytes(org.apache.tomcat.util.buf.MessageBytes) Host(org.apache.catalina.Host) IOException(java.io.IOException) CharChunk(org.apache.tomcat.util.buf.CharChunk)

Example 30 with MessageBytes

use of org.apache.tomcat.util.buf.MessageBytes in project tomcat by apache.

the class BasicAuthenticator method doAuthenticate.

// --------------------------------------------------------- Public Methods
@Override
protected boolean doAuthenticate(Request request, HttpServletResponse response) throws IOException {
    if (checkForCachedAuthentication(request, response, true)) {
        return true;
    }
    // Validate any credentials already included with this request
    MessageBytes authorization = request.getCoyoteRequest().getMimeHeaders().getValue("authorization");
    if (authorization != null) {
        authorization.toBytes();
        ByteChunk authorizationBC = authorization.getByteChunk();
        BasicCredentials credentials = null;
        try {
            credentials = new BasicCredentials(authorizationBC);
            String username = credentials.getUsername();
            String password = credentials.getPassword();
            Principal principal = context.getRealm().authenticate(username, password);
            if (principal != null) {
                register(request, response, principal, HttpServletRequest.BASIC_AUTH, username, password);
                return true;
            }
        } catch (IllegalArgumentException iae) {
            if (log.isDebugEnabled()) {
                log.debug("Invalid Authorization" + iae.getMessage());
            }
        }
    }
    // the request could not be authenticated, so reissue the challenge
    StringBuilder value = new StringBuilder(16);
    value.append("Basic realm=\"");
    value.append(getRealmName(context));
    value.append('\"');
    response.setHeader(AUTH_HEADER_NAME, value.toString());
    response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
    return false;
}
Also used : ByteChunk(org.apache.tomcat.util.buf.ByteChunk) MessageBytes(org.apache.tomcat.util.buf.MessageBytes) Principal(java.security.Principal)

Aggregations

MessageBytes (org.apache.tomcat.util.buf.MessageBytes)32 ByteChunk (org.apache.tomcat.util.buf.ByteChunk)7 Context (org.apache.catalina.Context)6 MimeHeaders (org.apache.tomcat.util.http.MimeHeaders)6 Test (org.junit.Test)6 IOException (java.io.IOException)4 Host (org.apache.catalina.Host)4 LoggingBaseTest (org.apache.catalina.startup.LoggingBaseTest)4 Pattern (java.util.regex.Pattern)3 ServletException (javax.servlet.ServletException)3 Cookie (javax.servlet.http.Cookie)3 Wrapper (org.apache.catalina.Wrapper)3 StandardContext (org.apache.catalina.core.StandardContext)3 StandardHost (org.apache.catalina.core.StandardHost)3 CharChunk (org.apache.tomcat.util.buf.CharChunk)3 UnsupportedEncodingException (java.io.UnsupportedEncodingException)2 Principal (java.security.Principal)2 MappingData (org.apache.catalina.mapper.MappingData)2 InputStream (java.io.InputStream)1 InvocationTargetException (java.lang.reflect.InvocationTargetException)1