|
1 | 1 | package net.lightbody.bmp.util;
|
2 | 2 |
|
3 | 3 | import com.google.common.net.HostAndPort;
|
| 4 | +import com.google.common.net.MediaType; |
4 | 5 | import io.netty.buffer.ByteBuf;
|
5 | 6 | import io.netty.handler.codec.http.HttpHeaders;
|
6 | 7 | import io.netty.handler.codec.http.HttpRequest;
|
7 | 8 | import io.netty.handler.codec.http.HttpResponse;
|
8 | 9 | import net.lightbody.bmp.exception.DecompressionException;
|
9 |
| -import org.apache.http.entity.ContentType; |
| 10 | +import net.lightbody.bmp.exception.UnsupportedCharsetException; |
10 | 11 | import org.slf4j.Logger;
|
11 | 12 | import org.slf4j.LoggerFactory;
|
12 | 13 |
|
|
18 | 19 | import java.nio.charset.Charset;
|
19 | 20 | import java.nio.charset.StandardCharsets;
|
20 | 21 | import java.util.List;
|
| 22 | +import java.util.Locale; |
21 | 23 | import java.util.Map;
|
22 | 24 | import java.util.zip.GZIPInputStream;
|
23 | 25 | import java.util.zip.InflaterInputStream;
|
@@ -149,62 +151,47 @@ public static byte[] extractReadableBytes(ByteBuf content) {
|
149 | 151 | }
|
150 | 152 |
|
151 | 153 | /**
|
152 |
| - * Converts the byte array into a String based on the charset specified in the contentTypeHeader. If no |
153 |
| - * charset is specified in the contentTypeHeader, this method uses default (see {@link #DEFAULT_HTTP_CHARSET}). The httpRequest is used |
154 |
| - * only for logging purposes if the contentTypeHeader does not contain a charset. |
| 154 | + * Converts the byte array into a String based on the specified charset. The charset cannot be null. |
155 | 155 | *
|
156 | 156 | * @param content bytes to convert to a String
|
157 |
| - * @param contentTypeHeader request's content type header |
158 |
| - * @param httpRequest HTTP request responsible for this content (used for logging purposes only) |
| 157 | + * @param charset the character set of the content |
159 | 158 | * @return String containing the converted content
|
| 159 | + * @throws IllegalArgumentException if charset is null |
160 | 160 | */
|
161 |
| - public static String getContentAsString(byte[] content, String contentTypeHeader, HttpRequest httpRequest) { |
162 |
| - Charset charset = readCharsetInContentTypeHeader(contentTypeHeader); |
| 161 | + public static String getContentAsString(byte[] content, Charset charset) { |
163 | 162 | if (charset == null) {
|
164 |
| - // no charset specified, so use the default -- but log a message since this might not encode the data correctly |
165 |
| - charset = DEFAULT_HTTP_CHARSET; |
166 |
| - if (httpRequest != null) { |
167 |
| - log.debug("No charset specified; using charset {} to decode contents to/from {}", charset, httpRequest.getUri()); |
168 |
| - } else { |
169 |
| - log.debug("No charset specified; using charset {} to decode contents", charset); |
170 |
| - } |
| 163 | + throw new IllegalArgumentException("Charset cannot be null"); |
171 | 164 | }
|
172 | 165 |
|
173 | 166 | return new String(content, charset);
|
174 | 167 | }
|
175 | 168 |
|
176 | 169 | /**
|
177 |
| - * Derives the charset from the Content-Type header. Unlike {@link #readCharsetInContentTypeHeader}, if contentTypeHeader is null or |
178 |
| - * does not specify a charset, this method will return the ISO-8859-1 charset. |
179 |
| - * |
180 |
| - * @param contentTypeHeader the Content-Type header string; can be null or empty |
181 |
| - * @return the character set indicated in the contentTypeHeader, or ISO-8859-1 if none is specified or no contentTypeHeader is specified |
182 |
| - */ |
183 |
| - public static Charset deriveCharsetFromContentTypeHeader(String contentTypeHeader) { |
184 |
| - Charset charset = readCharsetInContentTypeHeader(contentTypeHeader); |
185 |
| - if (charset == null) { |
186 |
| - return DEFAULT_HTTP_CHARSET; |
187 |
| - } |
188 |
| - |
189 |
| - return charset; |
190 |
| - } |
191 |
| - |
192 |
| - /** |
193 |
| - * Reads the charset directly from the Content-Type header string. If the Content-Type header does not contain a charset, or if the header |
194 |
| - * is null or empty, this method returns null. See also {@link #deriveCharsetFromContentTypeHeader(String)}. |
| 170 | + * Reads the charset directly from the Content-Type header string. If the Content-Type header does not contain a charset, |
| 171 | + * is malformed or unparsable, or if the header is null or empty, this method returns null. |
195 | 172 | *
|
196 | 173 | * @param contentTypeHeader the Content-Type header string; can be null or empty
|
197 |
| - * @return the character set indicated in the contentTypeHeader, or null if the charset is not present |
| 174 | + * @return the character set indicated in the contentTypeHeader, or null if the charset is not present or is not parsable |
| 175 | + * @throws UnsupportedCharsetException if there is a charset specified in the content-type header, but it is not supported on this platform |
198 | 176 | */
|
199 |
| - public static Charset readCharsetInContentTypeHeader(String contentTypeHeader) { |
| 177 | + public static Charset readCharsetInContentTypeHeader(String contentTypeHeader) throws UnsupportedCharsetException { |
200 | 178 | if (contentTypeHeader == null || contentTypeHeader.isEmpty()) {
|
201 |
| - return DEFAULT_HTTP_CHARSET; |
| 179 | + return null; |
202 | 180 | }
|
203 | 181 |
|
204 |
| - //FIXME: remove dependency on HttpCore's ContentType |
205 |
| - ContentType contentTypeCharset = ContentType.parse(contentTypeHeader); |
| 182 | + MediaType mediaType; |
| 183 | + try { |
| 184 | + mediaType = MediaType.parse(contentTypeHeader); |
| 185 | + } catch (IllegalArgumentException e) { |
| 186 | + log.info("Unable to parse Content-Type header: {}. Content-Type header will be ignored.", contentTypeHeader, e); |
| 187 | + return null; |
| 188 | + } |
206 | 189 |
|
207 |
| - return contentTypeCharset.getCharset(); |
| 190 | + try { |
| 191 | + return mediaType.charset().orNull(); |
| 192 | + } catch (java.nio.charset.UnsupportedCharsetException e) { |
| 193 | + throw new UnsupportedCharsetException(e); |
| 194 | + } |
208 | 195 | }
|
209 | 196 |
|
210 | 197 | /**
|
@@ -284,11 +271,15 @@ public static boolean startsWithHttpOrHttps(String uri) {
|
284 | 271 | return false;
|
285 | 272 | }
|
286 | 273 |
|
287 |
| - if (uri.startsWith("http://") || uri.startsWith("https://")) { |
288 |
| - return true; |
289 |
| - } else { |
290 |
| - return false; |
291 |
| - } |
| 274 | + // the scheme is case insensitive, according to RFC 7230, section 2.7.3: |
| 275 | + /* |
| 276 | + The scheme and host |
| 277 | + are case-insensitive and normally provided in lowercase; all other |
| 278 | + components are compared in a case-sensitive manner. |
| 279 | + */ |
| 280 | + String lowercaseUri = uri.toLowerCase(Locale.US); |
| 281 | + |
| 282 | + return lowercaseUri.startsWith("http://") || lowercaseUri.startsWith("https://"); |
292 | 283 | }
|
293 | 284 |
|
294 | 285 | /**
|
|
0 commit comments