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) { |
67 if (!isTokenCharacter(input[tokenEnd])) | 65 UChar c = input[tokenEnd]; |
| 66 if (quoted && tokenStart != tokenEnd && c == '\"' && !escape) |
| 67 return SubstringRange(tokenStart + 1, tokenEnd++ - tokenStart - 1); |
| 68 if (!quoted && (c == ';' || c == '=')) |
68 return SubstringRange(tokenStart, tokenEnd - tokenStart); | 69 return SubstringRange(tokenStart, tokenEnd - tokenStart); |
| 70 escape = !escape && c == '\\'; |
69 ++tokenEnd; | 71 ++tokenEnd; |
70 } | 72 } |
71 | 73 |
| 74 if (quoted) |
| 75 return SubstringRange(); |
72 return SubstringRange(tokenStart, tokenEnd - tokenStart); | 76 return SubstringRange(tokenStart, tokenEnd - tokenStart); |
73 } | 77 } |
74 | 78 |
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) | 79 static String substringForRange(const String& string, const SubstringRange& rang
e) |
103 { | 80 { |
104 return string.substring(range.first, range.second); | 81 return string.substring(range.first, range.second); |
105 } | 82 } |
106 | 83 |
107 // From http://tools.ietf.org/html/rfc2045#section-5.1: | 84 // From http://tools.ietf.org/html/rfc2045#section-5.1: |
108 // | 85 // |
109 // content := "Content-Type" ":" type "/" subtype | 86 // content := "Content-Type" ":" type "/" subtype |
110 // *(";" parameter) | 87 // *(";" parameter) |
111 // ; Matching of media type and subtype | 88 // ; 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); | 142 size_t semiColonIndex = contentType.find(';', index); |
166 if (semiColonIndex == notFound) { | 143 if (semiColonIndex == notFound) { |
167 receiver.setContentType(SubstringRange(index, contentTypeLength - index)
); | 144 receiver.setContentType(SubstringRange(index, contentTypeLength - index)
); |
168 return true; | 145 return true; |
169 } | 146 } |
170 | 147 |
171 receiver.setContentType(SubstringRange(index, semiColonIndex - index)); | 148 receiver.setContentType(SubstringRange(index, semiColonIndex - index)); |
172 index = semiColonIndex + 1; | 149 index = semiColonIndex + 1; |
173 while (true) { | 150 while (true) { |
174 skipSpaces(contentType, index); | 151 skipSpaces(contentType, index); |
175 SubstringRange keyRange = parseToken(contentType, index); | 152 SubstringRange keyRange = parseParameterPart(contentType, index); |
176 if (!keyRange.second || index >= contentTypeLength) { | 153 if (!keyRange.second || index >= contentTypeLength) { |
177 LOG_ERROR("Invalid Content-Type parameter name."); | 154 LOG_ERROR("Invalid Content-Type parameter name. (at %i)", index); |
178 return false; | 155 return false; |
179 } | 156 } |
180 | 157 |
181 // Should we tolerate spaces here? | 158 // Should we tolerate spaces here? |
182 if (contentType[index++] != '=' || index >= contentTypeLength) { | 159 if (contentType[index++] != '=' || index >= contentTypeLength) { |
183 LOG_ERROR("Invalid Content-Type malformed parameter."); | 160 LOG_ERROR("Invalid Content-Type malformed parameter (at %i).", index
); |
184 return false; | 161 return false; |
185 } | 162 } |
186 | 163 |
187 // Should we tolerate spaces here? | 164 // Should we tolerate spaces here? |
188 String value; | 165 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 | 166 |
195 if (!valueRange.second) { | 167 if (!valueRange.second) { |
196 LOG_ERROR("Invalid Content-Type, invalid parameter value."); | 168 LOG_ERROR("Invalid Content-Type, invalid parameter value (at %i, for
'%s').", index, substringForRange(contentType, keyRange).stripWhiteSpace().asci
i().data()); |
197 return false; | 169 return false; |
198 } | 170 } |
199 | 171 |
200 // Should we tolerate spaces here? | 172 // Should we tolerate spaces here? |
201 if (index < contentTypeLength && contentType[index++] != ';') { | 173 if (index < contentTypeLength && contentType[index++] != ';') { |
202 LOG_ERROR("Invalid Content-Type, invalid character at the end of key
/value parameter."); | 174 LOG_ERROR("Invalid Content-Type, invalid character at the end of key
/value parameter (at %i).", index); |
203 return false; | 175 return false; |
204 } | 176 } |
205 | 177 |
206 receiver.setContentTypeParameter(keyRange, valueRange); | 178 receiver.setContentTypeParameter(keyRange, valueRange); |
207 | 179 |
208 if (index >= contentTypeLength) | 180 if (index >= contentTypeLength) |
209 return true; | 181 return true; |
210 } | 182 } |
211 | 183 |
212 return true; | 184 return true; |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
246 { | 218 { |
247 m_mimeType = substringForRange(m_contentType, contentRange).stripWhiteSpace(
); | 219 m_mimeType = substringForRange(m_contentType, contentRange).stripWhiteSpace(
); |
248 } | 220 } |
249 | 221 |
250 void ParsedContentType::setContentTypeParameter(const SubstringRange& key, const
SubstringRange& value) | 222 void ParsedContentType::setContentTypeParameter(const SubstringRange& key, const
SubstringRange& value) |
251 { | 223 { |
252 m_parameters.set(substringForRange(m_contentType, key), substringForRange(m_
contentType, value)); | 224 m_parameters.set(substringForRange(m_contentType, key), substringForRange(m_
contentType, value)); |
253 } | 225 } |
254 | 226 |
255 } | 227 } |
OLD | NEW |