You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commons-dev@ws.apache.org by ve...@apache.org on 2009/06/04 23:22:55 UTC

svn commit: r781854 - in /webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter: ./ http/

Author: veithen
Date: Thu Jun  4 21:22:52 2009
New Revision: 781854

URL: http://svn.apache.org/viewvc?rev=781854&view=rev
Log:
* Reverted (my own) change r780724 which would make it more difficult to support keep-alive.
* Some fixes to the chunked decoder/encoder.

Added:
    webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/EntityProcessor.java
      - copied unchanged from r780723, webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/EntityProcessor.java
    webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/ReadOnlyEntityProcessorWrapper.java   (with props)
Removed:
    webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/http/EntityCompletionListener.java
Modified:
    webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/http/ChunkedDecoder.java
    webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/http/ChunkedEncoder.java
    webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/http/HttpFilter.java
    webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/http/IdentityDecoder.java

Added: webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/ReadOnlyEntityProcessorWrapper.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/ReadOnlyEntityProcessorWrapper.java?rev=781854&view=auto
==============================================================================
--- webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/ReadOnlyEntityProcessorWrapper.java (added)
+++ webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/ReadOnlyEntityProcessorWrapper.java Thu Jun  4 21:22:52 2009
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2004,2005 The Apache Software Foundation.
+ *
+ * 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.apache.ws.commons.tcpmon.core.filter;
+
+/**
+ * Wrapper that makes an {@link EntityProcessor} read-only.
+ */
+public class ReadOnlyEntityProcessorWrapper implements EntityProcessor {
+    private final EntityProcessor parent;
+
+    public ReadOnlyEntityProcessorWrapper(EntityProcessor parent) {
+        this.parent = parent;
+    }
+
+    public boolean process(Stream stream) {
+        return parent.process(new ReadOnlyStream(stream));
+    }
+}

Propchange: webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/ReadOnlyEntityProcessorWrapper.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/http/ChunkedDecoder.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/http/ChunkedDecoder.java?rev=781854&r1=781853&r2=781854&view=diff
==============================================================================
--- webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/http/ChunkedDecoder.java (original)
+++ webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/http/ChunkedDecoder.java Thu Jun  4 21:22:52 2009
@@ -16,51 +16,65 @@
 
 package org.apache.ws.commons.tcpmon.core.filter.http;
 
+import org.apache.ws.commons.tcpmon.core.filter.EntityProcessor;
 import org.apache.ws.commons.tcpmon.core.filter.Stream;
 import org.apache.ws.commons.tcpmon.core.filter.StreamException;
-import org.apache.ws.commons.tcpmon.core.filter.StreamFilter;
 import org.apache.ws.commons.tcpmon.core.filter.StreamUtil;
 
 /**
  * Entity processor that processes HTTP chunked transfer encoding.
  */
-public class ChunkedDecoder implements StreamFilter {
-    private final EntityCompletionListener listener;
-    private int remaining = -1; // bytes remaining in the current chunk
+public class ChunkedDecoder implements EntityProcessor {
+    private static final int STATE_START_CHUNK = 1;
+    private static final int STATE_CHUNK = 2;
+    private static final int STATE_TRAILER = 3;
+    
+    private int state = STATE_START_CHUNK;
+    private int remaining; // bytes remaining in the current chunk
 
-    public ChunkedDecoder(EntityCompletionListener listener) {
-        this.listener = listener;
-    }
-
-    public void invoke(Stream stream) {
+    public boolean process(Stream stream) {
         while (stream.available() > 0) {
-            if (remaining > 0) {
-                int c = Math.min(stream.available(), remaining);
-                stream.skip(c);
-                remaining -= c;
-            } else if (remaining == 0) {
-                if (stream.available() < 2) {
-                    return;
-                }
-                if (stream.get(0) == '\r' && stream.get(1) == '\n') {
-                    stream.discard(2);
-                    remaining = -1;
-                } else {
-                    throw new StreamException("Invalid chunked encoding");
-                }
-            } else {
-                int eolIndex = StreamUtil.searchEndOfLine(stream);
-                if (eolIndex == -1) {
-                    return;
+            switch (state) {
+                case STATE_CHUNK:
+                    if (remaining > 0) {
+                        int c = Math.min(stream.available(), remaining);
+                        stream.skip(c);
+                        remaining -= c;
+                    } else if (remaining == 0) {
+                        if (stream.available() < 2) {
+                            return false;
+                        }
+                        if (stream.get(0) == '\r' && stream.get(1) == '\n') {
+                            stream.discard(2);
+                            state = STATE_START_CHUNK;
+                        } else {
+                            throw new StreamException("Invalid chunked encoding");
+                        }
+                    }
+                    break;
+                case STATE_START_CHUNK: {
+                    int eolIndex = StreamUtil.searchEndOfLine(stream);
+                    if (eolIndex == -1) {
+                        return false;
+                    }
+                    remaining = Integer.parseInt(StreamUtil.getAsciiString(stream, 0, eolIndex), 16);
+                    stream.discard(eolIndex+2);
+                    state = remaining == 0 ? STATE_TRAILER : STATE_CHUNK;
+                    break;
                 }
-                remaining = Integer.parseInt(StreamUtil.getAsciiString(stream, 0, eolIndex), 16);
-                stream.discard(eolIndex+2);
-                if (remaining == 0) {
-                    listener.onComplete();
-                    return;
+                case STATE_TRAILER: {
+                    if (stream.available() < 2) {
+                        return false;
+                    }
+                    if (stream.get(0) == '\r' && stream.get(1) == '\n') {
+                        stream.discard(2);
+                        return true;
+                    } else {
+                        throw new StreamException("Entity headers in trailer not supported");
+                    }
                 }
             }
         }
-        return;
+        return false;
     }
 }

Modified: webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/http/ChunkedEncoder.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/http/ChunkedEncoder.java?rev=781854&r1=781853&r2=781854&view=diff
==============================================================================
--- webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/http/ChunkedEncoder.java (original)
+++ webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/http/ChunkedEncoder.java Thu Jun  4 21:22:52 2009
@@ -28,6 +28,9 @@
             StreamUtil.insertAsciiString(stream, "\r\n");
             StreamUtil.insertAsciiString(stream, Integer.toString(av, 16));
             StreamUtil.insertAsciiString(stream, "\r\n");
+            if (av == 0) {
+                StreamUtil.insertAsciiString(stream, "\r\n");
+            }
         }
     }
 }

Modified: webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/http/HttpFilter.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/http/HttpFilter.java?rev=781854&r1=781853&r2=781854&view=diff
==============================================================================
--- webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/http/HttpFilter.java (original)
+++ webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/http/HttpFilter.java Thu Jun  4 21:22:52 2009
@@ -21,8 +21,10 @@
 import javax.activation.MimeType;
 import javax.activation.MimeTypeParseException;
 
+import org.apache.ws.commons.tcpmon.core.filter.EntityProcessor;
 import org.apache.ws.commons.tcpmon.core.filter.HeaderParser;
-import org.apache.ws.commons.tcpmon.core.filter.ReadOnlyFilterWrapper;
+import org.apache.ws.commons.tcpmon.core.filter.ReadOnlyEntityProcessorWrapper;
+import org.apache.ws.commons.tcpmon.core.filter.ReadOnlyStream;
 import org.apache.ws.commons.tcpmon.core.filter.Stream;
 import org.apache.ws.commons.tcpmon.core.filter.StreamException;
 import org.apache.ws.commons.tcpmon.core.filter.StreamFilter;
@@ -32,7 +34,7 @@
 /**
  * Base class for {@link HttpRequestFilter} and {@link HttpResponseFilter}.
  */
-public abstract class HttpFilter implements StreamFilter, EntityCompletionListener {
+public abstract class HttpFilter implements StreamFilter {
     private static final int STATE_FIRST_LINE = 0;
     private static final int STATE_HEADER = 1;
     private static final int STATE_CONTENT = 2;
@@ -42,6 +44,8 @@
     private int state = STATE_FIRST_LINE;
     private final Headers headers = new Headers();
     private ContentFilterFactory contentFilterFactory;
+    private EntityProcessor transferDecoder;
+    private StreamFilter[] contentFilterChain;
     
     public HttpFilter(boolean decodeTransferEncoding) {
         this.decodeTransferEncoding = decodeTransferEncoding;
@@ -85,13 +89,29 @@
                     }
                     if (headerParser.noMoreHeaders()) {
                         processHeaders(headerParser, stream);
-                        state = STATE_CONTENT;
                     } else {
                         return;
                     }
                     break;
                 }
-                case STATE_CONTENT:
+                case STATE_CONTENT: {
+                    if (transferDecoder != null) {
+                        Stream decoderStream =
+                                decodeTransferEncoding ? stream : new ReadOnlyStream(stream);
+                        if (transferDecoder.process(decoderStream)) {
+                            state = STATE_COMPLETE;
+                            if (contentFilterChain != null) {
+                                for (int i=0; i<contentFilterChain.length; i++) {
+                                    stream.popFilter();
+                                }
+                            }
+                            onComplete();
+                        }
+                        break;
+                    }
+                    // Fall through
+                }
+                default:
                     stream.skipAll();
                     break;
                 case STATE_COMPLETE:
@@ -109,22 +129,20 @@
         
         boolean hasEntity = false;
         boolean discardHeaders = false;
-        StreamFilter transferDecoder = null;
         StreamFilter transferEncoder = null;
-        StreamFilter[] contentFilterChain = null;
         for (Iterator it = headers.iterator(); it.hasNext(); ) {
             Header header = (Header)it.next();
             String name = header.getName();
             String value = header.getValue();
             if (name.equalsIgnoreCase("Content-Length")) {
                 hasEntity = true;
-                transferDecoder = new IdentityDecoder(Integer.parseInt(value), this);
+                transferDecoder = new IdentityDecoder(Integer.parseInt(value));
                 transferEncoder = new IdentityEncoder(headers);
                 discardHeaders = true;
             } else if (name.equalsIgnoreCase("Transfer-Encoding")) {
                 hasEntity = true;
                 if (value.equals("chunked")) {
-                    transferDecoder = new ChunkedDecoder(this);
+                    transferDecoder = new ChunkedDecoder();
                     transferEncoder = new ChunkedEncoder();
                     discardHeaders = false;
                 }
@@ -158,19 +176,21 @@
                 for (int i=contentFilterChain.length-1; i>=0; i--) {
                     stream.pushFilter(contentFilterChain[i]);
                 }
+            } else {
+                if (transferDecoder != null && !decodeTransferEncoding) {
+                    transferDecoder = new ReadOnlyEntityProcessorWrapper(transferDecoder);
+                }
             }
-            if (transferDecoder != null) {
-                stream.pushFilter(decodeTransferEncoding || contentFilterChain != null
-                        ? transferDecoder
-                        : new ReadOnlyFilterWrapper(transferDecoder));
-            }
+            state = STATE_CONTENT;
         } else {
             onComplete();
         }
     }
-
-    public void onComplete() {
+    
+    private void onComplete() {
         state = STATE_COMPLETE;
+        transferDecoder = null;
+        contentFilterChain = null;
         completed();
     }
 }

Modified: webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/http/IdentityDecoder.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/http/IdentityDecoder.java?rev=781854&r1=781853&r2=781854&view=diff
==============================================================================
--- webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/http/IdentityDecoder.java (original)
+++ webservices/commons/trunk/modules/tcpmon/modules/tcpmon-core/src/main/java/org/apache/ws/commons/tcpmon/core/filter/http/IdentityDecoder.java Thu Jun  4 21:22:52 2009
@@ -16,27 +16,23 @@
 
 package org.apache.ws.commons.tcpmon.core.filter.http;
 
+import org.apache.ws.commons.tcpmon.core.filter.EntityProcessor;
 import org.apache.ws.commons.tcpmon.core.filter.Stream;
-import org.apache.ws.commons.tcpmon.core.filter.StreamFilter;
 
 /**
  * Entity processor that processes HTTP identity transfer encoding.
  */
-public class IdentityDecoder implements StreamFilter {
-    private final EntityCompletionListener listener;
+public class IdentityDecoder implements EntityProcessor {
     private int remaining;
 
-    public IdentityDecoder(int contentLength, EntityCompletionListener listener) {
+    public IdentityDecoder(int contentLength) {
         remaining = contentLength;
-        this.listener = listener;
     }
 
-    public void invoke(Stream stream) {
+    public boolean process(Stream stream) {
         int c = Math.min(stream.available(), remaining);
         stream.skip(c);
         remaining -= c;
-        if (remaining == 0) {
-            listener.onComplete();
-        }
+        return remaining == 0;
     }
 }