1 // Copyright (c) 2012 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 "net/http/http_request_headers.h" 6 7 #include "base/logging.h" 8 #include "base/strings/string_split.h" 9 #include "base/strings/string_util.h" 10 #include "base/strings/stringprintf.h" 11 #include "base/values.h" 12 #include "net/http/http_util.h" 13 14 namespace net { 15 16 const char HttpRequestHeaders::kGetMethod[] = "GET"; 17 const char HttpRequestHeaders::kAcceptCharset[] = "Accept-Charset"; 18 const char HttpRequestHeaders::kAcceptEncoding[] = "Accept-Encoding"; 19 const char HttpRequestHeaders::kAcceptLanguage[] = "Accept-Language"; 20 const char HttpRequestHeaders::kAuthorization[] = "Authorization"; 21 const char HttpRequestHeaders::kCacheControl[] = "Cache-Control"; 22 const char HttpRequestHeaders::kConnection[] = "Connection"; 23 const char HttpRequestHeaders::kContentLength[] = "Content-Length"; 24 const char HttpRequestHeaders::kContentType[] = "Content-Type"; 25 const char HttpRequestHeaders::kCookie[] = "Cookie"; 26 const char HttpRequestHeaders::kHost[] = "Host"; 27 const char HttpRequestHeaders::kIfModifiedSince[] = "If-Modified-Since"; 28 const char HttpRequestHeaders::kIfNoneMatch[] = "If-None-Match"; 29 const char HttpRequestHeaders::kIfRange[] = "If-Range"; 30 const char HttpRequestHeaders::kOrigin[] = "Origin"; 31 const char HttpRequestHeaders::kPragma[] = "Pragma"; 32 const char HttpRequestHeaders::kProxyAuthorization[] = "Proxy-Authorization"; 33 const char HttpRequestHeaders::kProxyConnection[] = "Proxy-Connection"; 34 const char HttpRequestHeaders::kRange[] = "Range"; 35 const char HttpRequestHeaders::kReferer[] = "Referer"; 36 const char HttpRequestHeaders::kUserAgent[] = "User-Agent"; 37 const char HttpRequestHeaders::kTransferEncoding[] = "Transfer-Encoding"; 38 39 HttpRequestHeaders::HeaderKeyValuePair::HeaderKeyValuePair() { 40 } 41 42 HttpRequestHeaders::HeaderKeyValuePair::HeaderKeyValuePair( 43 const base::StringPiece& key, const base::StringPiece& value) 44 : key(key.data(), key.size()), value(value.data(), value.size()) { 45 } 46 47 48 HttpRequestHeaders::Iterator::Iterator(const HttpRequestHeaders& headers) 49 : started_(false), 50 curr_(headers.headers_.begin()), 51 end_(headers.headers_.end()) {} 52 53 HttpRequestHeaders::Iterator::~Iterator() {} 54 55 bool HttpRequestHeaders::Iterator::GetNext() { 56 if (!started_) { 57 started_ = true; 58 return curr_ != end_; 59 } 60 61 if (curr_ == end_) 62 return false; 63 64 ++curr_; 65 return curr_ != end_; 66 } 67 68 HttpRequestHeaders::HttpRequestHeaders() {} 69 HttpRequestHeaders::~HttpRequestHeaders() {} 70 71 bool HttpRequestHeaders::GetHeader(const base::StringPiece& key, 72 std::string* out) const { 73 HeaderVector::const_iterator it = FindHeader(key); 74 if (it == headers_.end()) 75 return false; 76 out->assign(it->value); 77 return true; 78 } 79 80 void HttpRequestHeaders::Clear() { 81 headers_.clear(); 82 } 83 84 void HttpRequestHeaders::SetHeader(const base::StringPiece& key, 85 const base::StringPiece& value) { 86 HeaderVector::iterator it = FindHeader(key); 87 if (it != headers_.end()) 88 it->value.assign(value.data(), value.size()); 89 else 90 headers_.push_back(HeaderKeyValuePair(key, value)); 91 } 92 93 void HttpRequestHeaders::SetHeaderIfMissing(const base::StringPiece& key, 94 const base::StringPiece& value) { 95 HeaderVector::iterator it = FindHeader(key); 96 if (it == headers_.end()) 97 headers_.push_back(HeaderKeyValuePair(key, value)); 98 } 99 100 void HttpRequestHeaders::RemoveHeader(const base::StringPiece& key) { 101 HeaderVector::iterator it = FindHeader(key); 102 if (it != headers_.end()) 103 headers_.erase(it); 104 } 105 106 void HttpRequestHeaders::AddHeaderFromString( 107 const base::StringPiece& header_line) { 108 DCHECK_EQ(std::string::npos, header_line.find("\r\n")) 109 << "\"" << header_line << "\" contains CRLF."; 110 111 const std::string::size_type key_end_index = header_line.find(":"); 112 if (key_end_index == std::string::npos) { 113 LOG(DFATAL) << "\"" << header_line << "\" is missing colon delimiter."; 114 return; 115 } 116 117 if (key_end_index == 0) { 118 LOG(DFATAL) << "\"" << header_line << "\" is missing header key."; 119 return; 120 } 121 122 const base::StringPiece header_key(header_line.data(), key_end_index); 123 124 const std::string::size_type value_index = key_end_index + 1; 125 126 if (value_index < header_line.size()) { 127 std::string header_value(header_line.data() + value_index, 128 header_line.size() - value_index); 129 std::string::const_iterator header_value_begin = 130 header_value.begin(); 131 std::string::const_iterator header_value_end = 132 header_value.end(); 133 HttpUtil::TrimLWS(&header_value_begin, &header_value_end); 134 135 if (header_value_begin == header_value_end) { 136 // Value was all LWS. 137 SetHeader(header_key, ""); 138 } else { 139 SetHeader(header_key, 140 base::StringPiece(&*header_value_begin, 141 header_value_end - header_value_begin)); 142 } 143 } else if (value_index == header_line.size()) { 144 SetHeader(header_key, ""); 145 } else { 146 NOTREACHED(); 147 } 148 } 149 150 void HttpRequestHeaders::AddHeadersFromString( 151 const base::StringPiece& headers) { 152 // TODO(willchan): Consider adding more StringPiece support in string_util.h 153 // to eliminate copies. 154 std::vector<std::string> header_line_vector; 155 base::SplitStringUsingSubstr(headers.as_string(), "\r\n", 156 &header_line_vector); 157 for (std::vector<std::string>::const_iterator it = header_line_vector.begin(); 158 it != header_line_vector.end(); ++it) { 159 if (!it->empty()) 160 AddHeaderFromString(*it); 161 } 162 } 163 164 void HttpRequestHeaders::MergeFrom(const HttpRequestHeaders& other) { 165 for (HeaderVector::const_iterator it = other.headers_.begin(); 166 it != other.headers_.end(); ++it ) { 167 SetHeader(it->key, it->value); 168 } 169 } 170 171 std::string HttpRequestHeaders::ToString() const { 172 std::string output; 173 for (HeaderVector::const_iterator it = headers_.begin(); 174 it != headers_.end(); ++it) { 175 if (!it->value.empty()) { 176 base::StringAppendF(&output, "%s: %s\r\n", 177 it->key.c_str(), it->value.c_str()); 178 } else { 179 base::StringAppendF(&output, "%s:\r\n", it->key.c_str()); 180 } 181 } 182 output.append("\r\n"); 183 return output; 184 } 185 186 base::Value* HttpRequestHeaders::NetLogCallback( 187 const std::string* request_line, 188 NetLog::LogLevel /* log_level */) const { 189 base::DictionaryValue* dict = new base::DictionaryValue(); 190 dict->SetString("line", *request_line); 191 base::ListValue* headers = new base::ListValue(); 192 for (HeaderVector::const_iterator it = headers_.begin(); 193 it != headers_.end(); ++it) { 194 headers->Append( 195 new base::StringValue(base::StringPrintf("%s: %s", 196 it->key.c_str(), 197 it->value.c_str()))); 198 } 199 dict->Set("headers", headers); 200 return dict; 201 } 202 203 // static 204 bool HttpRequestHeaders::FromNetLogParam(const base::Value* event_param, 205 HttpRequestHeaders* headers, 206 std::string* request_line) { 207 headers->Clear(); 208 *request_line = ""; 209 210 const base::DictionaryValue* dict = NULL; 211 const base::ListValue* header_list = NULL; 212 213 if (!event_param || 214 !event_param->GetAsDictionary(&dict) || 215 !dict->GetList("headers", &header_list) || 216 !dict->GetString("line", request_line)) { 217 return false; 218 } 219 220 for (base::ListValue::const_iterator it = header_list->begin(); 221 it != header_list->end(); 222 ++it) { 223 std::string header_line; 224 if (!(*it)->GetAsString(&header_line)) { 225 headers->Clear(); 226 *request_line = ""; 227 return false; 228 } 229 headers->AddHeaderFromString(header_line); 230 } 231 return true; 232 } 233 234 HttpRequestHeaders::HeaderVector::iterator 235 HttpRequestHeaders::FindHeader(const base::StringPiece& key) { 236 for (HeaderVector::iterator it = headers_.begin(); 237 it != headers_.end(); ++it) { 238 if (key.length() == it->key.length() && 239 !base::strncasecmp(key.data(), it->key.data(), key.length())) 240 return it; 241 } 242 243 return headers_.end(); 244 } 245 246 HttpRequestHeaders::HeaderVector::const_iterator 247 HttpRequestHeaders::FindHeader(const base::StringPiece& key) const { 248 for (HeaderVector::const_iterator it = headers_.begin(); 249 it != headers_.end(); ++it) { 250 if (key.length() == it->key.length() && 251 !base::strncasecmp(key.data(), it->key.data(), key.length())) 252 return it; 253 } 254 255 return headers_.end(); 256 } 257 258 } // namespace net 259