/* ------------------------------------------------------------ */ public void flushResponse() throws IOException { try { commitResponse(Generator.MORE); _generator.flushBuffer(); } catch (IOException e) { throw (e instanceof EofException) ? e : new EofException(e); } }
/* ------------------------------------------------------------ */ public void reset(boolean returnBuffers) { _parser.reset(); if (returnBuffers) _parser.returnBuffers(); _requestFields.clear(); _request.recycle(); _generator.reset(returnBuffers); // TODO maybe only release when low on resources _responseFields.clear(); _response.recycle(); _uri.clear(); }
/** * Get the inputStream from the connection. * * <p>If the associated response has the Expect header set to 100 Continue, then accessing the * input stream indicates that the handler/servlet is ready for the request body and thus a 100 * Continue response is sent. * * @return The input stream for this connection. The stream will be created if it does not already * exist. */ public ServletInputStream getInputStream() throws IOException { // If the client is expecting 100 CONTINUE, then send it now. if (_expect100Continue) { // is content missing? if (((HttpParser) _parser).getHeaderBuffer() == null || ((HttpParser) _parser).getHeaderBuffer().length() < 2) { if (_generator.isCommitted()) throw new IllegalStateException("Committed before 100 Continues"); ((HttpGenerator) _generator).send1xx(HttpStatus.CONTINUE_100); } _expect100Continue = false; } if (_in == null) _in = new HttpInput(HttpConnection.this); return _in; }
/** Constructor */ public HttpConnection(Connector connector, EndPoint endpoint, Server server) { super(endpoint); _uri = StringUtil.__UTF8.equals(URIUtil.__CHARSET) ? new HttpURI() : new EncodedHttpURI(URIUtil.__CHARSET); _connector = connector; HttpBuffers ab = (HttpBuffers) _connector; _parser = new HttpParser(ab.getRequestBuffers(), endpoint, new RequestHandler()); _requestFields = new HttpFields(); _responseFields = new HttpFields(server.getMaxCookieVersion()); _request = new Request(this); _response = new Response(this); _generator = new HttpGenerator(ab.getResponseBuffers(), _endp); _generator.setSendServerVersion(server.getSendServerVersion()); _server = server; }
/* ------------------------------------------------------------ */ public void commitResponse(boolean last) throws IOException { if (!_generator.isCommitted()) { _generator.setResponse(_response.getStatus(), _response.getReason()); try { // If the client was expecting 100 continues, but we sent something // else, then we need to close the connection if (_expect100Continue && _response.getStatus() != 100) _generator.setPersistent(false); _generator.completeHeader(_responseFields, last); } catch (IOException io) { throw io; } catch (RuntimeException e) { LOG.warn("header full: " + e); _response.reset(); _generator.reset(true); _generator.setResponse(HttpStatus.INTERNAL_SERVER_ERROR_500, null); _generator.completeHeader(_responseFields, Generator.LAST); _generator.complete(); throw new HttpException(HttpStatus.INTERNAL_SERVER_ERROR_500); } } if (last) _generator.complete(); }
/* ------------------------------------------------------------ */ public void completeResponse() throws IOException { if (!_generator.isCommitted()) { _generator.setResponse(_response.getStatus(), _response.getReason()); try { _generator.completeHeader(_responseFields, Generator.LAST); } catch (IOException io) { throw io; } catch (RuntimeException e) { LOG.warn("header full: " + e); LOG.debug(e); _response.reset(); _generator.reset(true); _generator.setResponse(HttpStatus.INTERNAL_SERVER_ERROR_500, null); _generator.completeHeader(_responseFields, Generator.LAST); _generator.complete(); throw new HttpException(HttpStatus.INTERNAL_SERVER_ERROR_500); } } _generator.complete(); }
/* ------------------------------------------------------------ */ protected HttpConnection( Connector connector, EndPoint endpoint, Server server, Parser parser, Generator generator, Request request) { super(endpoint); _uri = URIUtil.__CHARSET.equals(StringUtil.__UTF8) ? new HttpURI() : new EncodedHttpURI(URIUtil.__CHARSET); _connector = connector; _parser = parser; _requestFields = new HttpFields(); _responseFields = new HttpFields(server.getMaxCookieVersion()); _request = request; _response = new Response(this); _generator = generator; _generator.setSendServerVersion(server.getSendServerVersion()); _server = server; }
/* ------------------------------------------------------------ */ public boolean isIdle() { return _generator.isIdle() && (_parser.isIdle() || _delayedHandling); }
/* ------------------------------------------------------------ */ 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); } } }
/* ------------------------------------------------------------ */ public boolean isResponseCommitted() { return _generator.isCommitted(); }