summaryrefslogtreecommitdiffstats
path: root/simple/simple-http/src/main/java/org/simpleframework/http/message/UpdateConsumer.java
diff options
context:
space:
mode:
Diffstat (limited to 'simple/simple-http/src/main/java/org/simpleframework/http/message/UpdateConsumer.java')
-rw-r--r--simple/simple-http/src/main/java/org/simpleframework/http/message/UpdateConsumer.java143
1 files changed, 143 insertions, 0 deletions
diff --git a/simple/simple-http/src/main/java/org/simpleframework/http/message/UpdateConsumer.java b/simple/simple-http/src/main/java/org/simpleframework/http/message/UpdateConsumer.java
new file mode 100644
index 0000000..5d514c9
--- /dev/null
+++ b/simple/simple-http/src/main/java/org/simpleframework/http/message/UpdateConsumer.java
@@ -0,0 +1,143 @@
+/*
+ * UpdateConsumer.java February 2007
+ *
+ * Copyright (C) 2007, Niall Gallagher <niallg@users.sf.net>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package org.simpleframework.http.message;
+
+import java.io.IOException;
+
+import org.simpleframework.transport.ByteCursor;
+
+/**
+ * The <code>UpdateConsumer</code> object is used to create a consumer
+ * that is used to consume and process large bodies. Typically a large
+ * body will be one that is delivered as part of a multipart upload
+ * or as a large form POST. The task of the large consumer is to
+ * consume all the bytes for the body, and reset the cursor after the
+ * last byte that has been send with the body. This ensures that the
+ * next character read from the cursor is the first character of a
+ * HTTP header within the pipeline.
+ *
+ * @author Niall Gallagher
+ */
+public abstract class UpdateConsumer implements BodyConsumer {
+
+ /**
+ * This is an external array used to copy data between buffers.
+ */
+ protected byte[] array;
+
+ /**
+ * This is used to determine whether the consumer has finished.
+ */
+ protected boolean finished;
+
+ /**
+ * Constructor for the <code>UpdateConsumer</code> object. This is
+ * used to create a consumer with a one kilobyte buffer used to
+ * read the contents from the cursor and transfer it to the buffer.
+ */
+ protected UpdateConsumer() {
+ this(2048);
+ }
+
+ /**
+ * Constructor for the <code>UpdateConsumer</code> object. This is
+ * used to create a consumer with a variable size buffer used to
+ * read the contents from the cursor and transfer it to the buffer.
+ *
+ * @param chunk this is the size of the buffer used to read bytes
+ */
+ protected UpdateConsumer(int chunk) {
+ this.array = new byte[chunk];
+ }
+
+ /**
+ * This is used to determine whether the consumer has finished
+ * reading. The consumer is considered finished if it has read a
+ * terminal token or if it has exhausted the stream and can not
+ * read any more. Once finished the consumed bytes can be parsed.
+ *
+ * @return true if the consumer has finished reading its content
+ */
+ public boolean isFinished() {
+ return finished;
+ }
+
+ /**
+ * This method is used to consume bytes from the provided cursor.
+ * Consuming of bytes from the cursor should be done in such a
+ * way that it does not block. So typically only the number of
+ * ready bytes in the <code>ByteCursor</code> object should be
+ * read. If there are no ready bytes then this will return.
+ *
+ * @param cursor used to consume the bytes from the HTTP pipeline
+ */
+ public void consume(ByteCursor cursor) throws IOException {
+ int ready = cursor.ready();
+
+ while(ready > 0) {
+ int size = Math.min(ready, array.length);
+ int count = cursor.read(array, 0, size);
+
+ if(count > 0) {
+ int reset = update(array, 0, count);
+
+ if(reset > 0) {
+ cursor.reset(reset);
+ }
+ }
+ if(finished) {
+ commit(cursor);
+ break;
+ }
+ ready = cursor.ready();
+ }
+ }
+
+ /**
+ * This method can be used to commit the consumer when all data
+ * has been consumed. It is often used to push back some data on
+ * to the cursor so that the next consumer can read valid tokens
+ * from the stream of bytes. If no commit is required then the
+ * default implementation of this will simply return quietly.
+ *
+ * @param cursor this is the cursor used by this consumer
+ */
+ protected void commit(ByteCursor cursor) throws IOException {
+ if(!finished) {
+ throw new IOException("Consumer not finished");
+ }
+ }
+
+ /**
+ * This is used to process the bytes that have been read from the
+ * cursor. Depending on the delimiter used this knows when the
+ * end of the body has been encountered. If the end is encountered
+ * this method must return the number of bytes overflow, and set
+ * the state of the consumer to finished.
+ *
+ * @param array this is a chunk read from the cursor
+ * @param off this is the offset within the array the chunk starts
+ * @param count this is the number of bytes within the array
+ *
+ * @return this returns the number of bytes overflow that is read
+ */
+ protected abstract int update(byte[] array, int off, int count) throws IOException;
+}
+
+