/* Handle a request from a connection. * Called to handle a request on the connection when either the header has been received, * or after the entire request has been received (for short requests of known length), or * on the dispatch of an async request. */ public void handleAsync(AbstractHttpConnection connection) throws IOException, ServletException { final AsyncContinuation async = connection.getRequest().getAsyncContinuation(); final AsyncContinuation.AsyncEventState state = async.getAsyncEventState(); final Request baseRequest = connection.getRequest(); final String path = state.getPath(); if (path != null) { // this is a dispatch with a path final String contextPath = state.getServletContext().getContextPath(); HttpURI uri = new HttpURI(URIUtil.addPaths(contextPath, path)); baseRequest.setUri(uri); baseRequest.setRequestURI(null); baseRequest.setPathInfo(baseRequest.getRequestURI()); if (uri.getQuery() != null) baseRequest.mergeQueryString(uri.getQuery()); } final String target = baseRequest.getPathInfo(); final HttpServletRequest request = (HttpServletRequest) async.getRequest(); final HttpServletResponse response = (HttpServletResponse) async.getResponse(); if (LOG.isDebugEnabled()) { LOG.debug("REQUEST " + target + " on " + connection); handle(target, baseRequest, request, response); LOG.debug("RESPONSE " + target + " " + connection.getResponse().getStatus()); } else handle(target, baseRequest, request, response); }
/* Handle a request from a connection. * Called to handle a request on the connection when either the header has been received, * or after the entire request has been received (for short requests of known length), or * on the dispatch of an async request. */ public void handle(AbstractHttpConnection connection) throws IOException, ServletException { final String target = connection.getRequest().getPathInfo(); final Request request = connection.getRequest(); final Response response = connection.getResponse(); if (LOG.isDebugEnabled()) { LOG.debug("REQUEST " + target + " on " + connection); handle(target, request, request, response); LOG.debug("RESPONSE " + target + " " + connection.getResponse().getStatus()); } else handle(target, request, request, response); }
/* ------------------------------------------------------------ */ protected void handleRequest() throws IOException { boolean error = false; String threadName = null; try { if (LOG.isDebugEnabled()) { threadName = Thread.currentThread().getName(); Thread.currentThread().setName(threadName + " - " + _uri); } // Loop here to handle async request redispatches. // The loop is controlled by the call to async.unhandle in the // finally block below. If call is from a non-blocking connector, // then the unhandle will return false only if an async dispatch has // already happened when unhandle is called. For a blocking connector, // the wait for the asynchronous dispatch or timeout actually happens // within the call to unhandle(). final Server server = _server; boolean handling = _request._async.handling() && server != null && server.isRunning(); while (handling) { _request.setHandled(false); String info = null; try { _uri.getPort(); info = URIUtil.canonicalPath(_uri.getDecodedPath()); if (info == null && !_request.getMethod().equals(HttpMethods.CONNECT)) throw new HttpException(400); _request.setPathInfo(info); if (_out != null) _out.reopen(); if (_request._async.isInitial()) { _request.setDispatcherType(DispatcherType.REQUEST); _connector.customize(_endp, _request); server.handle(this); } else { _request.setDispatcherType(DispatcherType.ASYNC); server.handleAsync(this); } } catch (ContinuationThrowable e) { LOG.ignore(e); } catch (EofException e) { LOG.debug(e); error = true; _request.setHandled(true); } catch (RuntimeIOException e) { LOG.debug(e); error = true; _request.setHandled(true); } catch (HttpException e) { LOG.debug(e); error = true; _request.setHandled(true); _response.sendError(e.getStatus(), e.getReason()); } catch (Throwable e) { if (e instanceof ThreadDeath) throw (ThreadDeath) e; LOG.warn(String.valueOf(_uri), e); error = true; _request.setHandled(true); _generator.sendError(info == null ? 400 : 500, null, null, true); } finally { handling = !_request._async.unhandle() && server.isRunning() && _server != null; } } } finally { if (threadName != null) Thread.currentThread().setName(threadName); if (_request._async.isUncompleted()) { _request._async.doComplete(); if (_expect100Continue) { LOG.debug("100 continues not sent"); // We didn't send 100 continues, but the latest interpretation // of the spec (see httpbis) is that the client will either // send the body anyway, or close. So we no longer need to // do anything special here other than make the connection not persistent _expect100Continue = false; if (!_response.isCommitted()) _generator.setPersistent(false); } if (_endp.isOpen()) { if (error) { _endp.shutdownOutput(); _generator.setPersistent(false); if (!_generator.isComplete()) _response.complete(); } else { if (!_response.isCommitted() && !_request.isHandled()) _response.sendError(HttpServletResponse.SC_NOT_FOUND); _response.complete(); if (_generator.isPersistent()) _connector.persist(_endp); } } else { _response.complete(); } _request.setHandled(true); } } }