| 387 | |
| 388 | |
| 389 | bool Request::_acceptsMediaType( |
| 390 | Option<string> name, |
| 391 | const string& mediaType) const |
| 392 | { |
| 393 | vector<string> mediaTypes = strings::tokenize(mediaType, "/"); |
| 394 | |
| 395 | if (mediaTypes.size() != 2) { |
| 396 | return false; |
| 397 | } |
| 398 | |
| 399 | // If no header field is present, then it is assumed |
| 400 | // that the client accepts all media types. |
| 401 | if (name.isNone()) { |
| 402 | return true; |
| 403 | } |
| 404 | |
| 405 | // Remove spaces and tabs for easier parsing. |
| 406 | name = strings::remove(name.get(), " "); |
| 407 | name = strings::remove(name.get(), "\t"); |
| 408 | name = strings::remove(name.get(), "\n"); |
| 409 | |
| 410 | // First match 'type/subtype', then 'type/*', then '*/*'. |
| 411 | vector<string> candidates; |
| 412 | candidates.push_back(mediaType); |
| 413 | candidates.push_back(mediaTypes[0] + "/*"); |
| 414 | candidates.push_back("*/*"); |
| 415 | |
| 416 | foreach (const string& candidate, candidates) { |
| 417 | foreach (const string& type, strings::tokenize(name.get(), ",")) { |
| 418 | vector<string> tokens = strings::tokenize(type, ";"); |
| 419 | |
| 420 | if (tokens.empty()) { |
| 421 | continue; |
| 422 | } |
| 423 | |
| 424 | // Is the candidate one of the accepted type? |
| 425 | if (strings::lower(tokens[0]) == strings::lower(candidate)) { |
| 426 | // Is there a 0 q value? Ex: 'gzip;q=0.0'. |
| 427 | const map<string, vector<string>> values = |
| 428 | strings::pairs(type, ";", "="); |
| 429 | |
| 430 | // Look for { "q": ["0"] }. |
| 431 | if (values.count("q") == 0 || values.find("q")->second.size() != 1) { |
| 432 | // No q value, or malformed q value. |
| 433 | return true; |
| 434 | } |
| 435 | |
| 436 | // Is the q value > 0? |
| 437 | Try<double> value = numify<double>(values.find("q")->second[0]); |
| 438 | return value.isSome() && value.get() > 0; |
| 439 | } |
| 440 | } |
| 441 | } |
| 442 | |
| 443 | return false; |
| 444 | } |
| 445 | |
| 446 | |