/** * Set the Locale that is appropriate for this response, including setting the appropriate * character encoding. * * @param locale The new locale */ @Override public void setLocale(Locale locale) { if (isCommitted()) { return; } // Ignore any call from an included servlet if (included) { return; } coyoteResponse.setLocale(locale); // Ignore any call made after the getWriter has been invoked. // The default should be used if (usingWriter) { return; } if (isCharacterEncodingSet) { return; } String charset = getContext().getCharset(locale); if (charset != null) { coyoteResponse.setCharacterEncoding(charset); } }
public int doWrite(ByteChunk chunk, Response res) throws IOException { if (!res.isCommitted()) { // Send the connector a request for commit. The connector should // then validate the headers, send them (using sendHeader) and // set the filters accordingly. res.sendHeaders(); } int len = chunk.getLength(); byte buf[] = outputMsg.getBuffer(); // 4 - hardcoded, byte[] marshalling overhead int chunkSize = buf.length - outputMsg.getHeaderLength() - 4; int off = 0; while (len > 0) { int thisTime = len; if (thisTime > chunkSize) { thisTime = chunkSize; } len -= thisTime; outputMsg.reset(); outputMsg.appendByte(AjpConstants.JK_AJP13_SEND_BODY_CHUNK); if (log.isTraceEnabled()) log.trace("doWrite " + off + " " + thisTime + " " + len); outputMsg.appendBytes(chunk.getBytes(), chunk.getOffset() + off, thisTime); off += thisTime; mc.getSource().send(outputMsg, mc); } return 0; }
// -------------------- Jk handler implementation -------------------- // Jk Handler mehod public int invoke(Msg msg, MsgContext ep) throws IOException { if (ep.isLogTimeEnabled()) ep.setLong(MsgContext.TIMER_PRE_REQUEST, System.currentTimeMillis()); Request req = ep.getRequest(); Response res = req.getResponse(); if (log.isDebugEnabled()) log.debug("Invoke " + req + " " + res + " " + req.requestURI().toString()); res.setNote(epNote, ep); ep.setStatus(MsgContext.JK_STATUS_HEAD); RequestInfo rp = req.getRequestProcessor(); rp.setStage(Constants.STAGE_SERVICE); try { adapter.service(req, res); } catch (Exception ex) { log.info("Error servicing request " + req, ex); } if (ep.getStatus() != MsgContext.JK_STATUS_CLOSED) { res.finish(); } req.updateCounters(); req.recycle(); res.recycle(); ep.recycle(); if (ep.getStatus() == MsgContext.JK_STATUS_ERROR) { return ERROR; } ep.setStatus(MsgContext.JK_STATUS_NEW); rp.setStage(Constants.STAGE_KEEPALIVE); return OK; }
/** * Set the content type for this Response. * * @param type The new content type */ @Override public void setContentType(String type) { if (isCommitted()) { return; } // Ignore any call from an included servlet if (included) { return; } if (type == null) { coyoteResponse.setContentType(null); return; } String[] m = MEDIA_TYPE_CACHE.parse(type); if (m == null) { // Invalid - Assume no charset and just pass through whatever // the user provided. coyoteResponse.setContentTypeNoCharset(type); return; } coyoteResponse.setContentTypeNoCharset(m[0]); if (m[1] != null) { // Ignore charset if getWriter() has already been called if (!usingWriter) { coyoteResponse.setCharacterEncoding(m[1]); isCharacterEncodingSet = true; } } }
public void appendHead(Response res) throws IOException { if (log.isDebugEnabled()) log.debug("COMMIT sending headers " + res + " " + res.getMimeHeaders()); C2BConverter c2b = mc.getConverter(); outputMsg.reset(); outputMsg.appendByte(AjpConstants.JK_AJP13_SEND_HEADERS); outputMsg.appendInt(res.getStatus()); String message = null; if (org.apache.coyote.Constants.USE_CUSTOM_STATUS_MSG_IN_HEADER && HttpMessages.isSafeInHttpHeader(res.getMessage())) { message = res.getMessage(); } if (message == null) { message = HttpMessages.getMessage(res.getStatus()); } if (message == null) { // mod_jk + httpd 2.x fails with a null status message - bug 45026 message = Integer.toString(res.getStatus()); } tempMB.setString(message); c2b.convert(tempMB); outputMsg.appendBytes(tempMB); // XXX add headers MimeHeaders headers = res.getMimeHeaders(); String contentType = res.getContentType(); if (contentType != null) { headers.setValue("Content-Type").setString(contentType); } String contentLanguage = res.getContentLanguage(); if (contentLanguage != null) { headers.setValue("Content-Language").setString(contentLanguage); } long contentLength = res.getContentLengthLong(); if (contentLength >= 0) { headers.setValue("Content-Length").setLong(contentLength); } int numHeaders = headers.size(); outputMsg.appendInt(numHeaders); for (int i = 0; i < numHeaders; i++) { MessageBytes hN = headers.getName(i); // no header to sc conversion - there's little benefit // on this direction outputMsg.appendBytes(hN); MessageBytes hV = headers.getValue(i); outputMsg.appendBytes(hV); } mc.getSource().send(outputMsg, mc); }
@Override public void log(org.apache.coyote.Request req, org.apache.coyote.Response res, long time) { 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()); } try { // Log at the lowest level available. logAccess() will be // automatically called on parent containers. boolean logged = false; if (request.mappingData != null) { if (request.mappingData.context != null) { logged = true; ((Context) request.mappingData.context).logAccess(request, response, time, true); } else if (request.mappingData.host != null) { logged = true; ((Host) request.mappingData.host).logAccess(request, response, time, true); } } if (!logged) { connector.getService().getContainer().logAccess(request, response, time, true); } } catch (Throwable t) { ExceptionUtils.handleThrowable(t); log.warn(sm.getString("coyoteAdapter.accesslogFail"), t); } finally { request.recycle(); response.recycle(); } }
/** * Set the HTTP status and message to be returned with this response. * * @param status The new HTTP status * @param message The associated text message * @deprecated As of Version 2.1 of the Java Servlet API, this method has been deprecated due to * the ambiguous meaning of the message parameter. */ @Override @Deprecated public void setStatus(int status, String message) { if (isCommitted()) { return; } // Ignore any call from an included servlet if (included) { return; } coyoteResponse.setStatus(status); coyoteResponse.setMessage(message); }
@Override public void checkRecycled(org.apache.coyote.Request req, org.apache.coyote.Response res) { Request request = (Request) req.getNote(ADAPTER_NOTES); Response response = (Response) res.getNote(ADAPTER_NOTES); String messageKey = null; if (request != null && request.getHost() != null) { messageKey = "coyoteAdapter.checkRecycled.request"; } else if (response != null && response.getContentWritten() != 0) { messageKey = "coyoteAdapter.checkRecycled.response"; } if (messageKey != null) { // Log this request, as it has probably skipped the access log. // The log() method will take care of recycling. log(req, res, 0L); if (connector.getState().isAvailable()) { if (log.isInfoEnabled()) { log.info(sm.getString(messageKey), new RecycleRequiredException()); } } else { // There may be some aborted requests. // When connector shuts down, the request and response will not // be reused, so there is no issue to warn about here. if (log.isDebugEnabled()) { log.debug(sm.getString(messageKey), new RecycleRequiredException()); } } } }
protected void setConverter() throws IOException { if (coyoteResponse != null) enc = coyoteResponse.getCharacterEncoding(); gotEnc = true; if (enc == null) enc = DEFAULT_ENCODING; conv = encoders.get(enc); if (conv == null) { if (Globals.IS_SECURITY_ENABLED) { try { conv = AccessController.doPrivileged( new PrivilegedExceptionAction<C2BConverter>() { @Override public C2BConverter run() throws IOException { return new C2BConverter(bb, enc); } }); } catch (PrivilegedActionException ex) { Exception e = ex.getException(); if (e instanceof IOException) throw (IOException) e; } } else { conv = new C2BConverter(bb, enc); } encoders.put(enc, conv); } }
/** * Update the current error state to the new error state if the new error state is more severe * than the current error state. */ protected void setErrorState(ErrorState errorState, Throwable t) { boolean blockIo = this.errorState.isIoAllowed() && !errorState.isIoAllowed(); this.errorState = this.errorState.getMostSevere(errorState); if (blockIo && !ContainerThreadMarker.isContainerThread() && isAsync()) { // The error occurred on a non-container thread during async // processing which means not all of the necessary clean-up will // have been completed. Dispatch to a container thread to do the // clean-up. Need to do it this way to ensure that all the necessary // clean-up is performed. if (response.getStatus() < 400) { response.setStatus(500); } getLog().info(sm.getString("abstractProcessor.nonContainerThreadError"), t); getEndpoint().processSocket(socketWrapper, SocketStatus.CLOSE_NOW, true); } }
@Override public void action(ActionCode actionCode, Object param) { // TODO Auto-generated method stub if (actionCode == ActionCode.ACTION_COMMIT) { // Commit current response if (response.isCommitted()) return; // Validate and write response headers prepareResponse(); try { outputBuffer.commit(); } catch (IOException e) { // Set error flag error = true; } } else if (actionCode == ActionCode.ACTION_CLOSE) { // Close // End the processing of the current request, and stop any further // transactions with the client try { outputBuffer.endRequest(); } catch (IOException e) { // Set error flag error = true; } } }
public void action(ActionCode actionCode, Object param) { if (hook == null && response != null) hook = response.getHook(); if (hook != null) { if (param == null) hook.action(actionCode, this); else hook.action(actionCode, param); } }
public AbstractProcessor(AbstractEndpoint<S> endpoint) { this.endpoint = endpoint; asyncStateMachine = new AsyncStateMachine(this); request = new Request(); response = new Response(); response.setHook(this); request.setResponse(response); }
public CCNProcessor(int headerBufferSize, CCNEndpoint endpoint) { // TODO Abnprsuto-generated constructor stub this.endpoint = endpoint; request = new Request(); inputBuffer = new InternalCCNInputBuffer(request, headerBufferSize); response = new Response(); response.setHook(this); outputBuffer = new InternalCCNOutputBuffer(response, headerBufferSize); response.setOutputBuffer(outputBuffer); request.setResponse(response); // nan initializeFilters(); // Cause loading of HexUtils // nan HexUtils.getDec('0'); }
/** * Has the specified header been set already in this response? * * @param name Name of the header to check */ @Override public boolean containsHeader(String name) { // Need special handling for Content-Type and Content-Length due to // special handling of these in coyoteResponse char cc = name.charAt(0); if (cc == 'C' || cc == 'c') { if (name.equalsIgnoreCase("Content-Type")) { // Will return null if this has not been set return (coyoteResponse.getContentType() != null); } if (name.equalsIgnoreCase("Content-Length")) { // -1 means not known and is not sent to client return (coyoteResponse.getContentLengthLong() != -1); } } return coyoteResponse.containsHeader(name); }
@Override public Collection<String> getHeaders(String name) { Enumeration<String> enumeration = coyoteResponse.getMimeHeaders().values(name); Vector<String> result = new Vector<>(); while (enumeration.hasMoreElements()) { result.addElement(enumeration.nextElement()); } return result; }
/** * Close the output buffer. This tries to calculate the response size if the response has not been * committed yet. * * @throws IOException An underlying IOException occurred */ @Override public void close() throws IOException { if (closed) return; if (suspended) return; if ((!coyoteResponse.isCommitted()) && (coyoteResponse.getContentLengthLong() == -1)) { // If this didn't cause a commit of the response, the final content // length can be calculated if (!coyoteResponse.isCommitted()) { coyoteResponse.setContentLength(bb.getLength()); } } doFlush(false); closed = true; coyoteResponse.finish(); }
/** * Return the number of bytes the actually written to the socket. This includes chunking, * compression, etc. but excludes headers. */ public long getBytesWritten(boolean flush) { if (flush) { try { outputBuffer.flush(); } catch (IOException ioe) { // Ignore - the client has probably closed the connection } } return coyoteResponse.getBytesWritten(flush); }
@Override public Collection<String> getHeaderNames() { MimeHeaders headers = coyoteResponse.getMimeHeaders(); int n = headers.size(); List<String> result = new ArrayList<>(n); for (int i = 0; i < n; i++) { result.add(headers.getName(i).toString()); } return result; }
/** TODO SERVLET 3.1 */ @Override public void setContentLengthLong(long length) { if (isCommitted()) { return; } // Ignore any call from an included servlet if (included) { return; } coyoteResponse.setContentLength(length); }
/** * 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); }
/** * Clear any content written to the buffer. * * @exception IllegalStateException if this response has already been committed */ @Override public void reset() { // Ignore any call from an included servlet if (included) { return; } coyoteResponse.reset(); outputBuffer.reset(); usingOutputStream = false; usingWriter = false; isCharacterEncodingSet = false; }
@Override public void errorDispatch(org.apache.coyote.Request req, org.apache.coyote.Response res) { Request request = (Request) req.getNote(ADAPTER_NOTES); Response response = (Response) res.getNote(ADAPTER_NOTES); if (request != null && request.getMappingData().context != null) { ((Context) request.getMappingData().context) .logAccess(request, response, System.currentTimeMillis() - req.getStartTime(), false); } else { log(req, res, System.currentTimeMillis() - req.getStartTime()); } if (request != null) { request.recycle(); } if (response != null) { response.recycle(); } req.recycle(); res.recycle(); }
/** * 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()); } } }
/** * Send an error response with the specified status and message. * * @param status HTTP status code to send * @param message Corresponding message to send * @exception IllegalStateException if this response has already been committed * @exception IOException if an input/output error occurs */ @Override public void sendError(int status, String message) throws IOException { if (isCommitted()) { throw new IllegalStateException(sm.getString("coyoteResponse.sendError.ise")); } // Ignore any call from an included servlet if (included) { return; } setError(); coyoteResponse.setStatus(status); coyoteResponse.setMessage(message); // Clear any data content that has been buffered resetBuffer(); // Cause the response to be finished (from the application perspective) setSuspended(true); }
/** * Sends the buffer data to the client output, checking the state of Response and calling the * right interceptors. * * @param buf Byte buffer to be written to the response * @param off Offset * @param cnt Length * @throws IOException An underlying IOException occurred */ @Override public void realWriteBytes(byte buf[], int off, int cnt) throws IOException { if (closed) return; if (coyoteResponse == null) return; // If we really have something to write if (cnt > 0) { // real write to the adapter outputChunk.setBytes(buf, off, cnt); try { coyoteResponse.doWrite(outputChunk); } catch (IOException e) { // An IOException on a write is almost always due to // the remote client aborting the request. Wrap this // so that it can be handled better by the error dispatcher. throw new ClientAbortException(e); } } }
/* * Overrides the name of the character encoding used in the body * of the request. This method must be called prior to reading * request parameters or reading input using getReader(). * * @param charset String containing the name of the character encoding. */ @Override public void setCharacterEncoding(String charset) { if (isCommitted()) { return; } // Ignore any call from an included servlet if (included) { return; } // Ignore any call made after the getWriter has been invoked // The default should be used if (usingWriter) { return; } coyoteResponse.setCharacterEncoding(charset); isCharacterEncodingSet = true; }
/** * Add the specified header to the specified value. * * @param name Name of the header to set * @param value Value to be set */ @Override public void addHeader(String name, String value) { if (name == null || name.length() == 0 || value == null) { return; } if (isCommitted()) { return; } // Ignore any call from an included servlet if (included) { return; } char cc = name.charAt(0); if (cc == 'C' || cc == 'c') { if (checkSpecialHeader(name, value)) return; } coyoteResponse.addHeader(name, value); }
/** * Special method for adding a session cookie as we should be overriding any previous * * @param cookie */ public void addSessionCookieInternal(final Cookie cookie) { if (isCommitted()) { return; } String name = cookie.getName(); final String headername = "Set-Cookie"; final String startsWith = name + "="; String header = generateCookieString(cookie); boolean set = false; MimeHeaders headers = coyoteResponse.getMimeHeaders(); int n = headers.size(); for (int i = 0; i < n; i++) { if (headers.getName(i).toString().equals(headername)) { if (headers.getValue(i).toString().startsWith(startsWith)) { headers.getValue(i).setString(header); set = true; } } } if (!set) { addHeader(headername, header); } }
/** 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; }