1 // Copyright 2013 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "ppapi/native_client/src/trusted/plugin/nacl_http_response_headers.h" 6 7 #include <algorithm> 8 #include <sstream> 9 10 namespace { 11 12 // TODO(jvoung): Use Tokenize from base/strings/string_util.h when this moves 13 // to Chromium. 14 void SplitString(const std::string& str, 15 char delim, 16 std::vector<std::string>* elems) { 17 std::stringstream ss(str); 18 std::string item; 19 while (std::getline(ss, item, delim)) { 20 elems->push_back(item); 21 } 22 } 23 24 bool SplitOnce(const std::string& str, 25 char delim, 26 std::vector<std::string>* elems) { 27 size_t pos = str.find(delim); 28 if (pos != std::string::npos) { 29 elems->push_back(str.substr(0, pos)); 30 elems->push_back(str.substr(pos + 1)); 31 return true; 32 } 33 return false; 34 } 35 36 } // namespace 37 38 namespace plugin { 39 40 NaClHttpResponseHeaders::NaClHttpResponseHeaders() {} 41 42 NaClHttpResponseHeaders::~NaClHttpResponseHeaders() {} 43 44 void NaClHttpResponseHeaders::Parse(const std::string& headers_str) { 45 // PPAPI response headers are \n delimited. Separate out the lines. 46 std::vector<std::string> lines; 47 SplitString(headers_str, '\n', &lines); 48 49 for (size_t i = 0; i < lines.size(); ++i) { 50 std::vector<std::string> tokens; 51 // Split along the key-value pair separator char. 52 if (!SplitOnce(lines[i], ':', &tokens)) { 53 // Ignore funny header lines that don't have the key-value separator. 54 continue; 55 } 56 std::string key = tokens[0]; 57 // Also ignore keys that start with white-space (they are invalid). 58 // See: HttpResponseHeadersTest.NormalizeHeadersLeadingWhitespace. 59 if (key[0] == ' ' || key[0] == '\t') 60 continue; 61 // TODO(jvoung): replace some of this with TrimWhitespaceASCII when 62 // we move code to chromium. 63 // Strip trailing whitespace from the key to normalize. 64 size_t pos = key.find_last_not_of(" \t"); 65 if (pos != std::string::npos) 66 key.erase(pos + 1); 67 // Strip leading whitespace from the value to normalize. 68 std::string value = tokens[1]; 69 value.erase(0, value.find_first_not_of(" \t")); 70 header_entries_.push_back(Entry(key, value)); 71 } 72 } 73 74 std::string NaClHttpResponseHeaders::GetHeader(const std::string& name) { 75 for (size_t i = 0; i < header_entries_.size(); ++i) { 76 const Entry& entry = header_entries_[i]; 77 std::string key = entry.first; 78 // TODO(jvoung): replace with LowerCaseEqualsASCII later. 79 std::transform(key.begin(), key.end(), key.begin(), ::tolower); 80 if (key.compare(name) == 0) 81 return entry.second; 82 } 83 return std::string(); 84 } 85 86 std::string NaClHttpResponseHeaders::GetCacheValidators() { 87 std::string result = GetHeader("etag"); 88 if (!result.empty()) 89 result = "etag:" + result; 90 std::string lm = GetHeader("last-modified"); 91 if (!lm.empty()) { 92 if (!result.empty()) 93 result += "&"; 94 result += "last-modified:" + lm; 95 } 96 return result; 97 } 98 99 bool NaClHttpResponseHeaders::CacheControlNoStore() { 100 for (size_t i = 0; i < header_entries_.size(); ++i) { 101 const Entry& entry = header_entries_[i]; 102 std::string key = entry.first; 103 // TODO(jvoung): replace with LowerCaseEqualsASCII later. 104 std::transform(key.begin(), key.end(), key.begin(), ::tolower); 105 if (key.compare("cache-control") == 0) { 106 std::string cc = entry.second; 107 std::transform(cc.begin(), cc.end(), cc.begin(), ::tolower); 108 if (entry.second.find("no-store") != std::string::npos) 109 return true; 110 } 111 } 112 return false; 113 } 114 115 } // namespace plugin 116