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 10namespace { 11 12// TODO(jvoung): Use Tokenize from base/strings/string_util.h when this moves 13// to Chromium. 14void 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 24bool 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 38namespace plugin { 39 40NaClHttpResponseHeaders::NaClHttpResponseHeaders() {} 41 42NaClHttpResponseHeaders::~NaClHttpResponseHeaders() {} 43 44void 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.length() == 0 || 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 74std::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 86std::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 99bool 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