public void reset() throws IllegalStateException { // Reset the headers only if this is the main request, // not for included contentType = null; ; locale = DEFAULT_LOCALE; contentLanguage = null; characterEncoding = Constants.DEFAULT_CHARACTER_ENCODING; // START SJSAS 6316254 quotedCharsetValue = characterEncoding; // END SJSAS 6316254 contentLength = -1; charsetSet = false; status = 200; message = null; headers.clear(); // Force the PrintWriter to flush its data to the output // stream before resetting the output stream // // Reset the stream if (commited) { // String msg = sm.getString("servletOutputStreamImpl.reset.ise"); throw new IllegalStateException(); } action(ActionCode.ACTION_RESET, this); }
public boolean checkRegisterForWrite() { AtomicBoolean ready = new AtomicBoolean(false); synchronized (nonBlockingStateLock) { if (!registeredForWrite) { action(ActionCode.NB_WRITE_INTEREST, ready); registeredForWrite = !ready.get(); } } return ready.get(); }
public void reset() throws IllegalStateException { if (commited) { throw new IllegalStateException(); } recycle(); // Reset the stream action(ActionCode.RESET, this); }
public void setWriteListener(WriteListener listener) { if (listener == null) { throw new NullPointerException(sm.getString("response.nullWriteListener")); } if (getWriteListener() != null) { throw new IllegalStateException(sm.getString("response.writeListenerSet")); } // Note: This class is not used for HTTP upgrade so only need to test // for async AtomicBoolean result = new AtomicBoolean(false); action(ActionCode.ASYNC_IS_ASYNC, result); if (!result.get()) { throw new IllegalStateException(sm.getString("response.notAsync")); } this.listener = listener; // The container is responsible for the first call to // listener.onWritePossible(). If isReady() returns true, the container // needs to call listener.onWritePossible() from a new thread. If // isReady() returns false, the socket will be registered for write and // the container will call listener.onWritePossible() once data can be // written. if (isReady()) { synchronized (nonBlockingStateLock) { // Ensure we don't get multiple write registrations if // ServletOutputStream.isReady() returns false during a call to // onDataAvailable() registeredForWrite = true; // Need to set the fireListener flag otherwise when the // container tries to trigger onWritePossible, nothing will // happen fireListener = true; } action(ActionCode.DISPATCH_WRITE, null); if (!ContainerThreadMarker.isContainerThread()) { // Not on a container thread so need to execute the dispatch action(ActionCode.DISPATCH_EXECUTE, null); } } }
/** * 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); }
/** * 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()); } } }
/** 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; }
/** Service method. */ @Override public void service(org.apache.coyote.Request req, org.apache.coyote.Response res) throws Exception { 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()); } if (connector.getXpoweredBy()) { response.addHeader("X-Powered-By", POWERED_BY); } boolean comet = false; boolean async = false; try { // Parse and set Catalina and configuration specific // request parameters req.getRequestProcessor().setWorkerThreadName(Thread.currentThread().getName()); boolean postParseSuccess = postParseRequest(req, request, res, response); if (postParseSuccess) { // check valves if we support async request.setAsyncSupported( connector.getService().getContainer().getPipeline().isAsyncSupported()); // Calling the container connector.getService().getContainer().getPipeline().getFirst().invoke(request, response); if (request.isComet()) { if (!response.isClosed() && !response.isError()) { if (request.getAvailable() || (request.getContentLength() > 0 && (!request.isParametersParsed()))) { // Invoke a read event right away if there are available bytes if (event(req, res, SocketStatus.OPEN_READ)) { comet = true; res.action(ActionCode.COMET_BEGIN, null); } } else { comet = true; res.action(ActionCode.COMET_BEGIN, null); } } else { // Clear the filter chain, as otherwise it will not be reset elsewhere // since this is a Comet request request.setFilterChain(null); } } } AsyncContextImpl asyncConImpl = (AsyncContextImpl) request.getAsyncContext(); if (asyncConImpl != null) { async = true; } else if (!comet) { request.finishRequest(); response.finishResponse(); if (postParseSuccess && request.getMappingData().context != null) { // Log only if processing was invoked. // If postParseRequest() failed, it has already logged it. // If context is null this was the start of a comet request // that failed and has already been logged. ((Context) request.getMappingData().context) .logAccess(request, response, System.currentTimeMillis() - req.getStartTime(), false); } req.action(ActionCode.POST_REQUEST, null); } } catch (IOException e) { // Ignore } finally { req.getRequestProcessor().setWorkerThreadName(null); AtomicBoolean error = new AtomicBoolean(false); res.action(ActionCode.IS_ERROR, error); // Recycle the wrapper request and response if (!comet && !async || error.get()) { request.recycle(); response.recycle(); } else { // Clear converters so that the minimum amount of memory // is used by this processor request.clearEncoders(); response.clearEncoders(); } } }
@Override public boolean asyncDispatch( org.apache.coyote.Request req, org.apache.coyote.Response res, SocketStatus status) throws Exception { Request request = (Request) req.getNote(ADAPTER_NOTES); Response response = (Response) res.getNote(ADAPTER_NOTES); if (request == null) { throw new IllegalStateException("Dispatch may only happen on an existing request."); } boolean comet = false; boolean success = true; AsyncContextImpl asyncConImpl = (AsyncContextImpl) request.getAsyncContext(); req.getRequestProcessor().setWorkerThreadName(Thread.currentThread().getName()); try { if (!request.isAsync() && !comet) { // Error or timeout - need to tell listeners the request is over // Have to test this first since state may change while in this // method and this is only required if entering this method in // this state Context ctxt = (Context) request.getMappingData().context; if (ctxt != null) { ctxt.fireRequestDestroyEvent(request); } // Lift any suspension (e.g. if sendError() was used by an async // request) to allow the response to be written to the client response.setSuspended(false); } if (status == SocketStatus.TIMEOUT) { if (!asyncConImpl.timeout()) { asyncConImpl.setErrorState(null, false); } } // Has an error occurred during async processing that needs to be // processed by the application's error page mechanism (or Tomcat's // if the application doesn't define one)? if (!request.isAsyncDispatching() && request.isAsync() && response.isErrorReportRequired()) { connector.getService().getContainer().getPipeline().getFirst().invoke(request, response); } if (request.isAsyncDispatching()) { connector.getService().getContainer().getPipeline().getFirst().invoke(request, response); Throwable t = (Throwable) request.getAttribute(RequestDispatcher.ERROR_EXCEPTION); if (t != null) { asyncConImpl.setErrorState(t, true); } } if (request.isComet()) { if (!response.isClosed() && !response.isError()) { if (request.getAvailable() || (request.getContentLength() > 0 && (!request.isParametersParsed()))) { // Invoke a read event right away if there are available bytes if (event(req, res, SocketStatus.OPEN_READ)) { comet = true; res.action(ActionCode.COMET_BEGIN, null); } } else { comet = true; res.action(ActionCode.COMET_BEGIN, null); } } else { // Clear the filter chain, as otherwise it will not be reset elsewhere // since this is a Comet request request.setFilterChain(null); } } if (!request.isAsync() && !comet) { request.finishRequest(); response.finishResponse(); req.action(ActionCode.POST_REQUEST, null); ((Context) request.getMappingData().context) .logAccess(request, response, System.currentTimeMillis() - req.getStartTime(), false); } // Check to see if the processor is in an error state. If it is, // bail out now. AtomicBoolean error = new AtomicBoolean(false); res.action(ActionCode.IS_ERROR, error); if (error.get()) { success = false; } } catch (IOException e) { success = false; // Ignore } catch (Throwable t) { ExceptionUtils.handleThrowable(t); success = false; log.error(sm.getString("coyoteAdapter.service"), t); } finally { req.getRequestProcessor().setWorkerThreadName(null); // Recycle the wrapper request and response if (!success || (!comet && !request.isAsync())) { request.recycle(); response.recycle(); } else { // Clear converters so that the minimum amount of memory // is used by this processor request.clearEncoders(); response.clearEncoders(); } } return success; }
/** * Event method. * * @return false to indicate an error, expected or not */ @Override public boolean event( org.apache.coyote.Request req, org.apache.coyote.Response res, SocketStatus status) { Request request = (Request) req.getNote(ADAPTER_NOTES); Response response = (Response) res.getNote(ADAPTER_NOTES); if (request.getWrapper() == null) { return false; } boolean error = false; boolean read = false; try { if (status == SocketStatus.OPEN_READ) { if (response.isClosed()) { // The event has been closed asynchronously, so call end instead of // read to cleanup the pipeline request.getEvent().setEventType(CometEvent.EventType.END); request.getEvent().setEventSubType(null); } else { try { // Fill the read buffer of the servlet layer if (request.read()) { read = true; } } catch (IOException e) { error = true; } if (read) { request.getEvent().setEventType(CometEvent.EventType.READ); request.getEvent().setEventSubType(null); } else if (error) { request.getEvent().setEventType(CometEvent.EventType.ERROR); request.getEvent().setEventSubType(CometEvent.EventSubType.CLIENT_DISCONNECT); } else { request.getEvent().setEventType(CometEvent.EventType.END); request.getEvent().setEventSubType(null); } } } else if (status == SocketStatus.DISCONNECT) { request.getEvent().setEventType(CometEvent.EventType.ERROR); request.getEvent().setEventSubType(CometEvent.EventSubType.CLIENT_DISCONNECT); error = true; } else if (status == SocketStatus.ERROR) { request.getEvent().setEventType(CometEvent.EventType.ERROR); request.getEvent().setEventSubType(CometEvent.EventSubType.IOEXCEPTION); error = true; } else if (status == SocketStatus.STOP) { request.getEvent().setEventType(CometEvent.EventType.END); request.getEvent().setEventSubType(CometEvent.EventSubType.SERVER_SHUTDOWN); } else if (status == SocketStatus.TIMEOUT) { if (response.isClosed()) { // The event has been closed asynchronously, so call end instead of // read to cleanup the pipeline request.getEvent().setEventType(CometEvent.EventType.END); request.getEvent().setEventSubType(null); } else { request.getEvent().setEventType(CometEvent.EventType.ERROR); request.getEvent().setEventSubType(CometEvent.EventSubType.TIMEOUT); } } req.getRequestProcessor().setWorkerThreadName(Thread.currentThread().getName()); // Calling the container connector .getService() .getContainer() .getPipeline() .getFirst() .event(request, response, request.getEvent()); if (!error && !response.isClosed() && (request.getAttribute(RequestDispatcher.ERROR_EXCEPTION) != null)) { // An unexpected exception occurred while processing the event, so // error should be called request.getEvent().setEventType(CometEvent.EventType.ERROR); request.getEvent().setEventSubType(null); error = true; connector .getService() .getContainer() .getPipeline() .getFirst() .event(request, response, request.getEvent()); } if (response.isClosed() || !request.isComet()) { if (status == SocketStatus.OPEN_READ && request.getEvent().getEventType() != EventType.END) { // CometEvent.close was called during an event other than END request.getEvent().setEventType(CometEvent.EventType.END); request.getEvent().setEventSubType(null); error = true; connector .getService() .getContainer() .getPipeline() .getFirst() .event(request, response, request.getEvent()); } res.action(ActionCode.COMET_END, null); } else if (!error && read && request.getAvailable()) { // If this was a read and not all bytes have been read, or if no data // was read from the connector, then it is an error request.getEvent().setEventType(CometEvent.EventType.ERROR); request.getEvent().setEventSubType(CometEvent.EventSubType.IOEXCEPTION); error = true; connector .getService() .getContainer() .getPipeline() .getFirst() .event(request, response, request.getEvent()); } return (!error); } catch (Throwable t) { ExceptionUtils.handleThrowable(t); if (!(t instanceof IOException)) { log.error(sm.getString("coyoteAdapter.service"), t); } error = true; return false; } finally { req.getRequestProcessor().setWorkerThreadName(null); // Recycle the wrapper request and response if (error || response.isClosed() || !request.isComet()) { ((Context) request.getMappingData().context) .logAccess(request, response, System.currentTimeMillis() - req.getStartTime(), false); request.recycle(); request.setFilterChain(null); response.recycle(); } } }
/** * Bytes written to socket - i.e. after compression, chunking, etc. * * @param flush Should any remaining bytes be flushed before returning the total? If {@code false} * bytes remaining in the buffer will not be included in the returned value * @return The total number of bytes written to the socket for this response */ public long getBytesWritten(boolean flush) { if (flush) { action(ActionCode.CLIENT_FLUSH, this); } return outputBuffer.getBytesWritten(); }
/** * Signal that we're done with the headers, and body will follow. Any implementation needs to * notify ContextManager, to allow interceptors to fix headers. */ public void sendHeaders() { action(ActionCode.COMMIT, this); setCommitted(true); }
/** * Signal that we're done with the headers, and body will follow. Any implementation needs to * notify ContextManager, to allow interceptors to fix headers. */ public void sendHeaders() throws IOException { action(ActionCode.ACTION_COMMIT, this); commited = true; }
public void acknowledge() throws IOException { action(ActionCode.ACTION_ACK, this); }
public void finish() throws IOException { action(ActionCode.ACTION_CLOSE, this); }