Esempio n. 1
0
  /**
   * Set the Locale that is appropriate for this response, including setting the appropriate
   * character encoding.
   *
   * @param locale The new locale
   */
  @Override
  public void setLocale(Locale locale) {

    if (isCommitted()) {
      return;
    }

    // Ignore any call from an included servlet
    if (included) {
      return;
    }

    coyoteResponse.setLocale(locale);

    // Ignore any call made after the getWriter has been invoked.
    // The default should be used
    if (usingWriter) {
      return;
    }

    if (isCharacterEncodingSet) {
      return;
    }

    String charset = getContext().getCharset(locale);
    if (charset != null) {
      coyoteResponse.setCharacterEncoding(charset);
    }
  }
Esempio n. 2
0
  public int doWrite(ByteChunk chunk, Response res) throws IOException {
    if (!res.isCommitted()) {
      // Send the connector a request for commit. The connector should
      // then validate the headers, send them (using sendHeader) and
      // set the filters accordingly.
      res.sendHeaders();
    }

    int len = chunk.getLength();
    byte buf[] = outputMsg.getBuffer();
    // 4 - hardcoded, byte[] marshalling overhead
    int chunkSize = buf.length - outputMsg.getHeaderLength() - 4;
    int off = 0;
    while (len > 0) {
      int thisTime = len;
      if (thisTime > chunkSize) {
        thisTime = chunkSize;
      }
      len -= thisTime;

      outputMsg.reset();
      outputMsg.appendByte(AjpConstants.JK_AJP13_SEND_BODY_CHUNK);
      if (log.isTraceEnabled()) log.trace("doWrite " + off + " " + thisTime + " " + len);
      outputMsg.appendBytes(chunk.getBytes(), chunk.getOffset() + off, thisTime);
      off += thisTime;
      mc.getSource().send(outputMsg, mc);
    }
    return 0;
  }
Esempio n. 3
0
  // -------------------- Jk handler implementation --------------------
  // Jk Handler mehod
  public int invoke(Msg msg, MsgContext ep) throws IOException {
    if (ep.isLogTimeEnabled()) ep.setLong(MsgContext.TIMER_PRE_REQUEST, System.currentTimeMillis());

    Request req = ep.getRequest();
    Response res = req.getResponse();

    if (log.isDebugEnabled())
      log.debug("Invoke " + req + " " + res + " " + req.requestURI().toString());

    res.setNote(epNote, ep);
    ep.setStatus(MsgContext.JK_STATUS_HEAD);
    RequestInfo rp = req.getRequestProcessor();
    rp.setStage(Constants.STAGE_SERVICE);
    try {
      adapter.service(req, res);
    } catch (Exception ex) {
      log.info("Error servicing request " + req, ex);
    }
    if (ep.getStatus() != MsgContext.JK_STATUS_CLOSED) {
      res.finish();
    }

    req.updateCounters();
    req.recycle();
    res.recycle();
    ep.recycle();
    if (ep.getStatus() == MsgContext.JK_STATUS_ERROR) {
      return ERROR;
    }
    ep.setStatus(MsgContext.JK_STATUS_NEW);
    rp.setStage(Constants.STAGE_KEEPALIVE);
    return OK;
  }
Esempio n. 4
0
  /**
   * Set the content type for this Response.
   *
   * @param type The new content type
   */
  @Override
  public void setContentType(String type) {

    if (isCommitted()) {
      return;
    }

    // Ignore any call from an included servlet
    if (included) {
      return;
    }

    if (type == null) {
      coyoteResponse.setContentType(null);
      return;
    }

    String[] m = MEDIA_TYPE_CACHE.parse(type);
    if (m == null) {
      // Invalid - Assume no charset and just pass through whatever
      // the user provided.
      coyoteResponse.setContentTypeNoCharset(type);
      return;
    }

    coyoteResponse.setContentTypeNoCharset(m[0]);

    if (m[1] != null) {
      // Ignore charset if getWriter() has already been called
      if (!usingWriter) {
        coyoteResponse.setCharacterEncoding(m[1]);
        isCharacterEncodingSet = true;
      }
    }
  }
Esempio n. 5
0
  public void appendHead(Response res) throws IOException {
    if (log.isDebugEnabled())
      log.debug("COMMIT sending headers " + res + " " + res.getMimeHeaders());

    C2BConverter c2b = mc.getConverter();

    outputMsg.reset();
    outputMsg.appendByte(AjpConstants.JK_AJP13_SEND_HEADERS);
    outputMsg.appendInt(res.getStatus());

    String message = null;
    if (org.apache.coyote.Constants.USE_CUSTOM_STATUS_MSG_IN_HEADER
        && HttpMessages.isSafeInHttpHeader(res.getMessage())) {
      message = res.getMessage();
    }
    if (message == null) {
      message = HttpMessages.getMessage(res.getStatus());
    }
    if (message == null) {
      // mod_jk + httpd 2.x fails with a null status message - bug 45026
      message = Integer.toString(res.getStatus());
    }
    tempMB.setString(message);
    c2b.convert(tempMB);
    outputMsg.appendBytes(tempMB);

    // XXX add headers

    MimeHeaders headers = res.getMimeHeaders();
    String contentType = res.getContentType();
    if (contentType != null) {
      headers.setValue("Content-Type").setString(contentType);
    }
    String contentLanguage = res.getContentLanguage();
    if (contentLanguage != null) {
      headers.setValue("Content-Language").setString(contentLanguage);
    }
    long contentLength = res.getContentLengthLong();
    if (contentLength >= 0) {
      headers.setValue("Content-Length").setLong(contentLength);
    }
    int numHeaders = headers.size();
    outputMsg.appendInt(numHeaders);
    for (int i = 0; i < numHeaders; i++) {
      MessageBytes hN = headers.getName(i);
      // no header to sc conversion - there's little benefit
      // on this direction
      outputMsg.appendBytes(hN);

      MessageBytes hV = headers.getValue(i);
      outputMsg.appendBytes(hV);
    }
    mc.getSource().send(outputMsg, mc);
  }
Esempio n. 6
0
  @Override
  public void log(org.apache.coyote.Request req, org.apache.coyote.Response res, long time) {

    Request request = (Request) req.getNote(ADAPTER_NOTES);
    Response response = (Response) res.getNote(ADAPTER_NOTES);

    if (request == null) {
      // Create objects
      request = connector.createRequest();
      request.setCoyoteRequest(req);
      response = connector.createResponse();
      response.setCoyoteResponse(res);

      // Link objects
      request.setResponse(response);
      response.setRequest(request);

      // Set as notes
      req.setNote(ADAPTER_NOTES, request);
      res.setNote(ADAPTER_NOTES, response);

      // Set query string encoding
      req.getParameters().setQueryStringEncoding(connector.getURIEncoding());
    }

    try {
      // Log at the lowest level available. logAccess() will be
      // automatically called on parent containers.
      boolean logged = false;
      if (request.mappingData != null) {
        if (request.mappingData.context != null) {
          logged = true;
          ((Context) request.mappingData.context).logAccess(request, response, time, true);
        } else if (request.mappingData.host != null) {
          logged = true;
          ((Host) request.mappingData.host).logAccess(request, response, time, true);
        }
      }
      if (!logged) {
        connector.getService().getContainer().logAccess(request, response, time, true);
      }
    } catch (Throwable t) {
      ExceptionUtils.handleThrowable(t);
      log.warn(sm.getString("coyoteAdapter.accesslogFail"), t);
    } finally {
      request.recycle();
      response.recycle();
    }
  }
Esempio n. 7
0
  /**
   * Set the HTTP status and message to be returned with this response.
   *
   * @param status The new HTTP status
   * @param message The associated text message
   * @deprecated As of Version 2.1 of the Java Servlet API, this method has been deprecated due to
   *     the ambiguous meaning of the message parameter.
   */
  @Override
  @Deprecated
  public void setStatus(int status, String message) {

    if (isCommitted()) {
      return;
    }

    // Ignore any call from an included servlet
    if (included) {
      return;
    }

    coyoteResponse.setStatus(status);
    coyoteResponse.setMessage(message);
  }
Esempio n. 8
0
  @Override
  public void checkRecycled(org.apache.coyote.Request req, org.apache.coyote.Response res) {
    Request request = (Request) req.getNote(ADAPTER_NOTES);
    Response response = (Response) res.getNote(ADAPTER_NOTES);
    String messageKey = null;
    if (request != null && request.getHost() != null) {
      messageKey = "coyoteAdapter.checkRecycled.request";
    } else if (response != null && response.getContentWritten() != 0) {
      messageKey = "coyoteAdapter.checkRecycled.response";
    }
    if (messageKey != null) {
      // Log this request, as it has probably skipped the access log.
      // The log() method will take care of recycling.
      log(req, res, 0L);

      if (connector.getState().isAvailable()) {
        if (log.isInfoEnabled()) {
          log.info(sm.getString(messageKey), new RecycleRequiredException());
        }
      } else {
        // There may be some aborted requests.
        // When connector shuts down, the request and response will not
        // be reused, so there is no issue to warn about here.
        if (log.isDebugEnabled()) {
          log.debug(sm.getString(messageKey), new RecycleRequiredException());
        }
      }
    }
  }
Esempio n. 9
0
  protected void setConverter() throws IOException {

    if (coyoteResponse != null) enc = coyoteResponse.getCharacterEncoding();

    gotEnc = true;
    if (enc == null) enc = DEFAULT_ENCODING;
    conv = encoders.get(enc);
    if (conv == null) {

      if (Globals.IS_SECURITY_ENABLED) {
        try {
          conv =
              AccessController.doPrivileged(
                  new PrivilegedExceptionAction<C2BConverter>() {

                    @Override
                    public C2BConverter run() throws IOException {
                      return new C2BConverter(bb, enc);
                    }
                  });
        } catch (PrivilegedActionException ex) {
          Exception e = ex.getException();
          if (e instanceof IOException) throw (IOException) e;
        }
      } else {
        conv = new C2BConverter(bb, enc);
      }

      encoders.put(enc, conv);
    }
  }
 /**
  * Update the current error state to the new error state if the new error state is more severe
  * than the current error state.
  */
 protected void setErrorState(ErrorState errorState, Throwable t) {
   boolean blockIo = this.errorState.isIoAllowed() && !errorState.isIoAllowed();
   this.errorState = this.errorState.getMostSevere(errorState);
   if (blockIo && !ContainerThreadMarker.isContainerThread() && isAsync()) {
     // The error occurred on a non-container thread during async
     // processing which means not all of the necessary clean-up will
     // have been completed. Dispatch to a container thread to do the
     // clean-up. Need to do it this way to ensure that all the necessary
     // clean-up is performed.
     if (response.getStatus() < 400) {
       response.setStatus(500);
     }
     getLog().info(sm.getString("abstractProcessor.nonContainerThreadError"), t);
     getEndpoint().processSocket(socketWrapper, SocketStatus.CLOSE_NOW, true);
   }
 }
  @Override
  public void action(ActionCode actionCode, Object param) {
    // TODO Auto-generated method stub
    if (actionCode == ActionCode.ACTION_COMMIT) {
      // Commit current response

      if (response.isCommitted()) return;

      // Validate and write response headers
      prepareResponse();
      try {
        outputBuffer.commit();
      } catch (IOException e) {
        // Set error flag
        error = true;
      }
    } else if (actionCode == ActionCode.ACTION_CLOSE) {
      // Close

      // End the processing of the current request, and stop any further
      // transactions with the client

      try {
        outputBuffer.endRequest();
      } catch (IOException e) {
        // Set error flag
        error = true;
      }
    }
  }
Esempio n. 12
0
  public void action(ActionCode actionCode, Object param) {
    if (hook == null && response != null) hook = response.getHook();

    if (hook != null) {
      if (param == null) hook.action(actionCode, this);
      else hook.action(actionCode, param);
    }
  }
 public AbstractProcessor(AbstractEndpoint<S> endpoint) {
   this.endpoint = endpoint;
   asyncStateMachine = new AsyncStateMachine(this);
   request = new Request();
   response = new Response();
   response.setHook(this);
   request.setResponse(response);
 }
  public CCNProcessor(int headerBufferSize, CCNEndpoint endpoint) {
    // TODO Abnprsuto-generated constructor stub
    this.endpoint = endpoint;
    request = new Request();
    inputBuffer = new InternalCCNInputBuffer(request, headerBufferSize);
    response = new Response();
    response.setHook(this);

    outputBuffer = new InternalCCNOutputBuffer(response, headerBufferSize);
    response.setOutputBuffer(outputBuffer);
    request.setResponse(response);

    // nan initializeFilters();

    // Cause loading of HexUtils
    // nan HexUtils.getDec('0');

  }
Esempio n. 15
0
  /**
   * Has the specified header been set already in this response?
   *
   * @param name Name of the header to check
   */
  @Override
  public boolean containsHeader(String name) {
    // Need special handling for Content-Type and Content-Length due to
    // special handling of these in coyoteResponse
    char cc = name.charAt(0);
    if (cc == 'C' || cc == 'c') {
      if (name.equalsIgnoreCase("Content-Type")) {
        // Will return null if this has not been set
        return (coyoteResponse.getContentType() != null);
      }
      if (name.equalsIgnoreCase("Content-Length")) {
        // -1 means not known and is not sent to client
        return (coyoteResponse.getContentLengthLong() != -1);
      }
    }

    return coyoteResponse.containsHeader(name);
  }
Esempio n. 16
0
  @Override
  public Collection<String> getHeaders(String name) {

    Enumeration<String> enumeration = coyoteResponse.getMimeHeaders().values(name);
    Vector<String> result = new Vector<>();
    while (enumeration.hasMoreElements()) {
      result.addElement(enumeration.nextElement());
    }
    return result;
  }
Esempio n. 17
0
  /**
   * Close the output buffer. This tries to calculate the response size if the response has not been
   * committed yet.
   *
   * @throws IOException An underlying IOException occurred
   */
  @Override
  public void close() throws IOException {

    if (closed) return;
    if (suspended) return;

    if ((!coyoteResponse.isCommitted()) && (coyoteResponse.getContentLengthLong() == -1)) {
      // If this didn't cause a commit of the response, the final content
      // length can be calculated
      if (!coyoteResponse.isCommitted()) {
        coyoteResponse.setContentLength(bb.getLength());
      }
    }

    doFlush(false);
    closed = true;

    coyoteResponse.finish();
  }
Esempio n. 18
0
 /**
  * Return the number of bytes the actually written to the socket. This includes chunking,
  * compression, etc. but excludes headers.
  */
 public long getBytesWritten(boolean flush) {
   if (flush) {
     try {
       outputBuffer.flush();
     } catch (IOException ioe) {
       // Ignore - the client has probably closed the connection
     }
   }
   return coyoteResponse.getBytesWritten(flush);
 }
Esempio n. 19
0
  @Override
  public Collection<String> getHeaderNames() {

    MimeHeaders headers = coyoteResponse.getMimeHeaders();
    int n = headers.size();
    List<String> result = new ArrayList<>(n);
    for (int i = 0; i < n; i++) {
      result.add(headers.getName(i).toString());
    }
    return result;
  }
Esempio n. 20
0
  /** TODO SERVLET 3.1 */
  @Override
  public void setContentLengthLong(long length) {
    if (isCommitted()) {
      return;
    }

    // Ignore any call from an included servlet
    if (included) {
      return;
    }

    coyoteResponse.setContentLength(length);
  }
Esempio n. 21
0
  /**
   * Send an acknowledgement of a request.
   *
   * @exception IOException if an input/output error occurs
   */
  public void sendAcknowledgement() throws IOException {

    if (isCommitted()) {
      return;
    }

    // Ignore any call from an included servlet
    if (included) {
      return;
    }

    coyoteResponse.action(ActionCode.ACK, null);
  }
Esempio n. 22
0
  /**
   * Clear any content written to the buffer.
   *
   * @exception IllegalStateException if this response has already been committed
   */
  @Override
  public void reset() {
    // Ignore any call from an included servlet
    if (included) {
      return;
    }

    coyoteResponse.reset();
    outputBuffer.reset();
    usingOutputStream = false;
    usingWriter = false;
    isCharacterEncodingSet = false;
  }
Esempio n. 23
0
  @Override
  public void errorDispatch(org.apache.coyote.Request req, org.apache.coyote.Response res) {
    Request request = (Request) req.getNote(ADAPTER_NOTES);
    Response response = (Response) res.getNote(ADAPTER_NOTES);

    if (request != null && request.getMappingData().context != null) {
      ((Context) request.getMappingData().context)
          .logAccess(request, response, System.currentTimeMillis() - req.getStartTime(), false);
    } else {
      log(req, res, System.currentTimeMillis() - req.getStartTime());
    }

    if (request != null) {
      request.recycle();
    }

    if (response != null) {
      response.recycle();
    }

    req.recycle();
    res.recycle();
  }
Esempio n. 24
0
  /**
   * Flush bytes or chars contained in the buffer.
   *
   * @throws IOException An underlying IOException occurred
   */
  protected void doFlush(boolean realFlush) throws IOException {

    if (suspended) return;

    doFlush = true;
    if (initial) {
      coyoteResponse.sendHeaders();
      initial = false;
    }
    if (bb.getLength() > 0) {
      bb.flushBuffer();
    }
    doFlush = false;

    if (realFlush) {
      coyoteResponse.action(ActionCode.CLIENT_FLUSH, coyoteResponse);
      // If some exception occurred earlier, or if some IOE occurred
      // here, notify the servlet with an IOE
      if (coyoteResponse.isExceptionPresent()) {
        throw new ClientAbortException(coyoteResponse.getErrorException());
      }
    }
  }
Esempio n. 25
0
  /**
   * Send an error response with the specified status and message.
   *
   * @param status HTTP status code to send
   * @param message Corresponding message to send
   * @exception IllegalStateException if this response has already been committed
   * @exception IOException if an input/output error occurs
   */
  @Override
  public void sendError(int status, String message) throws IOException {

    if (isCommitted()) {
      throw new IllegalStateException(sm.getString("coyoteResponse.sendError.ise"));
    }

    // Ignore any call from an included servlet
    if (included) {
      return;
    }

    setError();

    coyoteResponse.setStatus(status);
    coyoteResponse.setMessage(message);

    // Clear any data content that has been buffered
    resetBuffer();

    // Cause the response to be finished (from the application perspective)
    setSuspended(true);
  }
Esempio n. 26
0
  /**
   * Sends the buffer data to the client output, checking the state of Response and calling the
   * right interceptors.
   *
   * @param buf Byte buffer to be written to the response
   * @param off Offset
   * @param cnt Length
   * @throws IOException An underlying IOException occurred
   */
  @Override
  public void realWriteBytes(byte buf[], int off, int cnt) throws IOException {

    if (closed) return;
    if (coyoteResponse == null) return;

    // If we really have something to write
    if (cnt > 0) {
      // real write to the adapter
      outputChunk.setBytes(buf, off, cnt);
      try {
        coyoteResponse.doWrite(outputChunk);
      } catch (IOException e) {
        // An IOException on a write is almost always due to
        // the remote client aborting the request.  Wrap this
        // so that it can be handled better by the error dispatcher.
        throw new ClientAbortException(e);
      }
    }
  }
Esempio n. 27
0
  /*
   * Overrides the name of the character encoding used in the body
   * of the request. This method must be called prior to reading
   * request parameters or reading input using getReader().
   *
   * @param charset String containing the name of the character encoding.
   */
  @Override
  public void setCharacterEncoding(String charset) {

    if (isCommitted()) {
      return;
    }

    // Ignore any call from an included servlet
    if (included) {
      return;
    }

    // Ignore any call made after the getWriter has been invoked
    // The default should be used
    if (usingWriter) {
      return;
    }

    coyoteResponse.setCharacterEncoding(charset);
    isCharacterEncodingSet = true;
  }
Esempio n. 28
0
  /**
   * Add the specified header to the specified value.
   *
   * @param name Name of the header to set
   * @param value Value to be set
   */
  @Override
  public void addHeader(String name, String value) {

    if (name == null || name.length() == 0 || value == null) {
      return;
    }

    if (isCommitted()) {
      return;
    }

    // Ignore any call from an included servlet
    if (included) {
      return;
    }

    char cc = name.charAt(0);
    if (cc == 'C' || cc == 'c') {
      if (checkSpecialHeader(name, value)) return;
    }

    coyoteResponse.addHeader(name, value);
  }
Esempio n. 29
0
  /**
   * Special method for adding a session cookie as we should be overriding any previous
   *
   * @param cookie
   */
  public void addSessionCookieInternal(final Cookie cookie) {
    if (isCommitted()) {
      return;
    }

    String name = cookie.getName();
    final String headername = "Set-Cookie";
    final String startsWith = name + "=";
    String header = generateCookieString(cookie);
    boolean set = false;
    MimeHeaders headers = coyoteResponse.getMimeHeaders();
    int n = headers.size();
    for (int i = 0; i < n; i++) {
      if (headers.getName(i).toString().equals(headername)) {
        if (headers.getValue(i).toString().startsWith(startsWith)) {
          headers.getValue(i).setString(header);
          set = true;
        }
      }
    }
    if (!set) {
      addHeader(headername, header);
    }
  }
Esempio n. 30
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;
  }