remm 01/09/30 18:20:42
Modified: http11 .cvsignore
http11/src/java/org/apache/coyote/http11 Constants.java
Http11Connector.java InternalOutputBuffer.java
Log:
- Implement the output.
- The last parts to be written are the request processing itself, as well as some
utility components (like the chunking filters).
Revision Changes Path
1.2 +2 -3 jakarta-tomcat-connectors/http11/.cvsignore
Index: .cvsignore
===================================================================
RCS file: /home/cvs/jakarta-tomcat-connectors/http11/.cvsignore,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- .cvsignore 2001/09/17 06:04:00 1.1
+++ .cvsignore 2001/10/01 01:20:42 1.2
@@ -1,3 +1,2 @@
-dist
-build.properties
-target
\ No newline at end of file
+build
+build.properties
\ No newline at end of file
1.2 +6 -0
jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/Constants.java
Index: Constants.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/Constants.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- Constants.java 2001/09/17 06:04:00 1.1
+++ Constants.java 2001/10/01 01:20:42 1.2
@@ -137,4 +137,10 @@
public static final int DEFAULT_HTTP_HEADER_BUFFER_SIZE = 128 * 1024;
+ /**
+ * CRLF.
+ */
+ public static final String CRLF = "\r\n";
+
+
}
1.2 +157 -1
jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/Http11Connector.java
Index: Http11Connector.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/Http11Connector.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- Http11Connector.java 2001/09/17 06:04:00 1.1
+++ Http11Connector.java 2001/10/01 01:20:42 1.2
@@ -84,6 +84,93 @@
public class Http11Connector implements Connector, ActionHook {
+ // ----------------------------------------------------------- Constructors
+
+
+ /**
+ * Default constructor.
+ */
+ public Http11Connector() {
+
+ request = new Request();
+ inputBuffer = new InternalInputBuffer(request);
+ request.setInputBuffer(inputBuffer);
+
+ response = new Response();
+ response.setHook(this);
+ outputBuffer = new InternalOutputBuffer(response);
+ response.setOutputBuffer(outputBuffer);
+
+ }
+
+
+ // ----------------------------------------------------- Instance Variables
+
+
+ /**
+ * Associated adapter.
+ */
+ protected Adapter adapter = null;
+
+
+ /**
+ * Request object.
+ */
+ protected Request request = null;
+
+
+ /**
+ * Response object.
+ */
+ protected Response response = null;
+
+
+ /**
+ * Input.
+ */
+ protected InternalInputBuffer inputBuffer = null;
+
+
+ /**
+ * Output.
+ */
+ protected InternalOutputBuffer outputBuffer = null;
+
+
+ // --------------------------------------------------------- Public Methods
+
+
+ /**
+ * Process pipelined HTTP requests using the specified input and output
+ * streams.
+ *
+ * @param inputStream stream from which the HTTP requests will be read
+ * @param outputStream stream which will be used to output the HTTP
+ * responses
+ * @throws IOException error during an I/O operation
+ */
+ public void process(InputStream input, OutputStream output)
+ throws IOException {
+
+ // Setting up the I/O
+ inputBuffer.setInputStream(input);
+ outputBuffer.setOutputStream(output);
+
+
+
+
+ try {
+ adapter.service(request, response);
+ } catch (Exception e) {
+ ;
+ }
+
+
+
+
+ }
+
+
// ----------------------------------------------------- ActionHook Methods
@@ -94,18 +181,87 @@
* @param param Action parameter
*/
public void action(ActionCode actionCode, Object param) {
+
+ if (actionCode == ActionCode.ACTION_COMMIT) {
+
+ // Commit current response
+
+ // Validate and write response headers
+ prepareResponse();
+
+ } else if (actionCode == ActionCode.ACTION_ACK) {
+
+ // Acknowlege request
+
+ // Send a 100 status back if it makes sense (response not committed
+ // yet, and client specified an expectation for 100-continue)
+
+ } else if (actionCode == ActionCode.ACTION_CLOSE) {
+
+ // Close
+
+ // End the processing of the current request, and stop any further
+ // transactions with the client
+
+ } else if (actionCode == ActionCode.ACTION_RESET) {
+
+ // Reset response
+
+ // Note: This must be called before the response is committed
+
+ } else if (actionCode == ActionCode.ACTION_CUSTOM) {
+
+ // Do nothing
+
+ }
+
}
// ------------------------------------------------------ Connector Methods
+ /**
+ * Set the associated adapter.
+ *
+ * @param adapter the new adapter
+ */
public void setAdapter(Adapter adapter) {
+ this.adapter = adapter;
}
+ /**
+ * Get the associated adapter.
+ *
+ * @return the associated adapter
+ */
public Adapter getAdapter() {
- return null;
+ return adapter;
+ }
+
+
+ // ------------------------------------------------------ Protected Methods
+
+
+ /**
+ * After reading the request headers, we have to setup the request filters.
+ */
+ protected void prepareRequest() {
+
+
+
+ }
+
+
+ /**
+ * When committing the response, we have to validate the set of headers, as
+ * well as setup the response filters.
+ */
+ protected void prepareResponse() {
+
+
+
}
1.2 +233 -24
jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/InternalOutputBuffer.java
Index: InternalOutputBuffer.java
===================================================================
RCS file:
/home/cvs/jakarta-tomcat-connectors/http11/src/java/org/apache/coyote/http11/InternalOutputBuffer.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- InternalOutputBuffer.java 2001/09/17 06:04:00 1.1
+++ InternalOutputBuffer.java 2001/10/01 01:20:42 1.2
@@ -64,9 +64,11 @@
import org.apache.tomcat.util.buf.ByteChunk;
import org.apache.tomcat.util.buf.MessageBytes;
+import org.apache.tomcat.util.http.HttpMessages;
import org.apache.tomcat.util.http.MimeHeaders;
import org.apache.tomcat.util.res.StringManager;
+import org.apache.coyote.ActionCode;
import org.apache.coyote.OutputBuffer;
import org.apache.coyote.Response;
@@ -149,12 +151,6 @@
/**
- * Last valid byte.
- */
- protected int lastValid;
-
-
- /**
* Position in the buffer.
*/
protected int pos;
@@ -289,7 +285,6 @@
outputStream = null;
buf = headerBuffer;
- lastValid = 0;
pos = 0;
lastActiveFilter = 0;
committed = false;
@@ -304,8 +299,7 @@
* consumed. This method only resets all the pointers so that we are ready
* to parse the next HTTP request.
*/
- public void nextRequest()
- throws IOException {
+ public void nextRequest() {
// FIXME: Recycle Response object (or do it elsewhere) ?
@@ -320,7 +314,6 @@
}
// Reset pointers
- lastValid = 0;
pos = 0;
lastActiveFilter = 0;
committed = false;
@@ -330,23 +323,23 @@
/**
- * Send response header.
+ * End request.
+ *
+ * @throws IOException an undelying I/O error occured
*/
- public void sendHeader()
+ public void endRequest()
throws IOException {
- // FIXME
+ if (!committed) {
- committed = true;
-
- }
+ // Send the connector a request for commit. The connector should
+ // then validate the headers, send them (using sendHeader) and
+ // set the filters accordingly.
+ response.action(ActionCode.ACTION_COMMIT, null);
+ commit();
- /**
- * End request.
- */
- public void endRequest()
- throws IOException {
+ }
if (lastActiveFilter > 0) {
// Parsing through the filter list
@@ -355,22 +348,133 @@
}
}
- if (closeChunk.getLength() > 0)
+ if (closeChunk.getLength() > 0) {
outputStream.write(closeChunk.getBytes(), closeChunk.getStart(),
closeChunk.getLength());
+ outputStream.flush();
+ }
+
+ }
+
+
+ // ------------------------------------------------ HTTP/1.1 Output Methods
+
+
+ /**
+ * Send the response status line.
+ */
+ public void sendStatus() {
+
+ // Write protocol name
+ write("HTTP/1.1 ");
+ // Write status code
+ int status = response.getStatus();
+ switch (status) {
+ case 200:
+ write("200");
+ break;
+ case 400:
+ write("400");
+ break;
+ case 404:
+ write("404");
+ break;
+ default:
+ write(status);
+ }
+
+ // Write message
+ write(HttpMessages.getMessage(status));
+
+ // End the response status line
+ write(Constants.CRLF);
+
+ }
+
+
+ /**
+ * Send a header.
+ *
+ * @param name Header name
+ * @param value Header value
+ */
+ public void sendHeader(MessageBytes name, MessageBytes value) {
+
+ write(name);
+ write(": ");
+ write(value);
+ write(Constants.CRLF);
+
+ }
+
+
+ /**
+ * Send a header.
+ *
+ * @param name Header name
+ * @param value Header value
+ */
+ public void sendHeader(ByteChunk name, ByteChunk value) {
+
+ write(name);
+ write(": ");
+ write(value);
+ write(Constants.CRLF);
+
}
+ /**
+ * Send a header.
+ *
+ * @param name Header name
+ * @param value Header value
+ */
+ public void sendHeader(String name, String value) {
+
+ write(name);
+ write(": ");
+ write(value);
+ write(Constants.CRLF);
+
+ }
+
+
+ /**
+ * End the header block.
+ */
+ public void endHeaders() {
+
+ write(Constants.CRLF);
+
+ }
+
+
// --------------------------------------------------- OutputBuffer Methods
+ /**
+ * Write the contents of a byte chunk.
+ *
+ * @param chunk byte chunk
+ * @return number of bytes written
+ * @throws IOException an undelying I/O error occured
+ */
public int doWrite(ByteChunk chunk)
throws IOException {
- if (!committed)
- sendHeader();
+ if (!committed) {
+ // Send the connector a request for commit. The connector should
+ // then validate the headers, send them (using sendHeaders) and
+ // set the filters accordingly.
+ response.action(ActionCode.ACTION_COMMIT, null);
+
+ commit();
+
+ }
+
int n = -1;
if (lastActiveFilter > 0) {
@@ -384,6 +488,111 @@
chunk.getLength());
return n;
+
+ }
+
+
+ // ------------------------------------------------------ Protected Methods
+
+
+ /**
+ * Commit the response.
+ *
+ * @throws IOException an undelying I/O error occured
+ */
+ protected void commit()
+ throws IOException {
+
+ if (pos > 0) {
+ // Sending the response header buffer
+ outputStream.write(buf, 0, pos);
+ outputStream.flush(); // Is it really necessary ?
+ }
+
+ // The response is now committed
+ committed = true;
+ response.setCommitted(true);
+
+ }
+
+
+ /**
+ * This method will write the contents of the specyfied message bytes
+ * buffer to the output stream, without filtering. This method is meant to
+ * be used to write the response header.
+ *
+ * @param mb data to be written
+ */
+ protected void write(MessageBytes mb) {
+
+ mb.toBytes();
+ ByteChunk bc = mb.getByteChunk();
+ if (!bc.isNull()) {
+ // Writing the byte chunk to the output buffer
+ write(bc);
+ } else {
+ // Using toString
+ write(mb.toString());
+ }
+
+ }
+
+
+ /**
+ * This method will write the contents of the specyfied message bytes
+ * buffer to the output stream, without filtering. This method is meant to
+ * be used to write the response header.
+ *
+ * @param bc data to be written
+ */
+ protected void write(ByteChunk bc) {
+
+ // Writing the byte chunk to the output buffer
+ System.arraycopy(bc.getBytes(), bc.getStart(), buf, pos,
+ bc.getLength());
+ pos = pos + bc.getLength();
+
+ }
+
+
+ /**
+ * This method will write the contents of the specyfied String to the
+ * output stream, without filtering. This method is meant to be used to
+ * write the response header.
+ *
+ * @param s data to be written
+ */
+ protected void write(String s) {
+
+ // From the Tomcat 3.3 HTTP/1.0 connector
+ int len = s.length();
+ for (int i = 0; i < len; i++) {
+ char c = s.charAt (i);
+ // Note: This is clearly incorrect for many strings,
+ // but is the only consistent approach within the current
+ // servlet framework. It must suffice until servlet output
+ // streams properly encode their output.
+ if ((c & 0xff00) != 0) {
+ // High order byte must be zero
+ //log("Header character is not iso8859_1, " +
+ //"not supported yet: " + c, Log.ERROR ) ;
+ }
+ buf[pos++] = (byte) c;
+ }
+
+ }
+
+
+ /**
+ * This method will print the specified integer to the output stream,
+ * without filtering. This method is meant to be used to write the
+ * response header.
+ *
+ * @param i data to be written
+ */
+ protected void write(int i) {
+
+ write(String.valueOf(i));
}