Esempio n. 1
0
  /**
   * Extract the path parameters from the request. This assumes parameters are of the form
   * /path;name=value;name2=value2/ etc. Currently only really interested in the session ID that
   * will be in this form. Other parameters can safely be ignored.
   *
   * @param req
   * @param request
   */
  protected void parsePathParameters(org.apache.coyote.Request req, Request request) {

    // Process in bytes (this is default format so this is normally a NO-OP
    req.decodedURI().toBytes();

    ByteChunk uriBC = req.decodedURI().getByteChunk();
    int semicolon = uriBC.indexOf(';', 0);

    // What encoding to use? Some platforms, eg z/os, use a default
    // encoding that doesn't give the expected result so be explicit
    String enc = connector.getURIEncoding();
    if (enc == null) {
      enc = "ISO-8859-1";
    }
    Charset charset = null;
    try {
      charset = B2CConverter.getCharset(enc);
    } catch (UnsupportedEncodingException e1) {
      log.warn(sm.getString("coyoteAdapter.parsePathParam", enc));
    }

    if (log.isDebugEnabled()) {
      log.debug(sm.getString("coyoteAdapter.debug", "uriBC", uriBC.toString()));
      log.debug(sm.getString("coyoteAdapter.debug", "semicolon", String.valueOf(semicolon)));
      log.debug(sm.getString("coyoteAdapter.debug", "enc", enc));
    }

    while (semicolon > -1) {
      // Parse path param, and extract it from the decoded request URI
      int start = uriBC.getStart();
      int end = uriBC.getEnd();

      int pathParamStart = semicolon + 1;
      int pathParamEnd =
          ByteChunk.findBytes(
              uriBC.getBuffer(), start + pathParamStart, end, new byte[] {';', '/'});

      String pv = null;

      if (pathParamEnd >= 0) {
        if (charset != null) {
          pv =
              new String(
                  uriBC.getBuffer(),
                  start + pathParamStart,
                  pathParamEnd - pathParamStart,
                  charset);
        }
        // Extract path param from decoded request URI
        byte[] buf = uriBC.getBuffer();
        for (int i = 0; i < end - start - pathParamEnd; i++) {
          buf[start + semicolon + i] = buf[start + i + pathParamEnd];
        }
        uriBC.setBytes(buf, start, end - start - pathParamEnd + semicolon);
      } else {
        if (charset != null) {
          pv =
              new String(
                  uriBC.getBuffer(),
                  start + pathParamStart,
                  (end - start) - pathParamStart,
                  charset);
        }
        uriBC.setEnd(start + semicolon);
      }

      if (log.isDebugEnabled()) {
        log.debug(
            sm.getString("coyoteAdapter.debug", "pathParamStart", String.valueOf(pathParamStart)));
        log.debug(
            sm.getString("coyoteAdapter.debug", "pathParamEnd", String.valueOf(pathParamEnd)));
        log.debug(sm.getString("coyoteAdapter.debug", "pv", pv));
      }

      if (pv != null) {
        int equals = pv.indexOf('=');
        if (equals > -1) {
          String name = pv.substring(0, equals);
          String value = pv.substring(equals + 1);
          request.addPathParameter(name, value);
          if (log.isDebugEnabled()) {
            log.debug(sm.getString("coyoteAdapter.debug", "equals", String.valueOf(equals)));
            log.debug(sm.getString("coyoteAdapter.debug", "name", name));
            log.debug(sm.getString("coyoteAdapter.debug", "value", value));
          }
        }
      }

      semicolon = uriBC.indexOf(';', semicolon);
    }
  }
Esempio n. 2
0
  /** Parse additional request parameters. */
  protected boolean postParseRequest(
      org.apache.coyote.Request req,
      Request request,
      org.apache.coyote.Response res,
      Response response)
      throws Exception {

    // XXX the processor may have set a correct scheme and port prior to this point,
    // in ajp13 protocols dont make sense to get the port from the connector...
    // otherwise, use connector configuration
    if (!req.scheme().isNull()) {
      // use processor specified scheme to determine secure state
      request.setSecure(req.scheme().equals("https"));
    } else {
      // use connector scheme and secure configuration, (defaults to
      // "http" and false respectively)
      req.scheme().setString(connector.getScheme());
      request.setSecure(connector.getSecure());
    }

    // FIXME: the code below doesnt belongs to here,
    // this is only have sense
    // in Http11, not in ajp13..
    // 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);
    }
    if (proxyName != null) {
      req.serverName().setString(proxyName);
    }

    // Copy the raw URI to the decodedURI
    MessageBytes decodedURI = req.decodedURI();
    decodedURI.duplicate(req.requestURI());

    // Parse the path parameters. This will:
    //   - strip out the path parameters
    //   - convert the decodedURI to bytes
    parsePathParameters(req, request);

    // URI decoding
    // %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;
    }

    // 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();
    }
    if (request.isAsyncStarted()) {
      // TODO SERVLET3 - async
      // reset mapping data, should prolly be done elsewhere
      request.getMappingData().recycle();
    }

    // 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.getMapper().map(serverName, decodedURI, version, request.getMappingData());
      request.setContext((Context) request.getMappingData().context);
      request.setWrapper((Wrapper) request.getMappingData().wrapper);

      // If there is no context at this point, it is likely no ROOT context
      // 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(req, 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;

        Object[] contexts = request.getMappingData().contexts;
        // Single contextVersion means no need to remap
        // 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 = (Context) contexts[i - 1];
            if (ctxt.getManager().findSession(sessionID) != null) {
              // We found a context. Is it the one that has
              // 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;
              }
              break;
            }
          }
        }
      }

      if (!mapRequired && request.getContext().getPaused()) {
        // Found a matching context but it is paused. Mapping data will
        // be wrong since some Wrappers may not be registered at this
        // 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.encode(redirectPathMB.toString());
      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;
  }