1 /*
2  * ====================================================================
3  *
4  *  Licensed to the Apache Software Foundation (ASF) under one or more
5  *  contributor license agreements.  See the NOTICE file distributed with
6  *  this work for additional information regarding copyright ownership.
7  *  The ASF licenses this file to You under the Apache License, Version 2.0
8  *  (the "License"); you may not use this file except in compliance with
9  *  the License.  You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  *  Unless required by applicable law or agreed to in writing, software
14  *  distributed under the License is distributed on an "AS IS" BASIS,
15  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  *  See the License for the specific language governing permissions and
17  *  limitations under the License.
18  * ====================================================================
19  *
20  * This software consists of voluntary contributions made by many
21  * individuals on behalf of the Apache Software Foundation.  For more
22  * information on the Apache Software Foundation, please see
23  * <http://www.apache.org/>.
24  *
25  * [Additional notices, if required by prior licensing conditions]
26  *
27  */
28 
29 package org.apache.commons.httpclient;
30 
31 import junit.framework.Test;
32 import junit.framework.TestSuite;
33 
34 import java.io.ByteArrayInputStream;
35 import java.io.ByteArrayOutputStream;
36 import java.io.IOException;
37 import java.io.InputStream;
38 import java.util.HashMap;
39 import java.util.Map;
40 import java.util.StringTokenizer;
41 
42 import org.apache.commons.httpclient.methods.GetMethod;
43 import org.apache.commons.httpclient.methods.PostMethod;
44 import org.apache.commons.httpclient.methods.RequestEntity;
45 import org.apache.commons.httpclient.methods.StringRequestEntity;
46 import org.apache.commons.httpclient.util.URIUtil;
47 
48 /**
49  * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
50  * @author <a href="mailto:ajmas@bigfoot.com">Andre John Mas</a>
51  * @author <a href="mailto:laura@lwerner.org">Laura Werner</a>
52  */
53 
54 public class TestMethodCharEncoding extends HttpClientTestBase {
55 
56     static final String CHARSET_DEFAULT = "ISO-8859-1";
57     static final String CHARSET_ASCII = "US-ASCII";
58     static final String CHARSET_UTF8 = "UTF-8";
59     static final String CHARSET_KOI8_R = "KOI8_R";
60     static final String CHARSET_WIN1251 = "Cp1251";
61 
62     static final int SWISS_GERMAN_STUFF_UNICODE [] = {
63         0x47, 0x72, 0xFC, 0x65, 0x7A, 0x69, 0x5F, 0x7A, 0xE4, 0x6D, 0xE4
64     };
65 
66     static final int SWISS_GERMAN_STUFF_ISO8859_1 [] = {
67         0x47, 0x72, 0xFC, 0x65, 0x7A, 0x69, 0x5F, 0x7A, 0xE4, 0x6D, 0xE4
68     };
69 
70     static final int SWISS_GERMAN_STUFF_UTF8 [] = {
71         0x47, 0x72, 0xC3, 0xBC, 0x65, 0x7A, 0x69, 0x5F, 0x7A, 0xC3, 0xA4,
72         0x6D, 0xC3, 0xA4
73     };
74 
75     static final int RUSSIAN_STUFF_UNICODE [] = {
76         0x412, 0x441, 0x435, 0x43C, 0x5F, 0x43F, 0x440, 0x438,
77         0x432, 0x435, 0x442
78     };
79 
80     static final int RUSSIAN_STUFF_UTF8 [] = {
81         0xD0, 0x92, 0xD1, 0x81, 0xD0, 0xB5, 0xD0, 0xBC, 0x5F,
82         0xD0, 0xBF, 0xD1, 0x80, 0xD0, 0xB8, 0xD0, 0xB2, 0xD0,
83         0xB5, 0xD1, 0x82
84     };
85 
86     static final int RUSSIAN_STUFF_KOI8R [] = {
87         0xF7, 0xD3, 0xC5, 0xCD, 0x5F, 0xD0, 0xD2, 0xC9, 0xD7,
88         0xC5, 0xD4
89     };
90 
91     static final int RUSSIAN_STUFF_WIN1251 [] = {
92         0xC2, 0xF1, 0xE5, 0xEC, 0x5F, 0xEF, 0xF0, 0xE8, 0xE2,
93         0xE5, 0xF2
94     };
95 
96     // ------------------------------------------------------------ Constructor
97 
TestMethodCharEncoding(final String testName)98     public TestMethodCharEncoding(final String testName) throws IOException {
99         super(testName);
100     }
101 
102     // ------------------------------------------------------- TestCase Methods
103 
suite()104     public static Test suite() {
105         return new TestSuite(TestMethodCharEncoding.class);
106     }
107 
108     // ----------------------------------------------------------------- Tests
109 
110 
testRequestCharEncoding()111     public void testRequestCharEncoding() throws IOException {
112 
113         GetMethod httpget = new GetMethod("/");
114         assertEquals(CHARSET_DEFAULT, httpget.getRequestCharSet());
115         httpget.setRequestHeader("Content-Type", "text/plain; charset=" + CHARSET_ASCII);
116         assertEquals(CHARSET_ASCII, httpget.getRequestCharSet());
117         httpget.setRequestHeader("Content-Type", "text/plain; charset=" + CHARSET_UTF8);
118         assertEquals(CHARSET_UTF8, httpget.getRequestCharSet());
119 
120     }
121 
testNoExplicitCharEncoding()122     public void testNoExplicitCharEncoding() throws Exception {
123         this.server.setHttpService(new EchoService());
124 
125         GetMethod httpget = new GetMethod("/test/");
126         httpget.setRequestHeader("Content-Type", "text/plain");
127         try {
128             this.client.executeMethod(httpget);
129             assertEquals(HttpStatus.SC_OK, httpget.getStatusCode());
130             assertEquals(CHARSET_DEFAULT, httpget.getResponseCharSet());
131         } finally {
132             httpget.releaseConnection();
133         }
134     }
135 
testExplicitCharEncoding()136     public void testExplicitCharEncoding() throws Exception {
137         this.server.setHttpService(new EchoService());
138 
139         GetMethod httpget = new GetMethod("/test/");
140         httpget.setRequestHeader("Content-Type", "text/plain; charset=" + CHARSET_UTF8);
141         try {
142             this.client.executeMethod(httpget);
143             assertEquals(HttpStatus.SC_OK, httpget.getStatusCode());
144             assertEquals(CHARSET_UTF8, httpget.getResponseCharSet());
145         } finally {
146             httpget.releaseConnection();
147         }
148     }
149 
constructString(int [] unicodeChars)150     private String constructString(int [] unicodeChars) {
151         StringBuffer buffer = new StringBuffer();
152         if (unicodeChars != null) {
153             for (int i = 0; i < unicodeChars.length; i++) {
154                 buffer.append((char)unicodeChars[i]);
155             }
156         }
157         return buffer.toString();
158     }
159 
160 
verifyEncoding(RequestEntity entity, int[] sample)161     private void verifyEncoding(RequestEntity entity, int[] sample)
162      throws IOException  {
163 
164         assertNotNull("Request body", entity);
165 
166         ByteArrayOutputStream bos = new ByteArrayOutputStream();
167         entity.writeRequest(bos);
168 
169         InputStream instream = new ByteArrayInputStream(bos.toByteArray());
170         for (int i = 0; i < sample.length; i++) {
171             int b = instream.read();
172             assertTrue("Unexpected end of stream", b != -1);
173             if (sample[i] != b) {
174                 fail("Invalid request body encoding");
175             }
176         }
177         assertTrue("End of stream expected", instream.read() == -1);
178     }
179 
testLatinAccentInRequestBody()180     public void testLatinAccentInRequestBody() throws IOException {
181         PostMethod httppost = new PostMethod("/");
182         String s = constructString(SWISS_GERMAN_STUFF_UNICODE);
183         // Test default encoding ISO-8859-1
184         httppost.setRequestEntity(
185             new StringRequestEntity(s, "text/plain", CHARSET_DEFAULT));
186         verifyEncoding(httppost.getRequestEntity(), SWISS_GERMAN_STUFF_ISO8859_1);
187         // Test UTF-8 encoding
188         httppost.setRequestEntity(
189             new StringRequestEntity(s, "text/plain", CHARSET_UTF8));
190         verifyEncoding(httppost.getRequestEntity(), SWISS_GERMAN_STUFF_UTF8);
191 
192     }
193 
testRussianInRequestBody()194     public void testRussianInRequestBody() throws IOException {
195         PostMethod httppost = new PostMethod("/");
196         String s = constructString(RUSSIAN_STUFF_UNICODE);
197         // Test UTF-8 encoding
198         httppost.setRequestEntity(
199             new StringRequestEntity(s, "text/plain", CHARSET_UTF8));
200         verifyEncoding(httppost.getRequestEntity(), RUSSIAN_STUFF_UTF8);
201         // Test KOI8-R
202         httppost.setRequestEntity(
203             new StringRequestEntity(s, "text/plain", CHARSET_KOI8_R));
204         verifyEncoding(httppost.getRequestEntity(), RUSSIAN_STUFF_KOI8R);
205         // Test WIN1251
206         httppost.setRequestEntity(
207             new StringRequestEntity(s, "text/plain", CHARSET_WIN1251));
208         verifyEncoding(httppost.getRequestEntity(), RUSSIAN_STUFF_WIN1251);
209     }
210 
testQueryParams()211     public void testQueryParams() throws Exception {
212 
213         GetMethod get = new GetMethod("/");
214 
215         String ru_msg = constructString(RUSSIAN_STUFF_UNICODE);
216         String ch_msg = constructString(SWISS_GERMAN_STUFF_UNICODE);
217 
218         get.setQueryString(new NameValuePair[] {
219             new NameValuePair("ru", ru_msg),
220             new NameValuePair("ch", ch_msg)
221         });
222 
223         Map params = new HashMap();
224         StringTokenizer tokenizer = new StringTokenizer(
225             get.getQueryString(), "&");
226         while (tokenizer.hasMoreTokens()) {
227             String s = tokenizer.nextToken();
228             int i = s.indexOf('=');
229             assertTrue("Invalid url-encoded parameters", i != -1);
230             String name = s.substring(0, i).trim();
231             String value = s.substring(i + 1, s.length()).trim();
232             value = URIUtil.decode(value, CHARSET_UTF8);
233             params.put(name, value);
234         }
235         assertEquals(ru_msg, params.get("ru"));
236         assertEquals(ch_msg, params.get("ch"));
237     }
238 
testUrlEncodedRequestBody()239     public void testUrlEncodedRequestBody() throws Exception {
240 
241         PostMethod httppost = new PostMethod("/");
242 
243         String ru_msg = constructString(RUSSIAN_STUFF_UNICODE);
244         String ch_msg = constructString(SWISS_GERMAN_STUFF_UNICODE);
245 
246         httppost.setRequestBody(new NameValuePair[] {
247             new NameValuePair("ru", ru_msg),
248             new NameValuePair("ch", ch_msg)
249         });
250 
251         httppost.setRequestHeader("Content-Type", PostMethod.FORM_URL_ENCODED_CONTENT_TYPE
252             + "; charset=" + CHARSET_UTF8);
253 
254         ByteArrayOutputStream bos = new ByteArrayOutputStream();
255         httppost.getRequestEntity().writeRequest(bos);
256 
257         Map params = new HashMap();
258         StringTokenizer tokenizer = new StringTokenizer(
259             new String(bos.toByteArray(), CHARSET_UTF8), "&");
260         while (tokenizer.hasMoreTokens()) {
261             String s = tokenizer.nextToken();
262             int i = s.indexOf('=');
263             assertTrue("Invalid url-encoded parameters", i != -1);
264             String name = s.substring(0, i).trim();
265             String value = s.substring(i + 1, s.length()).trim();
266             value = URIUtil.decode(value, CHARSET_UTF8);
267             params.put(name, value);
268         }
269         assertEquals(ru_msg, params.get("ru"));
270         assertEquals(ch_msg, params.get("ch"));
271     }
272 
testRequestEntityLength()273     public void testRequestEntityLength() throws IOException {
274         String s = constructString(SWISS_GERMAN_STUFF_UNICODE);
275         RequestEntity requestentity =
276             new StringRequestEntity(s, "text/plain", CHARSET_UTF8);
277         assertEquals(
278                 s.getBytes(CHARSET_UTF8).length,
279                 requestentity.getContentLength());
280     }
281 
282 }
283