@Override public void sendRedirect(String location) throws IOException { if (isIncluding()) return; if (location == null) throw new IllegalArgumentException(); if (!URIUtil.hasScheme(location)) { StringBuilder buf = _channel.getRequest().getRootURL(); if (location.startsWith("/")) buf.append(location); else { String path = _channel.getRequest().getRequestURI(); String parent = (path.endsWith("/")) ? path : URIUtil.parentPath(path); location = URIUtil.addPaths(parent, location); if (location == null) throw new IllegalStateException("path cannot be above root"); if (!location.startsWith("/")) buf.append('/'); buf.append(location); } location = buf.toString(); HttpURI uri = new HttpURI(location); String path = uri.getDecodedPath(); String canonical = URIUtil.canonicalPath(path); if (canonical == null) throw new IllegalArgumentException(); if (!canonical.equals(path)) { buf = _channel.getRequest().getRootURL(); buf.append(URIUtil.encodePath(canonical)); String param = uri.getParam(); if (param != null) { buf.append(';'); buf.append(param); } String query = uri.getQuery(); if (query != null) { buf.append('?'); buf.append(query); } String fragment = uri.getFragment(); if (fragment != null) { buf.append('#'); buf.append(fragment); } location = buf.toString(); } } resetBuffer(); setHeader(HttpHeader.LOCATION, location); setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY); complete(); }
/* ------------------------------------------------------------ */ 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); } } }
@Override public void sendError(int code, String message) throws IOException { if (isIncluding()) return; if (isCommitted()) LOG.warn("Committed before " + code + " " + message); resetBuffer(); _characterEncoding = null; setHeader(HttpHeader.EXPIRES, null); setHeader(HttpHeader.LAST_MODIFIED, null); setHeader(HttpHeader.CACHE_CONTROL, null); setHeader(HttpHeader.CONTENT_TYPE, null); setHeader(HttpHeader.CONTENT_LENGTH, null); _outputType = OutputType.NONE; setStatus(code); _reason = message; Request request = _channel.getRequest(); Throwable cause = (Throwable) request.getAttribute(Dispatcher.ERROR_EXCEPTION); if (message == null) message = cause == null ? HttpStatus.getMessage(code) : cause.toString(); // If we are allowed to have a body if (code != SC_NO_CONTENT && code != SC_NOT_MODIFIED && code != SC_PARTIAL_CONTENT && code >= SC_OK) { ErrorHandler error_handler = null; ContextHandler.Context context = request.getContext(); if (context != null) error_handler = context.getContextHandler().getErrorHandler(); if (error_handler == null) error_handler = _channel.getServer().getBean(ErrorHandler.class); if (error_handler != null) { request.setAttribute(RequestDispatcher.ERROR_STATUS_CODE, new Integer(code)); request.setAttribute(RequestDispatcher.ERROR_MESSAGE, message); request.setAttribute(RequestDispatcher.ERROR_REQUEST_URI, request.getRequestURI()); request.setAttribute(RequestDispatcher.ERROR_SERVLET_NAME, request.getServletName()); error_handler.handle(null, _channel.getRequest(), _channel.getRequest(), this); } else { setHeader(HttpHeader.CACHE_CONTROL, "must-revalidate,no-cache,no-store"); setContentType(MimeTypes.Type.TEXT_HTML_8859_1.toString()); ByteArrayISO8859Writer writer = new ByteArrayISO8859Writer(2048); if (message != null) { message = StringUtil.replace(message, "&", "&"); message = StringUtil.replace(message, "<", "<"); message = StringUtil.replace(message, ">", ">"); } String uri = request.getRequestURI(); if (uri != null) { uri = StringUtil.replace(uri, "&", "&"); uri = StringUtil.replace(uri, "<", "<"); uri = StringUtil.replace(uri, ">", ">"); } writer.write( "<html>\n<head>\n<meta http-equiv=\"Content-Type\" content=\"text/html;charset=ISO-8859-1\"/>\n"); writer.write("<title>Error "); writer.write(Integer.toString(code)); writer.write(' '); if (message == null) writer.write(message); writer.write("</title>\n</head>\n<body>\n<h2>HTTP ERROR: "); writer.write(Integer.toString(code)); writer.write("</h2>\n<p>Problem accessing "); writer.write(uri); writer.write(". Reason:\n<pre> "); writer.write(message); writer.write("</pre>"); writer.write("</p>\n<hr /><i><small>Powered by Jetty://</small></i>"); writer.write("\n</body>\n</html>\n"); writer.flush(); setContentLength(writer.size()); writer.writeTo(getOutputStream()); writer.destroy(); } } else if (code != SC_PARTIAL_CONTENT) { // TODO work out why this is required? _channel.getRequest().getHttpFields().remove(HttpHeader.CONTENT_TYPE); _channel.getRequest().getHttpFields().remove(HttpHeader.CONTENT_LENGTH); _characterEncoding = null; _mimeType = null; } complete(); }