1
16 package okhttp3;
17
18 import java.nio.charset.Charset;
19 import java.util.Locale;
20 import java.util.regex.Matcher;
21 import java.util.regex.Pattern;
22 import javax.annotation.Nullable;
23
24
28 public final class MediaType {
29 private static final String TOKEN = "([a-zA-Z0-9-!#$%&'*+.^_`{|}~]+)";
30 private static final String QUOTED = "\"([^\"]*)\"";
31 private static final Pattern TYPE_SUBTYPE = Pattern.compile(TOKEN + "/" + TOKEN);
32 private static final Pattern PARAMETER = Pattern.compile(
33 ";\\s*(?:" + TOKEN + "=(?:" + TOKEN + "|" + QUOTED + "))?");
34
35 private final String mediaType;
36 private final String type;
37 private final String subtype;
38 private final @Nullable String charset;
39
40 private MediaType(String mediaType, String type, String subtype, @Nullable String charset) {
41 this.mediaType = mediaType;
42 this.type = type;
43 this.subtype = subtype;
44 this.charset = charset;
45 }
46
47
52 public static MediaType get(String string) {
53 Matcher typeSubtype = TYPE_SUBTYPE.matcher(string);
54 if (!typeSubtype.lookingAt()) {
55 throw new IllegalArgumentException("No subtype found for: \"" + string + '"');
56 }
57 String type = typeSubtype.group(1).toLowerCase(Locale.US);
58 String subtype = typeSubtype.group(2).toLowerCase(Locale.US);
59
60 String charset = null;
61 Matcher parameter = PARAMETER.matcher(string);
62 for (int s = typeSubtype.end(); s < string.length(); s = parameter.end()) {
63 parameter.region(s, string.length());
64 if (!parameter.lookingAt()) {
65 throw new IllegalArgumentException("Parameter is not formatted correctly: \""
66 + string.substring(s)
67 + "\" for: \""
68 + string
69 + '"');
70 }
71
72 String name = parameter.group(1);
73 if (name == null || !name.equalsIgnoreCase("charset")) continue;
74 String charsetParameter;
75 String token = parameter.group(2);
76 if (token != null) {
77
78 charsetParameter = (token.startsWith("'") && token.endsWith("'") && token.length() > 2)
79 ? token.substring(1, token.length() - 1)
80 : token;
81 } else {
82
83 charsetParameter = parameter.group(3);
84 }
85 if (charset != null && !charsetParameter.equalsIgnoreCase(charset)) {
86 throw new IllegalArgumentException("Multiple charsets defined: \""
87 + charset
88 + "\" and: \""
89 + charsetParameter
90 + "\" for: \""
91 + string
92 + '"');
93 }
94 charset = charsetParameter;
95 }
96
97 return new MediaType(string, type, subtype, charset);
98 }
99
100
104 public static @Nullable MediaType parse(String string) {
105 try {
106 return get(string);
107 } catch (IllegalArgumentException ignored) {
108 return null;
109 }
110 }
111
112
116 public String type() {
117 return type;
118 }
119
120
123 public String subtype() {
124 return subtype;
125 }
126
127
130 public @Nullable Charset charset() {
131 return charset(null);
132 }
133
134
138 public @Nullable Charset charset(@Nullable Charset defaultValue) {
139 try {
140 return charset != null ? Charset.forName(charset) : defaultValue;
141 } catch (IllegalArgumentException e) {
142 return defaultValue;
143 }
144 }
145
146
150 @Override public String toString() {
151 return mediaType;
152 }
153
154 @Override public boolean equals(@Nullable Object other) {
155 return other instanceof MediaType && ((MediaType) other).mediaType.equals(mediaType);
156 }
157
158 @Override public int hashCode() {
159 return mediaType.hashCode();
160 }
161 }
162