@Override public void reset() { resetForForward(); _status = 200; _reason = null; _contentLength = -1; _fields.clear(); String connection = _channel.getRequest().getHttpFields().getStringField(HttpHeader.CONNECTION); if (connection != null) { String[] values = connection.split(","); for (int i = 0; values != null && i < values.length; i++) { HttpHeaderValue cb = HttpHeaderValue.CACHE.get(values[0].trim()); if (cb != null) { switch (cb) { case CLOSE: _fields.put(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.toString()); break; case KEEP_ALIVE: if (HttpVersion.HTTP_1_0.is(_channel.getRequest().getProtocol())) _fields.put(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE.toString()); break; case TE: _fields.put(HttpHeader.CONNECTION, HttpHeaderValue.TE.toString()); break; } } } } }
@Override public void exchangeTerminated(HttpExchange exchange, Result result) { super.exchangeTerminated(exchange, result); Response response = result.getResponse(); HttpFields responseHeaders = response.getHeaders(); String closeReason = null; if (result.isFailed()) closeReason = "failure"; else if (receiver.isShutdown()) closeReason = "server close"; if (closeReason == null) { if (response.getVersion().compareTo(HttpVersion.HTTP_1_1) < 0) { // HTTP 1.0 must close the connection unless it has // an explicit keep alive or it's a CONNECT method. boolean keepAlive = responseHeaders.contains(HttpHeader.CONNECTION, HttpHeaderValue.KEEP_ALIVE.asString()); boolean connect = HttpMethod.CONNECT.is(exchange.getRequest().getMethod()); if (!keepAlive && !connect) closeReason = "http/1.0"; } else { // HTTP 1.1 or greater closes only if it has an explicit close. if (responseHeaders.contains(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE.asString())) closeReason = "http/1.1"; } } if (closeReason != null) { if (LOG.isDebugEnabled()) LOG.debug("Closing, reason: {} - {}", closeReason, connection); connection.close(); } else { if (response.getStatus() == HttpStatus.SWITCHING_PROTOCOLS_101) connection.remove(); else release(); } }
/** * Sends an error 500, performing a special logic to detect whether the request is suspended, to * avoid concurrent writes from the application. * * <p>It may happen that the application suspends, and then throws an exception, while an * application spawned thread writes the response content; in such case, we attempt to commit the * error directly bypassing the {@link ErrorHandler} mechanisms and the response OutputStream. * * @param x the Throwable that caused the problem */ protected void handleException(Throwable x) { try { _request.setAttribute(RequestDispatcher.ERROR_EXCEPTION, x); _request.setAttribute(RequestDispatcher.ERROR_EXCEPTION_TYPE, x.getClass()); if (_state.isSuspended()) { HttpFields fields = new HttpFields(); fields.add(HttpHeader.CONNECTION, HttpHeaderValue.CLOSE); ResponseInfo info = new ResponseInfo( _request.getHttpVersion(), fields, 0, HttpStatus.INTERNAL_SERVER_ERROR_500, null, _request.isHead()); boolean committed = sendResponse(info, null, true); if (!committed) LOG.warn("Could not send response error 500: " + x); _request.getAsyncContext().complete(); } else if (isCommitted()) { if (!(x instanceof EofException)) LOG.warn("Could not send response error 500: " + x); } else { _response.setHeader(HttpHeader.CONNECTION.asString(), HttpHeaderValue.CLOSE.asString()); _response.sendError(500, x.getMessage()); } } catch (IOException e) { // We tried our best, just log LOG.debug("Could not commit response error 500", e); } }