|
1 /* |
|
2 * ==================================================================== |
|
3 * Licensed to the Apache Software Foundation (ASF) under one |
|
4 * or more contributor license agreements. See the NOTICE file |
|
5 * distributed with this work for additional information |
|
6 * regarding copyright ownership. The ASF licenses this file |
|
7 * to you under the Apache License, Version 2.0 (the |
|
8 * "License"); you may not use this file except in compliance |
|
9 * with 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, |
|
14 * software distributed under the License is distributed on an |
|
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
|
16 * KIND, either express or implied. See the License for the |
|
17 * specific language governing permissions and limitations |
|
18 * under the License. |
|
19 * ==================================================================== |
|
20 * |
|
21 * This software consists of voluntary contributions made by many |
|
22 * individuals on behalf of the Apache Software Foundation. For more |
|
23 * information on the Apache Software Foundation, please see |
|
24 * <http://www.apache.org/>. |
|
25 * |
|
26 */ |
|
27 |
|
28 package ch.boye.httpclientandroidlib.client.utils; |
|
29 |
|
30 import java.io.IOException; |
|
31 import java.io.UnsupportedEncodingException; |
|
32 import java.net.URI; |
|
33 import java.net.URLDecoder; |
|
34 import java.net.URLEncoder; |
|
35 import java.util.ArrayList; |
|
36 import java.util.Collections; |
|
37 import java.util.List; |
|
38 import java.util.Scanner; |
|
39 |
|
40 import ch.boye.httpclientandroidlib.annotation.Immutable; |
|
41 |
|
42 import ch.boye.httpclientandroidlib.Header; |
|
43 import ch.boye.httpclientandroidlib.HeaderElement; |
|
44 import ch.boye.httpclientandroidlib.HttpEntity; |
|
45 import ch.boye.httpclientandroidlib.NameValuePair; |
|
46 import ch.boye.httpclientandroidlib.message.BasicNameValuePair; |
|
47 import ch.boye.httpclientandroidlib.protocol.HTTP; |
|
48 import ch.boye.httpclientandroidlib.util.EntityUtils; |
|
49 |
|
50 /** |
|
51 * A collection of utilities for encoding URLs. |
|
52 * |
|
53 * @since 4.0 |
|
54 */ |
|
55 @Immutable |
|
56 public class URLEncodedUtils { |
|
57 |
|
58 public static final String CONTENT_TYPE = "application/x-www-form-urlencoded"; |
|
59 private static final String PARAMETER_SEPARATOR = "&"; |
|
60 private static final String NAME_VALUE_SEPARATOR = "="; |
|
61 |
|
62 /** |
|
63 * Returns a list of {@link NameValuePair NameValuePairs} as built from the |
|
64 * URI's query portion. For example, a URI of |
|
65 * http://example.org/path/to/file?a=1&b=2&c=3 would return a list of three |
|
66 * NameValuePairs, one for a=1, one for b=2, and one for c=3. |
|
67 * <p> |
|
68 * This is typically useful while parsing an HTTP PUT. |
|
69 * |
|
70 * @param uri |
|
71 * uri to parse |
|
72 * @param encoding |
|
73 * encoding to use while parsing the query |
|
74 */ |
|
75 public static List <NameValuePair> parse (final URI uri, final String encoding) { |
|
76 List <NameValuePair> result = Collections.emptyList(); |
|
77 final String query = uri.getRawQuery(); |
|
78 if (query != null && query.length() > 0) { |
|
79 result = new ArrayList <NameValuePair>(); |
|
80 parse(result, new Scanner(query), encoding); |
|
81 } |
|
82 return result; |
|
83 } |
|
84 |
|
85 /** |
|
86 * Returns a list of {@link NameValuePair NameValuePairs} as parsed from an |
|
87 * {@link HttpEntity}. The encoding is taken from the entity's |
|
88 * Content-Encoding header. |
|
89 * <p> |
|
90 * This is typically used while parsing an HTTP POST. |
|
91 * |
|
92 * @param entity |
|
93 * The entity to parse |
|
94 * @throws IOException |
|
95 * If there was an exception getting the entity's data. |
|
96 */ |
|
97 public static List <NameValuePair> parse ( |
|
98 final HttpEntity entity) throws IOException { |
|
99 List <NameValuePair> result = Collections.emptyList(); |
|
100 |
|
101 String contentType = null; |
|
102 String charset = null; |
|
103 |
|
104 Header h = entity.getContentType(); |
|
105 if (h != null) { |
|
106 HeaderElement[] elems = h.getElements(); |
|
107 if (elems.length > 0) { |
|
108 HeaderElement elem = elems[0]; |
|
109 contentType = elem.getName(); |
|
110 NameValuePair param = elem.getParameterByName("charset"); |
|
111 if (param != null) { |
|
112 charset = param.getValue(); |
|
113 } |
|
114 } |
|
115 } |
|
116 |
|
117 if (contentType != null && contentType.equalsIgnoreCase(CONTENT_TYPE)) { |
|
118 final String content = EntityUtils.toString(entity, HTTP.ASCII); |
|
119 if (content != null && content.length() > 0) { |
|
120 result = new ArrayList <NameValuePair>(); |
|
121 parse(result, new Scanner(content), charset); |
|
122 } |
|
123 } |
|
124 return result; |
|
125 } |
|
126 |
|
127 /** |
|
128 * Returns true if the entity's Content-Type header is |
|
129 * <code>application/x-www-form-urlencoded</code>. |
|
130 */ |
|
131 public static boolean isEncoded (final HttpEntity entity) { |
|
132 Header h = entity.getContentType(); |
|
133 if (h != null) { |
|
134 HeaderElement[] elems = h.getElements(); |
|
135 if (elems.length > 0) { |
|
136 String contentType = elems[0].getName(); |
|
137 return contentType.equalsIgnoreCase(CONTENT_TYPE); |
|
138 } else { |
|
139 return false; |
|
140 } |
|
141 } else { |
|
142 return false; |
|
143 } |
|
144 } |
|
145 |
|
146 /** |
|
147 * Adds all parameters within the Scanner to the list of |
|
148 * <code>parameters</code>, as encoded by <code>encoding</code>. For |
|
149 * example, a scanner containing the string <code>a=1&b=2&c=3</code> would |
|
150 * add the {@link NameValuePair NameValuePairs} a=1, b=2, and c=3 to the |
|
151 * list of parameters. |
|
152 * |
|
153 * @param parameters |
|
154 * List to add parameters to. |
|
155 * @param scanner |
|
156 * Input that contains the parameters to parse. |
|
157 * @param encoding |
|
158 * Encoding to use when decoding the parameters. |
|
159 */ |
|
160 public static void parse ( |
|
161 final List <NameValuePair> parameters, |
|
162 final Scanner scanner, |
|
163 final String encoding) { |
|
164 scanner.useDelimiter(PARAMETER_SEPARATOR); |
|
165 while (scanner.hasNext()) { |
|
166 final String[] nameValue = scanner.next().split(NAME_VALUE_SEPARATOR); |
|
167 if (nameValue.length == 0 || nameValue.length > 2) |
|
168 throw new IllegalArgumentException("bad parameter"); |
|
169 |
|
170 final String name = decode(nameValue[0], encoding); |
|
171 String value = null; |
|
172 if (nameValue.length == 2) |
|
173 value = decode(nameValue[1], encoding); |
|
174 parameters.add(new BasicNameValuePair(name, value)); |
|
175 } |
|
176 } |
|
177 |
|
178 /** |
|
179 * Returns a String that is suitable for use as an <code>application/x-www-form-urlencoded</code> |
|
180 * list of parameters in an HTTP PUT or HTTP POST. |
|
181 * |
|
182 * @param parameters The parameters to include. |
|
183 * @param encoding The encoding to use. |
|
184 */ |
|
185 public static String format ( |
|
186 final List <? extends NameValuePair> parameters, |
|
187 final String encoding) { |
|
188 final StringBuilder result = new StringBuilder(); |
|
189 for (final NameValuePair parameter : parameters) { |
|
190 final String encodedName = encode(parameter.getName(), encoding); |
|
191 final String value = parameter.getValue(); |
|
192 final String encodedValue = value != null ? encode(value, encoding) : ""; |
|
193 if (result.length() > 0) |
|
194 result.append(PARAMETER_SEPARATOR); |
|
195 result.append(encodedName); |
|
196 result.append(NAME_VALUE_SEPARATOR); |
|
197 result.append(encodedValue); |
|
198 } |
|
199 return result.toString(); |
|
200 } |
|
201 |
|
202 private static String decode (final String content, final String encoding) { |
|
203 try { |
|
204 return URLDecoder.decode(content, |
|
205 encoding != null ? encoding : HTTP.DEFAULT_CONTENT_CHARSET); |
|
206 } catch (UnsupportedEncodingException problem) { |
|
207 throw new IllegalArgumentException(problem); |
|
208 } |
|
209 } |
|
210 |
|
211 private static String encode (final String content, final String encoding) { |
|
212 try { |
|
213 return URLEncoder.encode(content, |
|
214 encoding != null ? encoding : HTTP.DEFAULT_CONTENT_CHARSET); |
|
215 } catch (UnsupportedEncodingException problem) { |
|
216 throw new IllegalArgumentException(problem); |
|
217 } |
|
218 } |
|
219 |
|
220 } |