Home | History | Annotate | Download | only in http
      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