OLD | NEW |
---|---|
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 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
42 void setContentType(const SubstringRange&) const { } | 42 void setContentType(const SubstringRange&) const { } |
43 void setContentTypeParameter(const SubstringRange&, const SubstringRange&) c onst { } | 43 void setContentTypeParameter(const SubstringRange&, const SubstringRange&) c onst { } |
44 }; | 44 }; |
45 | 45 |
46 static void skipSpaces(const String& input, unsigned& startIndex) | 46 static void skipSpaces(const String& input, unsigned& startIndex) |
47 { | 47 { |
48 while (startIndex < input.length() && input[startIndex] == ' ') | 48 while (startIndex < input.length() && input[startIndex] == ' ') |
49 ++startIndex; | 49 ++startIndex; |
50 } | 50 } |
51 | 51 |
52 static bool isTokenCharacter(char c) | 52 static SubstringRange parseParameterPart(const String& input, unsigned& startInd ex) |
53 { | |
54 return isASCII(c) && c > ' ' && c != '"' && c != '(' && c != ')' && c != ',' && c != '/' && (c < ':' || c > '@') && (c < '[' || c > ']'); | |
55 } | |
56 | |
57 static SubstringRange parseToken(const String& input, unsigned& startIndex) | |
58 { | 53 { |
59 unsigned inputLength = input.length(); | 54 unsigned inputLength = input.length(); |
60 unsigned tokenStart = startIndex; | 55 unsigned tokenStart = startIndex; |
61 unsigned& tokenEnd = startIndex; | 56 unsigned& tokenEnd = startIndex; |
62 | 57 |
63 if (tokenEnd >= inputLength) | 58 if (tokenEnd >= inputLength) |
64 return SubstringRange(); | 59 return SubstringRange(); |
65 | 60 |
61 bool quoted = input[tokenStart] == '\"'; | |
62 bool escape = false; | |
63 | |
66 while (tokenEnd < inputLength) { | 64 while (tokenEnd < inputLength) { |
abarth-chromium
2013/09/16 19:41:42
Rather than calling input[tokenEnd] multiple times
| |
67 if (!isTokenCharacter(input[tokenEnd])) | 65 if (quoted && tokenStart != tokenEnd && input[tokenEnd] == '\"' && !esca pe) |
66 return SubstringRange(tokenStart + 1, tokenEnd++ - tokenStart - 1); | |
67 if (!quoted && (input[tokenEnd] == ';' || input[tokenEnd] == '=')) | |
68 return SubstringRange(tokenStart, tokenEnd - tokenStart); | 68 return SubstringRange(tokenStart, tokenEnd - tokenStart); |
69 escape = !escape && input[tokenEnd] == '\\'; | |
69 ++tokenEnd; | 70 ++tokenEnd; |
70 } | 71 } |
71 | 72 |
72 return SubstringRange(tokenStart, tokenEnd - tokenStart); | 73 return SubstringRange(tokenStart, tokenEnd - tokenStart); |
73 } | 74 } |
74 | 75 |
75 static SubstringRange parseQuotedString(const String& input, unsigned& startInde x) | |
76 { | |
77 unsigned inputLength = input.length(); | |
78 unsigned quotedStringStart = startIndex + 1; | |
79 unsigned& quotedStringEnd = startIndex; | |
80 | |
81 if (quotedStringEnd >= inputLength) | |
82 return SubstringRange(); | |
83 | |
84 if (input[quotedStringEnd++] != '"' || quotedStringEnd >= inputLength) | |
85 return SubstringRange(); | |
86 | |
87 bool lastCharacterWasBackslash = false; | |
88 char currentCharacter; | |
89 while ((currentCharacter = input[quotedStringEnd++]) != '"' || lastCharacter WasBackslash) { | |
90 if (quotedStringEnd >= inputLength) | |
91 return SubstringRange(); | |
92 if (currentCharacter == '\\' && !lastCharacterWasBackslash) { | |
93 lastCharacterWasBackslash = true; | |
94 continue; | |
95 } | |
96 if (lastCharacterWasBackslash) | |
97 lastCharacterWasBackslash = false; | |
98 } | |
99 return SubstringRange(quotedStringStart, quotedStringEnd - quotedStringStart - 1); | |
100 } | |
101 | |
102 static String substringForRange(const String& string, const SubstringRange& rang e) | 76 static String substringForRange(const String& string, const SubstringRange& rang e) |
103 { | 77 { |
104 return string.substring(range.first, range.second); | 78 return string.substring(range.first, range.second); |
105 } | 79 } |
106 | 80 |
107 // From http://tools.ietf.org/html/rfc2045#section-5.1: | 81 // From http://tools.ietf.org/html/rfc2045#section-5.1: |
108 // | 82 // |
109 // content := "Content-Type" ":" type "/" subtype | 83 // content := "Content-Type" ":" type "/" subtype |
110 // *(";" parameter) | 84 // *(";" parameter) |
111 // ; Matching of media type and subtype | 85 // ; Matching of media type and subtype |
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
165 size_t semiColonIndex = contentType.find(';', index); | 139 size_t semiColonIndex = contentType.find(';', index); |
166 if (semiColonIndex == notFound) { | 140 if (semiColonIndex == notFound) { |
167 receiver.setContentType(SubstringRange(index, contentTypeLength - index) ); | 141 receiver.setContentType(SubstringRange(index, contentTypeLength - index) ); |
168 return true; | 142 return true; |
169 } | 143 } |
170 | 144 |
171 receiver.setContentType(SubstringRange(index, semiColonIndex - index)); | 145 receiver.setContentType(SubstringRange(index, semiColonIndex - index)); |
172 index = semiColonIndex + 1; | 146 index = semiColonIndex + 1; |
173 while (true) { | 147 while (true) { |
174 skipSpaces(contentType, index); | 148 skipSpaces(contentType, index); |
175 SubstringRange keyRange = parseToken(contentType, index); | 149 SubstringRange keyRange = parseParameterPart(contentType, index); |
176 if (!keyRange.second || index >= contentTypeLength) { | 150 if (!keyRange.second || index >= contentTypeLength) { |
177 LOG_ERROR("Invalid Content-Type parameter name."); | 151 LOG_ERROR("Invalid Content-Type parameter name. (at %i)", index); |
178 return false; | 152 return false; |
179 } | 153 } |
180 | 154 |
181 // Should we tolerate spaces here? | 155 // Should we tolerate spaces here? |
182 if (contentType[index++] != '=' || index >= contentTypeLength) { | 156 if (contentType[index++] != '=' || index >= contentTypeLength) { |
183 LOG_ERROR("Invalid Content-Type malformed parameter."); | 157 LOG_ERROR("Invalid Content-Type malformed parameter (at %i).", index ); |
184 return false; | 158 return false; |
185 } | 159 } |
186 | 160 |
187 // Should we tolerate spaces here? | 161 // Should we tolerate spaces here? |
188 String value; | 162 SubstringRange valueRange = parseParameterPart(contentType, index); |
189 SubstringRange valueRange; | |
190 if (contentType[index] == '"') | |
191 valueRange = parseQuotedString(contentType, index); | |
192 else | |
193 valueRange = parseToken(contentType, index); | |
194 | 163 |
195 if (!valueRange.second) { | 164 if (!valueRange.second) { |
196 LOG_ERROR("Invalid Content-Type, invalid parameter value."); | 165 LOG_ERROR("Invalid Content-Type, invalid parameter value (at %i, for '%s').", index, substringForRange(contentType, keyRange).stripWhiteSpace().asci i().data()); |
197 return false; | 166 return false; |
198 } | 167 } |
199 | 168 |
200 // Should we tolerate spaces here? | 169 // Should we tolerate spaces here? |
201 if (index < contentTypeLength && contentType[index++] != ';') { | 170 if (index < contentTypeLength && contentType[index++] != ';') { |
202 LOG_ERROR("Invalid Content-Type, invalid character at the end of key /value parameter."); | 171 LOG_ERROR("Invalid Content-Type, invalid character at the end of key /value parameter (at %i).", index); |
203 return false; | 172 return false; |
204 } | 173 } |
205 | 174 |
206 receiver.setContentTypeParameter(keyRange, valueRange); | 175 receiver.setContentTypeParameter(keyRange, valueRange); |
207 | 176 |
208 if (index >= contentTypeLength) | 177 if (index >= contentTypeLength) |
209 return true; | 178 return true; |
210 } | 179 } |
211 | 180 |
212 return true; | 181 return true; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
246 { | 215 { |
247 m_mimeType = substringForRange(m_contentType, contentRange).stripWhiteSpace( ); | 216 m_mimeType = substringForRange(m_contentType, contentRange).stripWhiteSpace( ); |
248 } | 217 } |
249 | 218 |
250 void ParsedContentType::setContentTypeParameter(const SubstringRange& key, const SubstringRange& value) | 219 void ParsedContentType::setContentTypeParameter(const SubstringRange& key, const SubstringRange& value) |
251 { | 220 { |
252 m_parameters.set(substringForRange(m_contentType, key), substringForRange(m_ contentType, value)); | 221 m_parameters.set(substringForRange(m_contentType, key), substringForRange(m_ contentType, value)); |
253 } | 222 } |
254 | 223 |
255 } | 224 } |
OLD | NEW |