Author: markt Date: Fri Jul 8 09:50:02 2011 New Revision: 1144225 URL: http://svn.apache.org/viewvc?rev=1144225&view=rev Log: Fix indentation
Modified: tomcat/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java Modified: tomcat/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java URL: http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java?rev=1144225&r1=1144224&r2=1144225&view=diff ============================================================================== --- tomcat/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java (original) +++ tomcat/trunk/java/org/apache/coyote/ajp/AbstractAjpProcessor.java Fri Jul 8 09:50:02 2011 @@ -70,7 +70,7 @@ public abstract class AbstractAjpProcess * Flush message array. */ protected static final byte[] flushMessageArray; - + /** * Pong message array. @@ -88,7 +88,7 @@ public abstract class AbstractAjpProcess endMessageArray = new byte[endMessage.getLen()]; System.arraycopy(endMessage.getBuffer(), 0, endMessageArray, 0, endMessage.getLen()); - + // Allocate the flush message array AjpMessage flushMessage = new AjpMessage(16); flushMessage.reset(); @@ -99,7 +99,7 @@ public abstract class AbstractAjpProcess flushMessageArray = new byte[flushMessage.getLen()]; System.arraycopy(flushMessage.getBuffer(), 0, flushMessageArray, 0, flushMessage.getLen()); - + // Allocate the pong message array AjpMessage pongMessage = new AjpMessage(16); pongMessage.reset(); @@ -110,7 +110,7 @@ public abstract class AbstractAjpProcess 0, pongMessage.getLen()); } - + // ----------------------------------------------------- Instance Variables @@ -146,7 +146,7 @@ public abstract class AbstractAjpProcess */ protected AjpMessage bodyMessage = null; - + /** * Body message. */ @@ -205,28 +205,28 @@ public abstract class AbstractAjpProcess * Finished response. */ protected boolean finished = false; - - + + /** * Bytes written to client for the current request */ protected long byteCount = 0; - - + + // ------------------------------------------------------------ Constructor - + public AbstractAjpProcessor(int packetSize, AbstractEndpoint endpoint) { - + super(endpoint); this.packetSize = packetSize; request.setInputBuffer(new SocketInputBuffer()); - + requestHeaderMessage = new AjpMessage(packetSize); responseHeaderMessage = new AjpMessage(packetSize); bodyMessage = new AjpMessage(packetSize); - + // Set the getBody message buffer AjpMessage getBodyMessage = new AjpMessage(16); getBodyMessage.reset(); @@ -237,10 +237,10 @@ public abstract class AbstractAjpProcess getBodyMessage.end(); getBodyMessageArray = new byte[getBodyMessage.getLen()]; System.arraycopy(getBodyMessage.getBuffer(), 0, getBodyMessageArray, - 0, getBodyMessage.getLen()); + 0, getBodyMessage.getLen()); } - + // ------------------------------------------------------------- Properties @@ -289,648 +289,648 @@ public abstract class AbstractAjpProcess // --------------------------------------------------------- Public Methods - /** - * Send an action to the connector. - * - * @param actionCode Type of the action - * @param param Action parameter - */ - @Override - public final void action(ActionCode actionCode, Object param) { - - if (actionCode == ActionCode.COMMIT) { - - if (response.isCommitted()) - return; - - // Validate and write response headers - try { - prepareResponse(); - } catch (IOException e) { - // Set error flag - error = true; - } - - try { - flush(false); - } catch (IOException e) { - // Set error flag - error = true; - } - - } else if (actionCode == ActionCode.CLIENT_FLUSH) { - - if (!response.isCommitted()) { - // Validate and write response headers - try { - prepareResponse(); - } catch (IOException e) { - // Set error flag - error = true; - return; - } - } - - try { - flush(true); - } catch (IOException e) { - // Set error flag - error = true; - } - - } else if (actionCode == ActionCode.DISABLE_SWALLOW_INPUT) { - // TODO: Do not swallow request input but - // make sure we are closing the connection - error = true; - - } else if (actionCode == ActionCode.CLOSE) { - // Close - // End the processing of the current request, and stop any further - // transactions with the client - - try { - finish(); - } catch (IOException e) { - // Set error flag - error = true; - } - - } else if (actionCode == ActionCode.REQ_SSL_ATTRIBUTE ) { - - if (!certificates.isNull()) { - ByteChunk certData = certificates.getByteChunk(); - X509Certificate jsseCerts[] = null; - ByteArrayInputStream bais = - new ByteArrayInputStream(certData.getBytes(), - certData.getStart(), - certData.getLength()); - // Fill the elements. - try { - CertificateFactory cf; - if (clientCertProvider == null) { - cf = CertificateFactory.getInstance("X.509"); - } else { - cf = CertificateFactory.getInstance("X.509", - clientCertProvider); - } - while(bais.available() > 0) { - X509Certificate cert = (X509Certificate) - cf.generateCertificate(bais); - if(jsseCerts == null) { - jsseCerts = new X509Certificate[1]; - jsseCerts[0] = cert; - } else { - X509Certificate [] temp = new X509Certificate[jsseCerts.length+1]; - System.arraycopy(jsseCerts,0,temp,0,jsseCerts.length); - temp[jsseCerts.length] = cert; - jsseCerts = temp; - } - } - } catch (java.security.cert.CertificateException e) { - getLog().error(sm.getString("ajpprocessor.certs.fail"), e); - return; - } catch (NoSuchProviderException e) { - getLog().error(sm.getString("ajpprocessor.certs.fail"), e); - return; - } - request.setAttribute(SSLSupport.CERTIFICATE_KEY, jsseCerts); - } - - } else if (actionCode == ActionCode.REQ_HOST_ATTRIBUTE) { - - // Get remote host name using a DNS resolution - if (request.remoteHost().isNull()) { - try { - request.remoteHost().setString(InetAddress.getByName - (request.remoteAddr().toString()).getHostName()); - } catch (IOException iex) { - // Ignore - } - } - - } else if (actionCode == ActionCode.REQ_LOCAL_ADDR_ATTRIBUTE) { - - // Copy from local name for now, which should simply be an address - request.localAddr().setString(request.localName().toString()); - - } else if (actionCode == ActionCode.REQ_SET_BODY_REPLAY) { - - // Set the given bytes as the content - ByteChunk bc = (ByteChunk) param; - int length = bc.getLength(); - bodyBytes.setBytes(bc.getBytes(), bc.getStart(), length); - request.setContentLength(length); - first = false; - empty = false; - replay = true; - - } else if (actionCode == ActionCode.ASYNC_START) { - asyncStateMachine.asyncStart((AsyncContextCallback) param); - } else if (actionCode == ActionCode.ASYNC_DISPATCHED) { - asyncStateMachine.asyncDispatched(); - } else if (actionCode == ActionCode.ASYNC_TIMEOUT) { - AtomicBoolean result = (AtomicBoolean) param; - result.set(asyncStateMachine.asyncTimeout()); - } else if (actionCode == ActionCode.ASYNC_RUN) { - asyncStateMachine.asyncRun((Runnable) param); - } else if (actionCode == ActionCode.ASYNC_ERROR) { - asyncStateMachine.asyncError(); - } else if (actionCode == ActionCode.ASYNC_IS_STARTED) { - ((AtomicBoolean) param).set(asyncStateMachine.isAsyncStarted()); - } else if (actionCode == ActionCode.ASYNC_IS_DISPATCHING) { - ((AtomicBoolean) param).set(asyncStateMachine.isAsyncDispatching()); - } else if (actionCode == ActionCode.ASYNC_IS_ASYNC) { - ((AtomicBoolean) param).set(asyncStateMachine.isAsync()); - } else if (actionCode == ActionCode.ASYNC_IS_TIMINGOUT) { - ((AtomicBoolean) param).set(asyncStateMachine.isAsyncTimingOut()); - } else { - actionInternal(actionCode, param); - } - } - - // Methods called by action() - protected abstract void actionInternal(ActionCode actionCode, Object param); - protected abstract void flush(boolean tbd) throws IOException; - protected abstract void finish() throws IOException; - - - public SocketState asyncDispatch(SocketStatus status) { - - RequestInfo rp = request.getRequestProcessor(); - try { - rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); - error = !adapter.asyncDispatch(request, response, status); - } catch (InterruptedIOException e) { - error = true; - } catch (Throwable t) { - ExceptionUtils.handleThrowable(t); - getLog().error(sm.getString("http11processor.request.process"), t); - error = true; - } finally { - if (error) { - // 500 - Internal Server Error - response.setStatus(500); - adapter.log(request, response, 0); - } - } - - rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); - - if (isAsync()) { - if (error) { - request.updateCounters(); - return SocketState.CLOSED; - } else { - return SocketState.LONG; - } - } else { - request.updateCounters(); - if (error) { - return SocketState.CLOSED; - } else { - return SocketState.OPEN; - } - } - } - - - public void recycle() { - asyncStateMachine.recycle(); - - // Recycle Request object - first = true; - endOfStream = false; - empty = true; - replay = false; - finished = false; - request.recycle(); - response.recycle(); - certificates.recycle(); - byteCount = 0; - } - - // ------------------------------------------------------ Protected Methods - - - /** - * After reading the request headers, we have to setup the request filters. - */ - protected void prepareRequest() { - - // Translate the HTTP method code to a String. - byte methodCode = requestHeaderMessage.getByte(); - if (methodCode != Constants.SC_M_JK_STORED) { - String methodName = Constants.getMethodForCode(methodCode - 1); - request.method().setString(methodName); - } - - requestHeaderMessage.getBytes(request.protocol()); - requestHeaderMessage.getBytes(request.requestURI()); - - requestHeaderMessage.getBytes(request.remoteAddr()); - requestHeaderMessage.getBytes(request.remoteHost()); - requestHeaderMessage.getBytes(request.localName()); - request.setLocalPort(requestHeaderMessage.getInt()); - - boolean isSSL = requestHeaderMessage.getByte() != 0; - if (isSSL) { - request.scheme().setString("https"); - } - - // Decode headers - MimeHeaders headers = request.getMimeHeaders(); - - int hCount = requestHeaderMessage.getInt(); - for(int i = 0 ; i < hCount ; i++) { - String hName = null; - - // Header names are encoded as either an integer code starting - // with 0xA0, or as a normal string (in which case the first - // two bytes are the length). - int isc = requestHeaderMessage.peekInt(); - int hId = isc & 0xFF; - - MessageBytes vMB = null; - isc &= 0xFF00; - if(0xA000 == isc) { - requestHeaderMessage.getInt(); // To advance the read position - hName = Constants.getHeaderForCode(hId - 1); - vMB = headers.addValue(hName); - } else { - // reset hId -- if the header currently being read - // happens to be 7 or 8 bytes long, the code below - // will think it's the content-type header or the - // content-length header - SC_REQ_CONTENT_TYPE=7, - // SC_REQ_CONTENT_LENGTH=8 - leading to unexpected - // behaviour. see bug 5861 for more information. - hId = -1; - requestHeaderMessage.getBytes(tmpMB); - ByteChunk bc = tmpMB.getByteChunk(); - vMB = headers.addValue(bc.getBuffer(), - bc.getStart(), bc.getLength()); - } - - requestHeaderMessage.getBytes(vMB); - - if (hId == Constants.SC_REQ_CONTENT_LENGTH || - (hId == -1 && tmpMB.equalsIgnoreCase("Content-Length"))) { - // just read the content-length header, so set it - long cl = vMB.getLong(); - if(cl < Integer.MAX_VALUE) - request.setContentLength( (int)cl ); - } else if (hId == Constants.SC_REQ_CONTENT_TYPE || - (hId == -1 && tmpMB.equalsIgnoreCase("Content-Type"))) { - // just read the content-type header, so set it - ByteChunk bchunk = vMB.getByteChunk(); - request.contentType().setBytes(bchunk.getBytes(), - bchunk.getOffset(), - bchunk.getLength()); - } - } - - // Decode extra attributes - boolean secret = false; - byte attributeCode; - while ((attributeCode = requestHeaderMessage.getByte()) - != Constants.SC_A_ARE_DONE) { - - switch (attributeCode) { - - case Constants.SC_A_REQ_ATTRIBUTE : - requestHeaderMessage.getBytes(tmpMB); - String n = tmpMB.toString(); - requestHeaderMessage.getBytes(tmpMB); - String v = tmpMB.toString(); - /* - * AJP13 misses to forward the remotePort. - * Allow the AJP connector to add this info via - * a private request attribute. - * We will accept the forwarded data as the remote port, - * and remove it from the public list of request attributes. - */ - if(n.equals(Constants.SC_A_REQ_REMOTE_PORT)) { - try { - request.setRemotePort(Integer.parseInt(v)); - } catch (NumberFormatException nfe) { - // Ignore invalid value - } - } else { - request.setAttribute(n, v ); - } - break; - - case Constants.SC_A_CONTEXT : - requestHeaderMessage.getBytes(tmpMB); - // nothing - break; - - case Constants.SC_A_SERVLET_PATH : - requestHeaderMessage.getBytes(tmpMB); - // nothing - break; - - case Constants.SC_A_REMOTE_USER : - if (tomcatAuthentication) { - // ignore server - requestHeaderMessage.getBytes(tmpMB); - } else { - requestHeaderMessage.getBytes(request.getRemoteUser()); - } - break; - - case Constants.SC_A_AUTH_TYPE : - if (tomcatAuthentication) { - // ignore server - requestHeaderMessage.getBytes(tmpMB); - } else { - requestHeaderMessage.getBytes(request.getAuthType()); - } - break; - - case Constants.SC_A_QUERY_STRING : - requestHeaderMessage.getBytes(request.queryString()); - break; - - case Constants.SC_A_JVM_ROUTE : - requestHeaderMessage.getBytes(request.instanceId()); - break; - - case Constants.SC_A_SSL_CERT : - request.scheme().setString("https"); - // SSL certificate extraction is lazy, moved to JkCoyoteHandler - requestHeaderMessage.getBytes(certificates); - break; - - case Constants.SC_A_SSL_CIPHER : - request.scheme().setString("https"); - requestHeaderMessage.getBytes(tmpMB); - request.setAttribute(SSLSupport.CIPHER_SUITE_KEY, - tmpMB.toString()); - break; - - case Constants.SC_A_SSL_SESSION : - request.scheme().setString("https"); - requestHeaderMessage.getBytes(tmpMB); - request.setAttribute(SSLSupport.SESSION_ID_KEY, - tmpMB.toString()); - break; - - case Constants.SC_A_SSL_KEY_SIZE : - request.setAttribute(SSLSupport.KEY_SIZE_KEY, - Integer.valueOf(requestHeaderMessage.getInt())); - break; - - case Constants.SC_A_STORED_METHOD: - requestHeaderMessage.getBytes(request.method()); - break; - - case Constants.SC_A_SECRET: - requestHeaderMessage.getBytes(tmpMB); - if (requiredSecret != null) { - secret = true; - if (!tmpMB.equals(requiredSecret)) { - response.setStatus(403); - adapter.log(request, response, 0); - error = true; - } - } - break; - - default: - // Ignore unknown attribute for backward compatibility - break; - - } - - } - - // Check if secret was submitted if required - if ((requiredSecret != null) && !secret) { - response.setStatus(403); - adapter.log(request, response, 0); - error = true; - } - - // Check for a full URI (including protocol://host:port/) - ByteChunk uriBC = request.requestURI().getByteChunk(); - if (uriBC.startsWithIgnoreCase("http", 0)) { - - int pos = uriBC.indexOf("://", 0, 3, 4); - int uriBCStart = uriBC.getStart(); - int slashPos = -1; - if (pos != -1) { - byte[] uriB = uriBC.getBytes(); - slashPos = uriBC.indexOf('/', pos + 3); - if (slashPos == -1) { - slashPos = uriBC.getLength(); - // Set URI as "/" - request.requestURI().setBytes - (uriB, uriBCStart + pos + 1, 1); - } else { - request.requestURI().setBytes - (uriB, uriBCStart + slashPos, - uriBC.getLength() - slashPos); - } - MessageBytes hostMB = headers.setValue("host"); - hostMB.setBytes(uriB, uriBCStart + pos + 3, - slashPos - pos - 3); - } - - } - - MessageBytes valueMB = request.getMimeHeaders().getValue("host"); - parseHost(valueMB); - - } - - - /** - * Parse host. - */ - protected void parseHost(MessageBytes valueMB) { - - if (valueMB == null || valueMB.isNull()) { - // HTTP/1.0 - request.setServerPort(request.getLocalPort()); - try { - request.serverName().duplicate(request.localName()); - } catch (IOException e) { - response.setStatus(400); - adapter.log(request, response, 0); - error = true; - } - return; - } - - ByteChunk valueBC = valueMB.getByteChunk(); - byte[] valueB = valueBC.getBytes(); - int valueL = valueBC.getLength(); - int valueS = valueBC.getStart(); - int colonPos = -1; - if (hostNameC.length < valueL) { - hostNameC = new char[valueL]; - } - - boolean ipv6 = (valueB[valueS] == '['); - boolean bracketClosed = false; - for (int i = 0; i < valueL; i++) { - char b = (char) valueB[i + valueS]; - hostNameC[i] = b; - if (b == ']') { - bracketClosed = true; - } else if (b == ':') { - if (!ipv6 || bracketClosed) { - colonPos = i; - break; - } - } - } - - if (colonPos < 0) { - if (request.scheme().equalsIgnoreCase("https")) { - // 443 - Default HTTPS port - request.setServerPort(443); - } else { - // 80 - Default HTTTP port - request.setServerPort(80); - } - request.serverName().setChars(hostNameC, 0, valueL); - } else { - - request.serverName().setChars(hostNameC, 0, colonPos); - - int port = 0; - int mult = 1; - for (int i = valueL - 1; i > colonPos; i--) { - int charValue = HexUtils.getDec(valueB[i + valueS]); - if (charValue == -1) { - // Invalid character - error = true; - // 400 - Bad request - response.setStatus(400); - adapter.log(request, response, 0); - break; - } - port = port + (charValue * mult); - mult = 10 * mult; - } - request.setServerPort(port); - } - } - - - /** - * When committing the response, we have to validate the set of headers, as - * well as setup the response filters. - */ - protected void prepareResponse() - throws IOException { - - response.setCommitted(true); - - responseHeaderMessage.reset(); - responseHeaderMessage.appendByte(Constants.JK_AJP13_SEND_HEADERS); - - // HTTP header contents - responseHeaderMessage.appendInt(response.getStatus()); - String message = null; - if (org.apache.coyote.Constants.USE_CUSTOM_STATUS_MSG_IN_HEADER && - HttpMessages.isSafeInHttpHeader(response.getMessage())) { - message = response.getMessage(); - } - if (message == null){ - message = HttpMessages.getMessage(response.getStatus()); - } - if (message == null) { - // mod_jk + httpd 2.x fails with a null status message - bug 45026 - message = Integer.toString(response.getStatus()); - } - tmpMB.setString(message); - responseHeaderMessage.appendBytes(tmpMB); - - // Special headers - MimeHeaders headers = response.getMimeHeaders(); - String contentType = response.getContentType(); - if (contentType != null) { - headers.setValue("Content-Type").setString(contentType); - } - String contentLanguage = response.getContentLanguage(); - if (contentLanguage != null) { - headers.setValue("Content-Language").setString(contentLanguage); - } - long contentLength = response.getContentLengthLong(); - if (contentLength >= 0) { - headers.setValue("Content-Length").setLong(contentLength); - } - - // Other headers - int numHeaders = headers.size(); - responseHeaderMessage.appendInt(numHeaders); - for (int i = 0; i < numHeaders; i++) { - MessageBytes hN = headers.getName(i); - int hC = Constants.getResponseAjpIndex(hN.toString()); - if (hC > 0) { - responseHeaderMessage.appendInt(hC); - } - else { - responseHeaderMessage.appendBytes(hN); - } - MessageBytes hV=headers.getValue(i); - responseHeaderMessage.appendBytes(hV); - } - - // Write to buffer - responseHeaderMessage.end(); - output(responseHeaderMessage.getBuffer(), 0, - responseHeaderMessage.getLen()); - } - - // Methods called by prepareResponse() - protected abstract void output(byte[] src, int offset, int length) - throws IOException; - - - // ------------------------------------- InputStreamInputBuffer Inner Class - - - /** - * This class is an input buffer which will read its data from an input - * stream. - */ - protected class SocketInputBuffer - implements InputBuffer { - - - /** - * Read bytes into the specified chunk. - */ - @Override - public int doRead(ByteChunk chunk, Request req ) - throws IOException { - - if (endOfStream) { - return -1; - } - if (first && req.getContentLengthLong() > 0) { - // Handle special first-body-chunk - if (!receive()) { - return 0; - } - } else if (empty) { - if (!refillReadBuffer()) { - return -1; - } - } - ByteChunk bc = bodyBytes.getByteChunk(); - chunk.setBytes(bc.getBuffer(), bc.getStart(), bc.getLength()); - empty = true; - return chunk.getLength(); - - } - - } - - // Methods used by SocketInputBuffer - protected abstract boolean receive() throws IOException; - protected abstract boolean refillReadBuffer() throws IOException; + /** + * Send an action to the connector. + * + * @param actionCode Type of the action + * @param param Action parameter + */ + @Override + public final void action(ActionCode actionCode, Object param) { + + if (actionCode == ActionCode.COMMIT) { + + if (response.isCommitted()) + return; + + // Validate and write response headers + try { + prepareResponse(); + } catch (IOException e) { + // Set error flag + error = true; + } + + try { + flush(false); + } catch (IOException e) { + // Set error flag + error = true; + } + + } else if (actionCode == ActionCode.CLIENT_FLUSH) { + + if (!response.isCommitted()) { + // Validate and write response headers + try { + prepareResponse(); + } catch (IOException e) { + // Set error flag + error = true; + return; + } + } + + try { + flush(true); + } catch (IOException e) { + // Set error flag + error = true; + } + + } else if (actionCode == ActionCode.DISABLE_SWALLOW_INPUT) { + // TODO: Do not swallow request input but + // make sure we are closing the connection + error = true; + + } else if (actionCode == ActionCode.CLOSE) { + // Close + // End the processing of the current request, and stop any further + // transactions with the client + + try { + finish(); + } catch (IOException e) { + // Set error flag + error = true; + } + + } else if (actionCode == ActionCode.REQ_SSL_ATTRIBUTE ) { + + if (!certificates.isNull()) { + ByteChunk certData = certificates.getByteChunk(); + X509Certificate jsseCerts[] = null; + ByteArrayInputStream bais = + new ByteArrayInputStream(certData.getBytes(), + certData.getStart(), + certData.getLength()); + // Fill the elements. + try { + CertificateFactory cf; + if (clientCertProvider == null) { + cf = CertificateFactory.getInstance("X.509"); + } else { + cf = CertificateFactory.getInstance("X.509", + clientCertProvider); + } + while(bais.available() > 0) { + X509Certificate cert = (X509Certificate) + cf.generateCertificate(bais); + if(jsseCerts == null) { + jsseCerts = new X509Certificate[1]; + jsseCerts[0] = cert; + } else { + X509Certificate [] temp = new X509Certificate[jsseCerts.length+1]; + System.arraycopy(jsseCerts,0,temp,0,jsseCerts.length); + temp[jsseCerts.length] = cert; + jsseCerts = temp; + } + } + } catch (java.security.cert.CertificateException e) { + getLog().error(sm.getString("ajpprocessor.certs.fail"), e); + return; + } catch (NoSuchProviderException e) { + getLog().error(sm.getString("ajpprocessor.certs.fail"), e); + return; + } + request.setAttribute(SSLSupport.CERTIFICATE_KEY, jsseCerts); + } + + } else if (actionCode == ActionCode.REQ_HOST_ATTRIBUTE) { + + // Get remote host name using a DNS resolution + if (request.remoteHost().isNull()) { + try { + request.remoteHost().setString(InetAddress.getByName + (request.remoteAddr().toString()).getHostName()); + } catch (IOException iex) { + // Ignore + } + } + + } else if (actionCode == ActionCode.REQ_LOCAL_ADDR_ATTRIBUTE) { + + // Copy from local name for now, which should simply be an address + request.localAddr().setString(request.localName().toString()); + + } else if (actionCode == ActionCode.REQ_SET_BODY_REPLAY) { + + // Set the given bytes as the content + ByteChunk bc = (ByteChunk) param; + int length = bc.getLength(); + bodyBytes.setBytes(bc.getBytes(), bc.getStart(), length); + request.setContentLength(length); + first = false; + empty = false; + replay = true; + + } else if (actionCode == ActionCode.ASYNC_START) { + asyncStateMachine.asyncStart((AsyncContextCallback) param); + } else if (actionCode == ActionCode.ASYNC_DISPATCHED) { + asyncStateMachine.asyncDispatched(); + } else if (actionCode == ActionCode.ASYNC_TIMEOUT) { + AtomicBoolean result = (AtomicBoolean) param; + result.set(asyncStateMachine.asyncTimeout()); + } else if (actionCode == ActionCode.ASYNC_RUN) { + asyncStateMachine.asyncRun((Runnable) param); + } else if (actionCode == ActionCode.ASYNC_ERROR) { + asyncStateMachine.asyncError(); + } else if (actionCode == ActionCode.ASYNC_IS_STARTED) { + ((AtomicBoolean) param).set(asyncStateMachine.isAsyncStarted()); + } else if (actionCode == ActionCode.ASYNC_IS_DISPATCHING) { + ((AtomicBoolean) param).set(asyncStateMachine.isAsyncDispatching()); + } else if (actionCode == ActionCode.ASYNC_IS_ASYNC) { + ((AtomicBoolean) param).set(asyncStateMachine.isAsync()); + } else if (actionCode == ActionCode.ASYNC_IS_TIMINGOUT) { + ((AtomicBoolean) param).set(asyncStateMachine.isAsyncTimingOut()); + } else { + actionInternal(actionCode, param); + } + } + + // Methods called by action() + protected abstract void actionInternal(ActionCode actionCode, Object param); + protected abstract void flush(boolean tbd) throws IOException; + protected abstract void finish() throws IOException; + + + public SocketState asyncDispatch(SocketStatus status) { + + RequestInfo rp = request.getRequestProcessor(); + try { + rp.setStage(org.apache.coyote.Constants.STAGE_SERVICE); + error = !adapter.asyncDispatch(request, response, status); + } catch (InterruptedIOException e) { + error = true; + } catch (Throwable t) { + ExceptionUtils.handleThrowable(t); + getLog().error(sm.getString("http11processor.request.process"), t); + error = true; + } finally { + if (error) { + // 500 - Internal Server Error + response.setStatus(500); + adapter.log(request, response, 0); + } + } + + rp.setStage(org.apache.coyote.Constants.STAGE_ENDED); + + if (isAsync()) { + if (error) { + request.updateCounters(); + return SocketState.CLOSED; + } else { + return SocketState.LONG; + } + } else { + request.updateCounters(); + if (error) { + return SocketState.CLOSED; + } else { + return SocketState.OPEN; + } + } + } + + + public void recycle() { + asyncStateMachine.recycle(); + + // Recycle Request object + first = true; + endOfStream = false; + empty = true; + replay = false; + finished = false; + request.recycle(); + response.recycle(); + certificates.recycle(); + byteCount = 0; + } + + // ------------------------------------------------------ Protected Methods + + + /** + * After reading the request headers, we have to setup the request filters. + */ + protected void prepareRequest() { + + // Translate the HTTP method code to a String. + byte methodCode = requestHeaderMessage.getByte(); + if (methodCode != Constants.SC_M_JK_STORED) { + String methodName = Constants.getMethodForCode(methodCode - 1); + request.method().setString(methodName); + } + + requestHeaderMessage.getBytes(request.protocol()); + requestHeaderMessage.getBytes(request.requestURI()); + + requestHeaderMessage.getBytes(request.remoteAddr()); + requestHeaderMessage.getBytes(request.remoteHost()); + requestHeaderMessage.getBytes(request.localName()); + request.setLocalPort(requestHeaderMessage.getInt()); + + boolean isSSL = requestHeaderMessage.getByte() != 0; + if (isSSL) { + request.scheme().setString("https"); + } + + // Decode headers + MimeHeaders headers = request.getMimeHeaders(); + + int hCount = requestHeaderMessage.getInt(); + for(int i = 0 ; i < hCount ; i++) { + String hName = null; + + // Header names are encoded as either an integer code starting + // with 0xA0, or as a normal string (in which case the first + // two bytes are the length). + int isc = requestHeaderMessage.peekInt(); + int hId = isc & 0xFF; + + MessageBytes vMB = null; + isc &= 0xFF00; + if(0xA000 == isc) { + requestHeaderMessage.getInt(); // To advance the read position + hName = Constants.getHeaderForCode(hId - 1); + vMB = headers.addValue(hName); + } else { + // reset hId -- if the header currently being read + // happens to be 7 or 8 bytes long, the code below + // will think it's the content-type header or the + // content-length header - SC_REQ_CONTENT_TYPE=7, + // SC_REQ_CONTENT_LENGTH=8 - leading to unexpected + // behaviour. see bug 5861 for more information. + hId = -1; + requestHeaderMessage.getBytes(tmpMB); + ByteChunk bc = tmpMB.getByteChunk(); + vMB = headers.addValue(bc.getBuffer(), + bc.getStart(), bc.getLength()); + } + + requestHeaderMessage.getBytes(vMB); + + if (hId == Constants.SC_REQ_CONTENT_LENGTH || + (hId == -1 && tmpMB.equalsIgnoreCase("Content-Length"))) { + // just read the content-length header, so set it + long cl = vMB.getLong(); + if(cl < Integer.MAX_VALUE) + request.setContentLength( (int)cl ); + } else if (hId == Constants.SC_REQ_CONTENT_TYPE || + (hId == -1 && tmpMB.equalsIgnoreCase("Content-Type"))) { + // just read the content-type header, so set it + ByteChunk bchunk = vMB.getByteChunk(); + request.contentType().setBytes(bchunk.getBytes(), + bchunk.getOffset(), + bchunk.getLength()); + } + } + + // Decode extra attributes + boolean secret = false; + byte attributeCode; + while ((attributeCode = requestHeaderMessage.getByte()) + != Constants.SC_A_ARE_DONE) { + + switch (attributeCode) { + + case Constants.SC_A_REQ_ATTRIBUTE : + requestHeaderMessage.getBytes(tmpMB); + String n = tmpMB.toString(); + requestHeaderMessage.getBytes(tmpMB); + String v = tmpMB.toString(); + /* + * AJP13 misses to forward the remotePort. + * Allow the AJP connector to add this info via + * a private request attribute. + * We will accept the forwarded data as the remote port, + * and remove it from the public list of request attributes. + */ + if(n.equals(Constants.SC_A_REQ_REMOTE_PORT)) { + try { + request.setRemotePort(Integer.parseInt(v)); + } catch (NumberFormatException nfe) { + // Ignore invalid value + } + } else { + request.setAttribute(n, v ); + } + break; + + case Constants.SC_A_CONTEXT : + requestHeaderMessage.getBytes(tmpMB); + // nothing + break; + + case Constants.SC_A_SERVLET_PATH : + requestHeaderMessage.getBytes(tmpMB); + // nothing + break; + + case Constants.SC_A_REMOTE_USER : + if (tomcatAuthentication) { + // ignore server + requestHeaderMessage.getBytes(tmpMB); + } else { + requestHeaderMessage.getBytes(request.getRemoteUser()); + } + break; + + case Constants.SC_A_AUTH_TYPE : + if (tomcatAuthentication) { + // ignore server + requestHeaderMessage.getBytes(tmpMB); + } else { + requestHeaderMessage.getBytes(request.getAuthType()); + } + break; + + case Constants.SC_A_QUERY_STRING : + requestHeaderMessage.getBytes(request.queryString()); + break; + + case Constants.SC_A_JVM_ROUTE : + requestHeaderMessage.getBytes(request.instanceId()); + break; + + case Constants.SC_A_SSL_CERT : + request.scheme().setString("https"); + // SSL certificate extraction is lazy, moved to JkCoyoteHandler + requestHeaderMessage.getBytes(certificates); + break; + + case Constants.SC_A_SSL_CIPHER : + request.scheme().setString("https"); + requestHeaderMessage.getBytes(tmpMB); + request.setAttribute(SSLSupport.CIPHER_SUITE_KEY, + tmpMB.toString()); + break; + + case Constants.SC_A_SSL_SESSION : + request.scheme().setString("https"); + requestHeaderMessage.getBytes(tmpMB); + request.setAttribute(SSLSupport.SESSION_ID_KEY, + tmpMB.toString()); + break; + + case Constants.SC_A_SSL_KEY_SIZE : + request.setAttribute(SSLSupport.KEY_SIZE_KEY, + Integer.valueOf(requestHeaderMessage.getInt())); + break; + + case Constants.SC_A_STORED_METHOD: + requestHeaderMessage.getBytes(request.method()); + break; + + case Constants.SC_A_SECRET: + requestHeaderMessage.getBytes(tmpMB); + if (requiredSecret != null) { + secret = true; + if (!tmpMB.equals(requiredSecret)) { + response.setStatus(403); + adapter.log(request, response, 0); + error = true; + } + } + break; + + default: + // Ignore unknown attribute for backward compatibility + break; + + } + + } + + // Check if secret was submitted if required + if ((requiredSecret != null) && !secret) { + response.setStatus(403); + adapter.log(request, response, 0); + error = true; + } + + // Check for a full URI (including protocol://host:port/) + ByteChunk uriBC = request.requestURI().getByteChunk(); + if (uriBC.startsWithIgnoreCase("http", 0)) { + + int pos = uriBC.indexOf("://", 0, 3, 4); + int uriBCStart = uriBC.getStart(); + int slashPos = -1; + if (pos != -1) { + byte[] uriB = uriBC.getBytes(); + slashPos = uriBC.indexOf('/', pos + 3); + if (slashPos == -1) { + slashPos = uriBC.getLength(); + // Set URI as "/" + request.requestURI().setBytes + (uriB, uriBCStart + pos + 1, 1); + } else { + request.requestURI().setBytes + (uriB, uriBCStart + slashPos, + uriBC.getLength() - slashPos); + } + MessageBytes hostMB = headers.setValue("host"); + hostMB.setBytes(uriB, uriBCStart + pos + 3, + slashPos - pos - 3); + } + + } + + MessageBytes valueMB = request.getMimeHeaders().getValue("host"); + parseHost(valueMB); + + } + + + /** + * Parse host. + */ + protected void parseHost(MessageBytes valueMB) { + + if (valueMB == null || valueMB.isNull()) { + // HTTP/1.0 + request.setServerPort(request.getLocalPort()); + try { + request.serverName().duplicate(request.localName()); + } catch (IOException e) { + response.setStatus(400); + adapter.log(request, response, 0); + error = true; + } + return; + } + + ByteChunk valueBC = valueMB.getByteChunk(); + byte[] valueB = valueBC.getBytes(); + int valueL = valueBC.getLength(); + int valueS = valueBC.getStart(); + int colonPos = -1; + if (hostNameC.length < valueL) { + hostNameC = new char[valueL]; + } + + boolean ipv6 = (valueB[valueS] == '['); + boolean bracketClosed = false; + for (int i = 0; i < valueL; i++) { + char b = (char) valueB[i + valueS]; + hostNameC[i] = b; + if (b == ']') { + bracketClosed = true; + } else if (b == ':') { + if (!ipv6 || bracketClosed) { + colonPos = i; + break; + } + } + } + + if (colonPos < 0) { + if (request.scheme().equalsIgnoreCase("https")) { + // 443 - Default HTTPS port + request.setServerPort(443); + } else { + // 80 - Default HTTTP port + request.setServerPort(80); + } + request.serverName().setChars(hostNameC, 0, valueL); + } else { + + request.serverName().setChars(hostNameC, 0, colonPos); + + int port = 0; + int mult = 1; + for (int i = valueL - 1; i > colonPos; i--) { + int charValue = HexUtils.getDec(valueB[i + valueS]); + if (charValue == -1) { + // Invalid character + error = true; + // 400 - Bad request + response.setStatus(400); + adapter.log(request, response, 0); + break; + } + port = port + (charValue * mult); + mult = 10 * mult; + } + request.setServerPort(port); + } + } + + + /** + * When committing the response, we have to validate the set of headers, as + * well as setup the response filters. + */ + protected void prepareResponse() + throws IOException { + + response.setCommitted(true); + + responseHeaderMessage.reset(); + responseHeaderMessage.appendByte(Constants.JK_AJP13_SEND_HEADERS); + + // HTTP header contents + responseHeaderMessage.appendInt(response.getStatus()); + String message = null; + if (org.apache.coyote.Constants.USE_CUSTOM_STATUS_MSG_IN_HEADER && + HttpMessages.isSafeInHttpHeader(response.getMessage())) { + message = response.getMessage(); + } + if (message == null){ + message = HttpMessages.getMessage(response.getStatus()); + } + if (message == null) { + // mod_jk + httpd 2.x fails with a null status message - bug 45026 + message = Integer.toString(response.getStatus()); + } + tmpMB.setString(message); + responseHeaderMessage.appendBytes(tmpMB); + + // Special headers + MimeHeaders headers = response.getMimeHeaders(); + String contentType = response.getContentType(); + if (contentType != null) { + headers.setValue("Content-Type").setString(contentType); + } + String contentLanguage = response.getContentLanguage(); + if (contentLanguage != null) { + headers.setValue("Content-Language").setString(contentLanguage); + } + long contentLength = response.getContentLengthLong(); + if (contentLength >= 0) { + headers.setValue("Content-Length").setLong(contentLength); + } + + // Other headers + int numHeaders = headers.size(); + responseHeaderMessage.appendInt(numHeaders); + for (int i = 0; i < numHeaders; i++) { + MessageBytes hN = headers.getName(i); + int hC = Constants.getResponseAjpIndex(hN.toString()); + if (hC > 0) { + responseHeaderMessage.appendInt(hC); + } + else { + responseHeaderMessage.appendBytes(hN); + } + MessageBytes hV=headers.getValue(i); + responseHeaderMessage.appendBytes(hV); + } + + // Write to buffer + responseHeaderMessage.end(); + output(responseHeaderMessage.getBuffer(), 0, + responseHeaderMessage.getLen()); + } + + // Methods called by prepareResponse() + protected abstract void output(byte[] src, int offset, int length) + throws IOException; + + + // ------------------------------------- InputStreamInputBuffer Inner Class + + + /** + * This class is an input buffer which will read its data from an input + * stream. + */ + protected class SocketInputBuffer + implements InputBuffer { + + + /** + * Read bytes into the specified chunk. + */ + @Override + public int doRead(ByteChunk chunk, Request req ) + throws IOException { + + if (endOfStream) { + return -1; + } + if (first && req.getContentLengthLong() > 0) { + // Handle special first-body-chunk + if (!receive()) { + return 0; + } + } else if (empty) { + if (!refillReadBuffer()) { + return -1; + } + } + ByteChunk bc = bodyBytes.getByteChunk(); + chunk.setBytes(bc.getBuffer(), bc.getStart(), bc.getLength()); + empty = true; + return chunk.getLength(); + + } + + } + + // Methods used by SocketInputBuffer + protected abstract boolean receive() throws IOException; + protected abstract boolean refillReadBuffer() throws IOException; } --------------------------------------------------------------------- To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org For additional commands, e-mail: dev-h...@tomcat.apache.org