• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 package org.chromium.net.apihelpers;
6 
7 import org.chromium.net.UrlResponseInfo;
8 
9 import java.nio.charset.Charset;
10 import java.util.List;
11 import java.util.Map;
12 
13 /**
14  * A specialization of {@link InMemoryTransformCronetCallback} that interprets the response body as
15  * a string.
16  *
17  * <p>The charset used to decode the string is derived from the {@code Content-Type} header.
18  */
19 public abstract class StringCronetCallback extends InMemoryTransformCronetCallback<String> {
20     private static final String CONTENT_TYPE_HEADER_NAME = "Content-Type";
21 
StringCronetCallback()22     StringCronetCallback() {}
23 
24     @Override
addCompletionListener( CronetRequestCompletionListener<? super String> listener)25     public StringCronetCallback addCompletionListener(
26             CronetRequestCompletionListener<? super String> listener) {
27         super.addCompletionListener(listener);
28         return this;
29     }
30 
31     @Override // Override to return the subtype
transformBodyBytes(UrlResponseInfo info, byte[] bodyBytes)32     protected String transformBodyBytes(UrlResponseInfo info, byte[] bodyBytes) {
33         return new String(bodyBytes, getCharsetFromHeaders(info));
34     }
35 
getCharsetFromHeaders(UrlResponseInfo info)36     private Charset getCharsetFromHeaders(UrlResponseInfo info) {
37         List<String> contentTypeHeaders = info.getAllHeaders().get(CONTENT_TYPE_HEADER_NAME);
38 
39         String charset = null;
40 
41         for (String header : contentTypeHeaders) {
42             ContentTypeParametersParser parser = new ContentTypeParametersParser(header);
43 
44             while (parser.hasMore()) {
45                 Map.Entry<String, String> parameter;
46                 try {
47                     parameter = parser.getNextParameter();
48                 } catch (ContentTypeParametersParser.ContentTypeParametersParserException e) {
49                     // Malformed header, continue with the next one
50                     break;
51                 }
52                 String parameterName = parameter.getKey();
53                 String parameterValue = parameter.getValue();
54 
55                 if (charset != null && !parameterValue.equalsIgnoreCase(charset)) {
56                     throw new IllegalArgumentException(
57                             "Multiple charsets provided: " + parameterValue + " and " + charset);
58                 }
59                 charset = parameterValue;
60             }
61         }
62 
63         if (charset != null) {
64             return Charset.forName(charset);
65         } else {
66             // Always UTF-8 on Android
67             return Charset.defaultCharset();
68         }
69     }
70 }
71