Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(106)

Side by Side Diff: third_party/WebKit/Source/platform/network/ParsedContentType.cpp

Issue 2704153002: ParsedContentType refactoring (Closed)
Patch Set: fix Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2011 Google Inc. All rights reserved. 2 * Copyright (C) 2011 Google Inc. All rights reserved.
3 * Copyright (C) 2012 Intel Corporation. All rights reserved. 3 * Copyright (C) 2012 Intel Corporation. All rights reserved.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are 6 * modification, are permitted provided that the following conditions are
7 * met: 7 * met:
8 * 8 *
9 * * Redistributions of source code must retain the above copyright 9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer. 10 * notice, this list of conditions and the following disclaimer.
(...skipping 18 matching lines...) Expand all
29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 */ 30 */
31 31
32 #include "platform/network/ParsedContentType.h" 32 #include "platform/network/ParsedContentType.h"
33 33
34 #include "wtf/text/CString.h" 34 #include "wtf/text/CString.h"
35 #include "wtf/text/StringBuilder.h" 35 #include "wtf/text/StringBuilder.h"
36 36
37 namespace blink { 37 namespace blink {
38 38
39 class DummyParsedContentType final { 39 using SubstringRange = ParsedContentType::SubstringRange;
40 STACK_ALLOCATED();
41 40
42 public: 41 namespace {
43 void setContentType(const SubstringRange&) const {}
44 void setContentTypeParameter(const SubstringRange&,
45 const SubstringRange&) const {}
46 };
47 42
48 static void skipSpaces(const String& input, unsigned& startIndex) { 43 void skipSpaces(const String& input, unsigned& startIndex) {
49 while (startIndex < input.length() && input[startIndex] == ' ') 44 while (startIndex < input.length() && input[startIndex] == ' ')
50 ++startIndex; 45 ++startIndex;
51 } 46 }
52 47
53 static SubstringRange parseParameterPart(const String& input, 48 SubstringRange parseParameterPart(const String& input, unsigned& startIndex) {
54 unsigned& startIndex) {
55 unsigned inputLength = input.length(); 49 unsigned inputLength = input.length();
56 unsigned tokenStart = startIndex; 50 unsigned tokenStart = startIndex;
57 unsigned& tokenEnd = startIndex; 51 unsigned& tokenEnd = startIndex;
58 52
59 if (tokenEnd >= inputLength) 53 if (tokenEnd >= inputLength)
60 return SubstringRange(); 54 return SubstringRange();
61 55
62 bool quoted = input[tokenStart] == '\"'; 56 bool quoted = input[tokenStart] == '\"';
63 bool escape = false; 57 bool escape = false;
64 58
65 while (tokenEnd < inputLength) { 59 while (tokenEnd < inputLength) {
66 UChar c = input[tokenEnd]; 60 UChar c = input[tokenEnd];
67 if (quoted && tokenStart != tokenEnd && c == '\"' && !escape) 61 if (quoted && tokenStart != tokenEnd && c == '\"' && !escape)
68 return SubstringRange(tokenStart + 1, tokenEnd++ - tokenStart - 1); 62 return SubstringRange(tokenStart + 1, tokenEnd++ - tokenStart - 1);
69 if (!quoted && (c == ';' || c == '=')) 63 if (!quoted && (c == ';' || c == '='))
70 return SubstringRange(tokenStart, tokenEnd - tokenStart); 64 return SubstringRange(tokenStart, tokenEnd - tokenStart);
71 escape = !escape && c == '\\'; 65 escape = !escape && c == '\\';
72 ++tokenEnd; 66 ++tokenEnd;
73 } 67 }
74 68
75 if (quoted) 69 if (quoted)
76 return SubstringRange(); 70 return SubstringRange();
77 return SubstringRange(tokenStart, tokenEnd - tokenStart); 71 return SubstringRange(tokenStart, tokenEnd - tokenStart);
78 } 72 }
79 73
80 static String substringForRange(const String& string, 74 String substringForRange(const String& string, const SubstringRange& range) {
81 const SubstringRange& range) {
82 return string.substring(range.first, range.second); 75 return string.substring(range.first, range.second);
83 } 76 }
84 77
78 } // namespace
79
80 ParsedContentType::ParsedContentType(const String& contentType) {
81 parse(contentType.stripWhiteSpace());
tyoshino-do-not-use 2017/02/20 14:48:46 How about saving the result of parse() in a member
tyoshino-do-not-use 2017/02/20 14:50:31 Sorry. I forgot to insert break in the last paragr
yhirano 2017/02/21 04:40:30 Done.
82 }
83
84 String ParsedContentType::charset() const {
85 return parameterValueForName("charset");
86 }
87
88 String ParsedContentType::parameterValueForName(const String& name) const {
89 return m_parameters.get(name);
90 }
91
92 size_t ParsedContentType::parameterCount() const {
93 return m_parameters.size();
94 }
95
96 bool ParsedContentType::isValid(const String& contentType) {
97 if (contentType.contains('\r') || contentType.contains('\n'))
98 return false;
99
100 return ParsedContentType().parse(contentType.stripWhiteSpace());
101 }
102
85 // From http://tools.ietf.org/html/rfc2045#section-5.1: 103 // From http://tools.ietf.org/html/rfc2045#section-5.1:
86 // 104 //
87 // content := "Content-Type" ":" type "/" subtype 105 // content := "Content-Type" ":" type "/" subtype
88 // *(";" parameter) 106 // *(";" parameter)
89 // ; Matching of media type and subtype 107 // ; Matching of media type and subtype
90 // ; is ALWAYS case-insensitive. 108 // ; is ALWAYS case-insensitive.
91 // 109 //
92 // type := discrete-type / composite-type 110 // type := discrete-type / composite-type
93 // 111 //
94 // discrete-type := "text" / "image" / "audio" / "video" / 112 // discrete-type := "text" / "image" / "audio" / "video" /
(...skipping 26 matching lines...) Expand all
121 // 139 //
122 // token := 1*<any (US-ASCII) CHAR except SPACE, CTLs, 140 // token := 1*<any (US-ASCII) CHAR except SPACE, CTLs,
123 // or tspecials> 141 // or tspecials>
124 // 142 //
125 // tspecials := "(" / ")" / "<" / ">" / "@" / 143 // tspecials := "(" / ")" / "<" / ">" / "@" /
126 // "," / ";" / ":" / "\" / <"> 144 // "," / ";" / ":" / "\" / <">
127 // "/" / "[" / "]" / "?" / "=" 145 // "/" / "[" / "]" / "?" / "="
128 // ; Must be in quoted-string, 146 // ; Must be in quoted-string,
129 // ; to use within parameter values 147 // ; to use within parameter values
130 148
131 template <class ReceiverType> 149 bool ParsedContentType::parse(const String& contentType) {
132 bool parseContentType(const String& contentType, ReceiverType& receiver) {
133 unsigned index = 0; 150 unsigned index = 0;
134 unsigned contentTypeLength = contentType.length(); 151 unsigned contentTypeLength = contentType.length();
135 skipSpaces(contentType, index); 152 skipSpaces(contentType, index);
136 if (index >= contentTypeLength) { 153 if (index >= contentTypeLength) {
137 DVLOG(1) << "Invalid Content-Type string '" << contentType << "'"; 154 DVLOG(1) << "Invalid Content-Type string '" << contentType << "'";
138 return false; 155 return false;
139 } 156 }
140 157
141 // There should not be any quoted strings until we reach the parameters. 158 // There should not be any quoted strings until we reach the parameters.
142 size_t semiColonIndex = contentType.find(';', index); 159 size_t semiColonIndex = contentType.find(';', index);
143 if (semiColonIndex == kNotFound) { 160 if (semiColonIndex == kNotFound) {
144 receiver.setContentType(SubstringRange(index, contentTypeLength - index)); 161 m_mimeType =
162 substringForRange(contentType,
163 SubstringRange(index, contentTypeLength - index))
164 .stripWhiteSpace();
145 return true; 165 return true;
146 } 166 }
147 167
148 receiver.setContentType(SubstringRange(index, semiColonIndex - index)); 168 m_mimeType = substringForRange(contentType,
169 SubstringRange(index, semiColonIndex - index))
170 .stripWhiteSpace();
149 index = semiColonIndex + 1; 171 index = semiColonIndex + 1;
150 while (true) { 172 do {
151 skipSpaces(contentType, index); 173 skipSpaces(contentType, index);
152 SubstringRange keyRange = parseParameterPart(contentType, index); 174 SubstringRange keyRange = parseParameterPart(contentType, index);
153 if (!keyRange.second || index >= contentTypeLength) { 175 if (!keyRange.second || index >= contentTypeLength) {
154 DVLOG(1) << "Invalid Content-Type parameter name. (at " << index << ")"; 176 DVLOG(1) << "Invalid Content-Type parameter name. (at " << index << ")";
155 return false; 177 return false;
156 } 178 }
157 179
158 // Should we tolerate spaces here? 180 // Should we tolerate spaces here?
159 if (contentType[index++] != '=' || index >= contentTypeLength) { 181 if (contentType[index++] != '=' || index >= contentTypeLength) {
160 DVLOG(1) << "Invalid Content-Type malformed parameter (at " << index 182 DVLOG(1) << "Invalid Content-Type malformed parameter (at " << index
(...skipping 13 matching lines...) Expand all
174 } 196 }
175 197
176 // Should we tolerate spaces here? 198 // Should we tolerate spaces here?
177 if (index < contentTypeLength && contentType[index++] != ';') { 199 if (index < contentTypeLength && contentType[index++] != ';') {
178 DVLOG(1) << "Invalid Content-Type, invalid character at the end of " 200 DVLOG(1) << "Invalid Content-Type, invalid character at the end of "
179 "key/value parameter (at " 201 "key/value parameter (at "
180 << index << ")."; 202 << index << ").";
181 return false; 203 return false;
182 } 204 }
183 205
184 receiver.setContentTypeParameter(keyRange, valueRange); 206 m_parameters.set(substringForRange(contentType, keyRange),
185 207 substringForRange(contentType, valueRange));
186 if (index >= contentTypeLength) 208 } while (index < contentTypeLength);
187 return true;
188 }
189 209
190 return true; 210 return true;
191 } 211 }
192 212
193 bool isValidContentType(const String& contentType) {
194 if (contentType.contains('\r') || contentType.contains('\n'))
195 return false;
196
197 DummyParsedContentType parsedContentType = DummyParsedContentType();
198 return parseContentType<DummyParsedContentType>(contentType,
199 parsedContentType);
200 }
201
202 ParsedContentType::ParsedContentType(const String& contentType)
203 : m_contentType(contentType.stripWhiteSpace()) {
204 parseContentType<ParsedContentType>(m_contentType, *this);
205 }
206
207 String ParsedContentType::charset() const {
208 return parameterValueForName("charset");
209 }
210
211 String ParsedContentType::parameterValueForName(const String& name) const {
212 return m_parameters.get(name);
213 }
214
215 size_t ParsedContentType::parameterCount() const {
216 return m_parameters.size();
217 }
218
219 void ParsedContentType::setContentType(const SubstringRange& contentRange) {
220 m_mimeType = substringForRange(m_contentType, contentRange).stripWhiteSpace();
221 }
222
223 void ParsedContentType::setContentTypeParameter(const SubstringRange& key,
224 const SubstringRange& value) {
225 m_parameters.set(substringForRange(m_contentType, key),
226 substringForRange(m_contentType, value));
227 }
228
229 } // namespace blink 213 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698