Chromium Code Reviews| OLD | NEW |
|---|---|
| (Empty) | |
| 1 /* | |
| 2 * Copyright (C) 2011 Google Inc. All rights reserved. | |
| 3 * Copyright (C) 2012 Intel Corporation. All rights reserved. | |
| 4 * | |
| 5 * Redistribution and use in source and binary forms, with or without | |
| 6 * modification, are permitted provided that the following conditions are | |
| 7 * met: | |
| 8 * | |
| 9 * * Redistributions of source code must retain the above copyright | |
| 10 * notice, this list of conditions and the following disclaimer. | |
| 11 * * Redistributions in binary form must reproduce the above | |
| 12 * copyright notice, this list of conditions and the following disclaimer | |
| 13 * in the documentation and/or other materials provided with the | |
| 14 * distribution. | |
| 15 * * Neither the name of Google Inc. nor the names of its | |
| 16 * contributors may be used to endorse or promote products derived from | |
| 17 * this software without specific prior written permission. | |
| 18 * | |
| 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
| 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
| 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
| 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
| 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
| 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| 30 */ | |
| 31 | |
| 32 #include "platform/network/ParsedParameterizedContentHeaderField.h" | |
| 33 | |
| 34 #include "platform/wtf/text/StringBuilder.h" | |
| 35 #include "platform/wtf/text/StringView.h" | |
| 36 | |
| 37 namespace blink { | |
| 38 | |
| 39 using Mode = ParsedParameterizedContentHeaderField::Mode; | |
| 40 | |
| 41 namespace { | |
| 42 | |
| 43 bool IsTokenCharacter(Mode mode, UChar c) { | |
| 44 if (c >= 128) | |
| 45 return false; | |
| 46 if (c < 0x20) | |
| 47 return false; | |
| 48 | |
| 49 switch (c) { | |
| 50 case ' ': | |
| 51 case ';': | |
| 52 case '"': | |
| 53 return false; | |
| 54 case '(': | |
| 55 case ')': | |
| 56 case '<': | |
| 57 case '>': | |
| 58 case '@': | |
| 59 case ',': | |
| 60 case ':': | |
| 61 case '\\': | |
| 62 case '/': | |
| 63 case '[': | |
| 64 case ']': | |
| 65 case '?': | |
| 66 case '=': | |
| 67 return mode == Mode::kRelaxed; | |
| 68 default: | |
| 69 return true; | |
| 70 } | |
| 71 } | |
| 72 | |
| 73 } // namespace | |
| 74 | |
| 75 ParsedParameterizedContentHeaderField::Input::Input(const String& header_field) | |
| 76 : index_(0u), input_(header_field) {} | |
| 77 | |
| 78 bool ParsedParameterizedContentHeaderField::Input::Consume(char c) { | |
| 79 DCHECK_NE(c, ' '); | |
| 80 | |
| 81 SkipSpaces(); | |
| 82 if (IsConsumed()) | |
| 83 return false; | |
| 84 | |
| 85 ++index_; | |
|
horo
2017/05/15 05:57:54
Why you don't use |c|?
e_hakkinen
2017/05/18 09:35:48
Due to too much refactoring. Fixed.
| |
| 86 return true; | |
| 87 } | |
| 88 | |
| 89 bool ParsedParameterizedContentHeaderField::Input::ConsumeQuotedString( | |
| 90 String& output) { | |
| 91 StringBuilder builder; | |
| 92 | |
| 93 DCHECK_EQ('"', input_[index_]); | |
| 94 ++index_; | |
| 95 | |
| 96 while (!IsConsumed()) { | |
| 97 if (input_[index_] == '"') { | |
| 98 output = builder.ToString(); | |
| 99 ++index_; | |
| 100 return true; | |
| 101 } | |
| 102 if (input_[index_] == '\\') { | |
| 103 ++index_; | |
| 104 if (IsConsumed()) | |
| 105 return false; | |
| 106 } | |
| 107 builder.Append(input_[index_]); | |
| 108 ++index_; | |
| 109 } | |
| 110 return false; | |
| 111 } | |
| 112 | |
| 113 bool ParsedParameterizedContentHeaderField::Input::ConsumeToken( | |
| 114 Mode mode, | |
| 115 StringView& output) { | |
| 116 DCHECK(output.IsNull()); | |
| 117 | |
| 118 SkipSpaces(); | |
| 119 | |
| 120 auto start = index_; | |
| 121 while (!IsConsumed() && IsTokenCharacter(mode, input_[index_])) | |
| 122 ++index_; | |
| 123 | |
| 124 if (start == index_) | |
| 125 return false; | |
| 126 | |
| 127 output = StringView(input_, start, index_ - start); | |
| 128 return true; | |
| 129 } | |
| 130 | |
| 131 bool ParsedParameterizedContentHeaderField::Input::ConsumeTokenOrQuotedString( | |
| 132 Mode mode, | |
| 133 String& output) { | |
| 134 SkipSpaces(); | |
| 135 if (IsConsumed()) | |
| 136 return false; | |
| 137 | |
| 138 if (input_[index_] == '"') | |
| 139 return ConsumeQuotedString(output); | |
| 140 | |
| 141 StringView view; | |
| 142 if (!ConsumeToken(mode, view)) | |
| 143 return false; | |
| 144 output = view.ToString(); | |
| 145 return true; | |
| 146 } | |
| 147 | |
| 148 void ParsedParameterizedContentHeaderField::Input::SkipSpaces() { | |
| 149 while (!IsConsumed() && input_[index_] == ' ') | |
| 150 ++index_; | |
| 151 } | |
| 152 | |
| 153 ParsedParameterizedContentHeaderField::ParsedParameterizedContentHeaderField() | |
| 154 : is_valid_(false) {} | |
| 155 | |
| 156 ParsedParameterizedContentHeaderField::ParsedParameterizedContentHeaderField( | |
|
horo
2017/05/15 05:57:54
Who call this?
If you want to use it to parse Cont
e_hakkinen
2017/05/18 09:35:48
Anyone wanting to parse any content header field o
| |
| 157 const String& header_field, | |
| 158 Mode mode) | |
| 159 : ParsedParameterizedContentHeaderField() { | |
| 160 is_valid_ = Parse(header_field, mode); | |
| 161 } | |
| 162 | |
| 163 String ParsedParameterizedContentHeaderField::ParameterValueForName( | |
| 164 const String& name) const { | |
| 165 if (!name.ContainsOnlyASCII()) | |
| 166 return String(); | |
| 167 return parameters_.at(name.DeprecatedLower()); | |
| 168 } | |
| 169 | |
| 170 size_t ParsedParameterizedContentHeaderField::ParameterCount() const { | |
| 171 return parameters_.size(); | |
| 172 } | |
| 173 | |
| 174 bool ParsedParameterizedContentHeaderField::Parse(const String& header_field, | |
| 175 Mode mode) { | |
| 176 Input input(header_field); | |
| 177 | |
| 178 StringView type; | |
| 179 if (!input.ConsumeToken(Mode::kNormal, type)) { | |
| 180 DVLOG(1) << "Failed to find `type' in '" << header_field << "'"; | |
| 181 return false; | |
| 182 } | |
| 183 SetType(type.ToString()); | |
| 184 | |
| 185 return ParseParameters(input, mode); | |
| 186 } | |
| 187 | |
| 188 // parameters := *(";" parameter) | |
| 189 // | |
| 190 // From http://tools.ietf.org/html/rfc2045#section-5.1: | |
| 191 // | |
| 192 // parameter := attribute "=" value | |
| 193 // | |
| 194 // attribute := token | |
| 195 // ; Matching of attributes | |
| 196 // ; is ALWAYS case-insensitive. | |
| 197 // | |
| 198 // value := token / quoted-string | |
| 199 // | |
| 200 // token := 1*<any (US-ASCII) CHAR except SPACE, CTLs, | |
| 201 // or tspecials> | |
| 202 // | |
| 203 // tspecials := "(" / ")" / "<" / ">" / "@" / | |
| 204 // "," / ";" / ":" / "\" / <"> | |
| 205 // "/" / "[" / "]" / "?" / "=" | |
| 206 // ; Must be in quoted-string, | |
| 207 // ; to use within parameter values | |
| 208 bool ParsedParameterizedContentHeaderField::ParseParameters(Input& input, | |
| 209 Mode mode) { | |
| 210 KeyValuePairs map; | |
| 211 for (;;) { | |
| 212 input.SkipSpaces(); | |
| 213 if (input.IsConsumed()) | |
| 214 break; | |
| 215 | |
| 216 if (!input.Consume(';')) { | |
| 217 DVLOG(1) << "Failed to find ';'"; | |
| 218 return false; | |
| 219 } | |
| 220 | |
| 221 StringView key; | |
| 222 String value; | |
| 223 if (!input.ConsumeToken(Mode::kNormal, key)) { | |
| 224 DVLOG(1) << "Invalid content parameter name. (at " << input.Index() | |
| 225 << ")"; | |
| 226 return false; | |
| 227 } | |
| 228 if (!input.Consume('=')) { | |
| 229 DVLOG(1) << "Failed to find '='"; | |
| 230 return false; | |
| 231 } | |
| 232 if (!input.ConsumeTokenOrQuotedString(mode, value)) { | |
| 233 DVLOG(1) << "Invalid content parameter value (at " << input.Index() | |
| 234 << ", for '" << key.ToString() << "')."; | |
| 235 return false; | |
| 236 } | |
| 237 // As |key| is parsed as a token, it consists of ascii characters | |
| 238 // and hence we don't need to care about non-ascii lowercasing. | |
| 239 DCHECK(key.ToString().ContainsOnlyASCII()); | |
| 240 String key_string = key.ToString().DeprecatedLower(); | |
| 241 if (mode == Mode::kStrict && map.find(key_string) != map.end()) { | |
| 242 DVLOG(1) << "Parameter " << key_string << " is defined multiple times."; | |
| 243 return false; | |
| 244 } | |
| 245 map.Set(key_string, value); | |
| 246 } | |
| 247 parameters_ = std::move(map); | |
| 248 return true; | |
| 249 } | |
| 250 | |
| 251 } // namespace blink | |
| OLD | NEW |