Author: markt
Date: Fri Oct 10 14:28:52 2014
New Revision: 1630910

URL: http://svn.apache.org/r1630910
Log:
Allow HTTP headers to be sent using encodings other than ISO-8859-1

Modified:
    tomcat/trunk/java/org/apache/catalina/connector/Response.java
    tomcat/trunk/java/org/apache/coyote/Response.java
    tomcat/trunk/java/org/apache/coyote/ajp/AjpMessage.java
    tomcat/trunk/java/org/apache/coyote/http11/AbstractOutputBuffer.java
    tomcat/trunk/test/org/apache/coyote/ajp/TesterAjpMessage.java

Modified: tomcat/trunk/java/org/apache/catalina/connector/Response.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/catalina/connector/Response.java?rev=1630910&r1=1630909&r2=1630910&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/catalina/connector/Response.java (original)
+++ tomcat/trunk/java/org/apache/catalina/connector/Response.java Fri Oct 10 
14:28:52 2014
@@ -19,6 +19,7 @@ package org.apache.catalina.connector;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.net.MalformedURLException;
+import java.nio.charset.Charset;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.security.PrivilegedActionException;
@@ -1000,6 +1001,11 @@ public class Response
      */
     @Override
     public void addHeader(String name, String value) {
+        addHeader(name, value, null);
+    }
+
+
+    private void addHeader(String name, String value, Charset charset) {
 
         if (name == null || name.length() == 0 || value == null) {
             return;
@@ -1020,7 +1026,7 @@ public class Response
             return;
         }
 
-        coyoteResponse.addHeader(name, value);
+        coyoteResponse.addHeader(name, value, charset);
     }
 
 

Modified: tomcat/trunk/java/org/apache/coyote/Response.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/Response.java?rev=1630910&r1=1630909&r2=1630910&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/Response.java (original)
+++ tomcat/trunk/java/org/apache/coyote/Response.java Fri Oct 10 14:28:52 2014
@@ -18,12 +18,14 @@ package org.apache.coyote;
 
 import java.io.IOException;
 import java.io.StringReader;
+import java.nio.charset.Charset;
 import java.util.Locale;
 import java.util.concurrent.atomic.AtomicBoolean;
 
 import javax.servlet.WriteListener;
 
 import org.apache.tomcat.util.buf.ByteChunk;
+import org.apache.tomcat.util.buf.MessageBytes;
 import org.apache.tomcat.util.http.MimeHeaders;
 import org.apache.tomcat.util.http.parser.MediaType;
 import org.apache.tomcat.util.res.StringManager;
@@ -297,12 +299,21 @@ public final class Response {
 
 
     public void addHeader(String name, String value) {
+        addHeader(name, value, null);
+    }
+
+
+    public void addHeader(String name, String value, Charset charset) {
         char cc=name.charAt(0);
         if( cc=='C' || cc=='c' ) {
             if( checkSpecialHeader(name, value) )
             return;
         }
-        headers.addValue(name).setString( value );
+        MessageBytes mb = headers.addValue(name);
+        if (charset != null) {
+            mb.getByteChunk().setCharset(charset);
+        }
+        mb.setString(value);
     }
 
 

Modified: tomcat/trunk/java/org/apache/coyote/ajp/AjpMessage.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/ajp/AjpMessage.java?rev=1630910&r1=1630909&r2=1630910&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/ajp/AjpMessage.java (original)
+++ tomcat/trunk/java/org/apache/coyote/ajp/AjpMessage.java Fri Oct 10 14:28:52 
2014
@@ -20,7 +20,6 @@ package org.apache.coyote.ajp;
 import org.apache.juli.logging.Log;
 import org.apache.juli.logging.LogFactory;
 import org.apache.tomcat.util.buf.ByteChunk;
-import org.apache.tomcat.util.buf.CharChunk;
 import org.apache.tomcat.util.buf.HexUtils;
 import org.apache.tomcat.util.buf.MessageBytes;
 import org.apache.tomcat.util.res.StringManager;
@@ -159,15 +158,21 @@ public class AjpMessage {
             appendByte(0);
             return;
         }
-        if (mb.getType() == MessageBytes.T_BYTES) {
+        if (mb.getType() != MessageBytes.T_BYTES) {
+            mb.toBytes();
             ByteChunk bc = mb.getByteChunk();
-            appendByteChunk(bc);
-        } else if (mb.getType() == MessageBytes.T_CHARS) {
-            CharChunk cc = mb.getCharChunk();
-            appendCharChunk(cc);
-        } else {
-            appendString(mb.toString());
+            // Need to filter out CTLs excluding TAB. ISO-8859-1 and UTF-8
+            // values will be OK. Strings using other encodings may be
+            // corrupted.
+            byte[] buffer = bc.getBuffer();
+            for (int i = bc.getOffset(); i < bc.getLength(); i++) {
+                if (((buffer[i] <= 31) && (buffer[i] != 9)) ||
+                        buffer[i] == 127 || buffer[i] > 255) {
+                    buffer[i] = ' ';
+                }
+            }
         }
+        appendByteChunk(mb.getByteChunk());
     }
 
 
@@ -188,70 +193,6 @@ public class AjpMessage {
 
 
     /**
-     * Write a CharChunk out at the current write position.
-     * A null CharChunk is encoded as a string with length 0.
-     */
-    public void appendCharChunk(CharChunk cc) {
-        if (cc == null) {
-            log.error(sm.getString("ajpmessage.null"),
-                    new NullPointerException());
-            appendInt(0);
-            appendByte(0);
-            return;
-        }
-        int start = cc.getStart();
-        int end = cc.getEnd();
-        appendInt(end - start);
-        char[] cbuf = cc.getBuffer();
-        for (int i = start; i < end; i++) {
-            char c = cbuf[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 <= 31) && (c != 9)) || c == 127 || c > 255) {
-                c = ' ';
-            }
-            appendByte(c);
-        }
-        appendByte(0);
-    }
-
-
-    /**
-     * Write a String out at the current write position.  Strings are
-     * encoded with the length in two bytes first, then the string, and
-     * then a terminating \0 (which is <B>not</B> included in the
-     * encoded length).  The terminator is for the convenience of the C
-     * code, where it saves a round of copying.  A null string is
-     * encoded as a string with length 0.
-     */
-    public void appendString(String str) {
-        if (str == null) {
-            log.error(sm.getString("ajpmessage.null"),
-                    new NullPointerException());
-            appendInt(0);
-            appendByte(0);
-            return;
-        }
-        int len = str.length();
-        appendInt(len);
-        for (int i = 0; i < len; i++) {
-            char c = str.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 <= 31) && (c != 9)) || c == 127 || c > 255) {
-                c = ' ';
-            }
-            appendByte(c);
-        }
-        appendByte(0);
-    }
-
-
-    /**
      * Copy a chunk of bytes into the packet, starting at the current
      * write position.  The chunk of bytes is encoded with the length
      * in two bytes first, then the data itself, and finally a

Modified: tomcat/trunk/java/org/apache/coyote/http11/AbstractOutputBuffer.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/java/org/apache/coyote/http11/AbstractOutputBuffer.java?rev=1630910&r1=1630909&r2=1630910&view=diff
==============================================================================
--- tomcat/trunk/java/org/apache/coyote/http11/AbstractOutputBuffer.java 
(original)
+++ tomcat/trunk/java/org/apache/coyote/http11/AbstractOutputBuffer.java Fri 
Oct 10 14:28:52 2014
@@ -28,7 +28,6 @@ import org.apache.coyote.OutputBuffer;
 import org.apache.coyote.Response;
 import org.apache.coyote.http11.filters.GzipOutputFilter;
 import org.apache.tomcat.util.buf.ByteChunk;
-import org.apache.tomcat.util.buf.CharChunk;
 import org.apache.tomcat.util.buf.MessageBytes;
 import org.apache.tomcat.util.http.HttpMessages;
 import org.apache.tomcat.util.net.AbstractEndpoint;
@@ -488,16 +487,21 @@ public abstract class AbstractOutputBuff
      */
     protected void write(MessageBytes mb) {
 
-        if (mb.getType() == MessageBytes.T_BYTES) {
+        if (mb.getType() != MessageBytes.T_BYTES) {
+            mb.toBytes();
             ByteChunk bc = mb.getByteChunk();
-            write(bc);
-        } else if (mb.getType() == MessageBytes.T_CHARS) {
-            CharChunk cc = mb.getCharChunk();
-            write(cc);
-        } else {
-            write(mb.toString());
+            // Need to filter out CTLs excluding TAB. ISO-8859-1 and UTF-8
+            // values will be OK. Strings using other encodings may be
+            // corrupted.
+            byte[] buffer = bc.getBuffer();
+            for (int i = bc.getOffset(); i < bc.getLength(); i++) {
+                if (((buffer[i] <= 31) && (buffer[i] != 9)) ||
+                        buffer[i] == 127 || buffer[i] > 255) {
+                    buffer[i] = ' ';
+                }
+            }
         }
-
+        write(mb.getByteChunk());
     }
 
 
@@ -520,34 +524,6 @@ public abstract class AbstractOutputBuff
 
 
     /**
-     * This method will write the contents of the specified char
-     * buffer to the output stream, without filtering. This method is meant to
-     * be used to write the response header.
-     *
-     * @param cc data to be written
-     */
-    protected void write(CharChunk cc) {
-
-        int start = cc.getStart();
-        int end = cc.getEnd();
-        checkLengthBeforeWrite(end-start);
-        char[] cbuf = cc.getBuffer();
-        for (int i = start; i < end; i++) {
-            char c = cbuf[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 <= 31) && (c != 9)) || c == 127 || c > 255) {
-                c = ' ';
-            }
-            headerBuffer[pos++] = (byte) c;
-        }
-
-    }
-
-
-    /**
      * This method will write the contents of the specified byte
      * buffer to the output stream, without filtering. This method is meant to
      * be used to write the response header.

Modified: tomcat/trunk/test/org/apache/coyote/ajp/TesterAjpMessage.java
URL: 
http://svn.apache.org/viewvc/tomcat/trunk/test/org/apache/coyote/ajp/TesterAjpMessage.java?rev=1630910&r1=1630909&r2=1630910&view=diff
==============================================================================
--- tomcat/trunk/test/org/apache/coyote/ajp/TesterAjpMessage.java (original)
+++ tomcat/trunk/test/org/apache/coyote/ajp/TesterAjpMessage.java Fri Oct 10 
14:28:52 2014
@@ -16,6 +16,7 @@
  */
 package org.apache.coyote.ajp;
 
+import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -114,6 +115,11 @@ public class TesterAjpMessage extends Aj
     }
 
 
+    public void appendString(String string) {
+        byte[] bytes = string.getBytes(StandardCharsets.ISO_8859_1);
+        appendBytes(bytes, 0, bytes.length);
+    }
+
 
 
     private static class Header {



---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
For additional commands, e-mail: dev-h...@tomcat.apache.org

Reply via email to