You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hc.apache.org by ol...@apache.org on 2011/05/10 14:42:58 UTC

svn commit: r1101439 - /httpcomponents/httpcore/trunk/httpcore/src/main/java/org/apache/http/impl/io/AbstractSessionInputBuffer.java

Author: olegk
Date: Tue May 10 12:42:57 2011
New Revision: 1101439

URL: http://svn.apache.org/viewvc?rev=1101439&view=rev
Log:
More efficient handling of non-ascii coded lines by input/output session buffers due to utilization of Java 1.5 charset decoder / encoder API

Modified:
    httpcomponents/httpcore/trunk/httpcore/src/main/java/org/apache/http/impl/io/AbstractSessionInputBuffer.java

Modified: httpcomponents/httpcore/trunk/httpcore/src/main/java/org/apache/http/impl/io/AbstractSessionInputBuffer.java
URL: http://svn.apache.org/viewvc/httpcomponents/httpcore/trunk/httpcore/src/main/java/org/apache/http/impl/io/AbstractSessionInputBuffer.java?rev=1101439&r1=1101438&r2=1101439&view=diff
==============================================================================
--- httpcomponents/httpcore/trunk/httpcore/src/main/java/org/apache/http/impl/io/AbstractSessionInputBuffer.java (original)
+++ httpcomponents/httpcore/trunk/httpcore/src/main/java/org/apache/http/impl/io/AbstractSessionInputBuffer.java Tue May 10 12:42:57 2011
@@ -29,6 +29,11 @@ package org.apache.http.impl.io;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
+import java.nio.charset.Charset;
+import java.nio.charset.CharsetDecoder;
+import java.nio.charset.CoderResult;
 
 import org.apache.http.io.BufferInfo;
 import org.apache.http.io.SessionInputBuffer;
@@ -61,6 +66,8 @@ import org.apache.http.util.CharArrayBuf
  */
 public abstract class AbstractSessionInputBuffer implements SessionInputBuffer, BufferInfo {
 
+    private static final Charset ASCII = Charset.forName("US-ASCII");
+
     private InputStream instream;
     private byte[] buffer;
     private int bufferpos;
@@ -68,7 +75,9 @@ public abstract class AbstractSessionInp
 
     private ByteArrayBuffer linebuffer = null;
 
-    private String charset = HTTP.US_ASCII;
+    private Charset charset;
+    private CharsetDecoder decoder;
+    private CharBuffer cbuf;
     private boolean ascii = true;
     private int maxLineLen = -1;
     private int minChunkLimit = 512;
@@ -97,9 +106,9 @@ public abstract class AbstractSessionInp
         this.bufferpos = 0;
         this.bufferlen = 0;
         this.linebuffer = new ByteArrayBuffer(buffersize);
-        this.charset = HttpProtocolParams.getHttpElementCharset(params);
-        this.ascii = this.charset.equalsIgnoreCase(HTTP.US_ASCII)
-                     || this.charset.equalsIgnoreCase(HTTP.ASCII);
+        this.charset = Charset.forName(HttpProtocolParams.getHttpElementCharset(params));
+        this.ascii = this.charset.equals(ASCII);
+        this.decoder = null;
         this.maxLineLen = params.getIntParameter(CoreConnectionPNames.MAX_LINE_LENGTH, -1);
         this.minChunkLimit = params.getIntParameter(CoreConnectionPNames.MIN_CHUNK_LIMIT, 512);
         this.metrics = createTransportMetrics();
@@ -293,32 +302,26 @@ public abstract class AbstractSessionInp
     private int lineFromLineBuffer(final CharArrayBuffer charbuffer)
             throws IOException {
         // discard LF if found
-        int l = this.linebuffer.length();
-        if (l > 0) {
-            if (this.linebuffer.byteAt(l - 1) == HTTP.LF) {
-                l--;
-                this.linebuffer.setLength(l);
+        int len = this.linebuffer.length();
+        if (len > 0) {
+            if (this.linebuffer.byteAt(len - 1) == HTTP.LF) {
+                len--;
             }
             // discard CR if found
-            if (l > 0) {
-                if (this.linebuffer.byteAt(l - 1) == HTTP.CR) {
-                    l--;
-                    this.linebuffer.setLength(l);
+            if (len > 0) {
+                if (this.linebuffer.byteAt(len - 1) == HTTP.CR) {
+                    len--;
                 }
             }
         }
-        l = this.linebuffer.length();
         if (this.ascii) {
-            charbuffer.append(this.linebuffer, 0, l);
+            charbuffer.append(this.linebuffer, 0, len);
         } else {
-            // This is VERY memory inefficient, BUT since non-ASCII charsets are
-            // NOT meant to be used anyway, there's no point optimizing it
-            String s = new String(this.linebuffer.buffer(), 0, l, this.charset);
-            l = s.length();
-            charbuffer.append(s);
+            ByteBuffer bbuf =  ByteBuffer.wrap(this.linebuffer.buffer(), 0, len);
+            len = appendDecoded(charbuffer, bbuf);
         }
         this.linebuffer.clear();
-        return l;
+        return len;
     }
 
     private int lineFromReadBuffer(final CharArrayBuffer charbuffer, int pos)
@@ -334,12 +337,45 @@ public abstract class AbstractSessionInp
         if (this.ascii) {
             charbuffer.append(this.buffer, off, len);
         } else {
-            // This is VERY memory inefficient, BUT since non-ASCII charsets are
-            // NOT meant to be used anyway, there's no point optimizing it
-            String s = new String(this.buffer, off, len, this.charset);
-            charbuffer.append(s);
-            len = s.length();
+            ByteBuffer bbuf =  ByteBuffer.wrap(this.buffer, off, len);
+            len = appendDecoded(charbuffer, bbuf);
+        }
+        return len;
+    }
+
+    private int appendDecoded(
+            final CharArrayBuffer charbuffer, final ByteBuffer bbuf) throws IOException {
+        if (this.decoder == null) {
+            this.decoder = this.charset.newDecoder();
+        }
+        if (this.cbuf == null) {
+            this.cbuf = CharBuffer.allocate(1024);
+        }
+        this.decoder.reset();
+        int len = 0;
+        while (bbuf.hasRemaining()) {
+            CoderResult result = this.decoder.decode(bbuf, this.cbuf, true);
+            len += handleDecodingResult(result, charbuffer, bbuf);
+        }
+        CoderResult result = this.decoder.flush(this.cbuf);
+        len += handleDecodingResult(result, charbuffer, bbuf);
+        this.cbuf.clear();
+        return len;
+    }
+
+    private int handleDecodingResult(
+            final CoderResult result,
+            final CharArrayBuffer charbuffer,
+            final ByteBuffer bbuf) throws IOException {
+        if (result.isError()) {
+            result.throwException();
+        }
+        this.cbuf.flip();
+        int len = this.cbuf.remaining();
+        while (this.cbuf.hasRemaining()) {
+            charbuffer.append(this.cbuf.get());
         }
+        this.cbuf.compact();
         return len;
     }