HTTP headers should be case-insensitive but case-preserving.

Bug: http://code.google.com/p/android/issues/detail?id=6684
diff --git a/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/Header.java b/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/Header.java
index bdd1d0a..0f8dfa9 100644
--- a/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/Header.java
+++ b/luni/src/main/java/org/apache/harmony/luni/internal/net/www/protocol/http/Header.java
@@ -19,24 +19,23 @@
 
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Map.Entry;
+import java.util.TreeMap;
 
 /**
  * The general structure for request / response header. It is essentially
  * constructed by hashtable with key indexed in a vector for position lookup.
  */
 public class Header implements Cloneable {
-    /*
-     * we use the non-synchronized ArrayList and HashMap instead of the
-     * synchronized Vector and Hashtable
-     */
     private ArrayList<String> props;
 
-    private HashMap<String, LinkedList<String>> keyTable;
+    // BEGIN android-changed: header fields should be case-insensitive but case-preserving.
+    // http://code.google.com/p/android/issues/detail?id=6684
+    private TreeMap<String, LinkedList<String>> keyTable;
+    // END android-changed
 
     private String statusLine;
 
@@ -48,7 +47,7 @@
     public Header() {
         super();
         this.props = new ArrayList<String>(20);
-        this.keyTable = new HashMap<String, LinkedList<String>>(20);
+        this.keyTable = new TreeMap<String, LinkedList<String>>(String.CASE_INSENSITIVE_ORDER); // android-changed
     }
 
     /**
@@ -79,11 +78,9 @@
         try {
             Header clone = (Header) super.clone();
             clone.props = (ArrayList<String>) props.clone();
-            clone.keyTable = new HashMap<String, LinkedList<String>>(20);
-            for (Map.Entry<String, LinkedList<String>> next : this.keyTable
-                    .entrySet()) {
-                LinkedList<String> v = (LinkedList<String>) next.getValue()
-                        .clone();
+            clone.keyTable = new TreeMap<String, LinkedList<String>>(String.CASE_INSENSITIVE_ORDER); // android-changed
+            for (Map.Entry<String, LinkedList<String>> next : this.keyTable.entrySet()) {
+                LinkedList<String> v = (LinkedList<String>) next.getValue().clone();
                 clone.keyTable.put(next.getKey(), v);
             }
             return clone;
@@ -102,14 +99,11 @@
         if (key == null) {
             throw new NullPointerException();
         }
-        // BEGIN android-changed
-        key = key.toLowerCase();
         LinkedList<String> list = keyTable.get(key);
         if (list == null) {
             list = new LinkedList<String>();
-            keyTable.put(key, list);
+            keyTable.put(key, list); // android-changed
         }
-        // END android-changed
         list.add(value);
         props.add(key);
         props.add(value);
@@ -126,9 +120,6 @@
         if (key == null) {
             throw new NullPointerException();
         }
-        // BEGIN android-added
-        key = key.toLowerCase();
-        // END android-added
         LinkedList<String> list = keyTable.get(key);
         if (list == null) {
             add(key, value);
@@ -154,8 +145,7 @@
      * @since 1.4
      */
     public Map<String, List<String>> getFieldMap() {
-        Map<String, List<String>> result = new HashMap<String, List<String>>(
-                keyTable.size());
+        Map<String, List<String>> result = new TreeMap<String, List<String>>(String.CASE_INSENSITIVE_ORDER); // android-changed
         for (Map.Entry<String, LinkedList<String>> next : keyTable.entrySet()) {
             List<String> v = next.getValue();
             result.put(next.getKey(), Collections.unmodifiableList(v));
@@ -203,7 +193,7 @@
      *         such key exists.
      */
     public String get(String key) {
-        LinkedList<String> result = keyTable.get(key.toLowerCase());
+        LinkedList<String> result = keyTable.get(key); // android-changed
         if (result == null) {
             return null;
         }
diff --git a/luni/src/test/java/org/apache/harmony/luni/internal/net/www/protocol/http/HeaderTest.java b/luni/src/test/java/org/apache/harmony/luni/internal/net/www/protocol/http/HeaderTest.java
new file mode 100644
index 0000000..7ec5fd8
--- /dev/null
+++ b/luni/src/test/java/org/apache/harmony/luni/internal/net/www/protocol/http/HeaderTest.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * 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.harmony.luni.internal.net.www.protocol.http;
+
+import java.util.Arrays;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+public class HeaderTest extends junit.framework.TestCase {
+    // http://code.google.com/p/android/issues/detail?id=6684
+    public void test_caseInsensitiveButCasePreserving() {
+        Header h = new Header();
+        h.add("Content-Type", "text/plain");
+        // Case-insensitive:
+        assertEquals("text/plain", h.get("Content-Type"));
+        assertEquals("text/plain", h.get("Content-type"));
+        assertEquals("text/plain", h.get("content-type"));
+        assertEquals("text/plain", h.get("CONTENT-TYPE"));
+        // ...but case-preserving:
+        assertEquals("Content-Type", h.getFieldMap().keySet().toArray()[0]);
+        
+        // We differ from the RI in that the Map we return is also case-insensitive.
+        // Our behavior seems more consistent. (And code that works on the RI will work on Android.)
+        assertEquals(Arrays.asList("text/plain"), h.getFieldMap().get("Content-Type"));
+        assertEquals(Arrays.asList("text/plain"), h.getFieldMap().get("Content-type")); // RI fails this.
+    }
+}