Home | History | Annotate | Download | only in spdy
      1 // Copyright (c) 2010 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/spdy/spdy_http_utils.h"
      6 
      7 #include <string>
      8 
      9 #include "base/string_number_conversions.h"
     10 #include "base/string_util.h"
     11 #include "base/time.h"
     12 #include "net/base/load_flags.h"
     13 #include "net/base/net_util.h"
     14 #include "net/http/http_request_headers.h"
     15 #include "net/http/http_request_info.h"
     16 #include "net/http/http_response_headers.h"
     17 #include "net/http/http_response_info.h"
     18 #include "net/http/http_util.h"
     19 
     20 namespace net {
     21 
     22 bool SpdyHeadersToHttpResponse(const spdy::SpdyHeaderBlock& headers,
     23                                HttpResponseInfo* response) {
     24   std::string version;
     25   std::string status;
     26 
     27   // The "status" and "version" headers are required.
     28   spdy::SpdyHeaderBlock::const_iterator it;
     29   it = headers.find("status");
     30   if (it == headers.end())
     31     return false;
     32   status = it->second;
     33 
     34   // Grab the version.  If not provided by the server,
     35   it = headers.find("version");
     36   if (it == headers.end())
     37     return false;
     38   version = it->second;
     39 
     40   response->response_time = base::Time::Now();
     41 
     42   std::string raw_headers(version);
     43   raw_headers.push_back(' ');
     44   raw_headers.append(status);
     45   raw_headers.push_back('\0');
     46   for (it = headers.begin(); it != headers.end(); ++it) {
     47     // For each value, if the server sends a NUL-separated
     48     // list of values, we separate that back out into
     49     // individual headers for each value in the list.
     50     // e.g.
     51     //    Set-Cookie "foo\0bar"
     52     // becomes
     53     //    Set-Cookie: foo\0
     54     //    Set-Cookie: bar\0
     55     std::string value = it->second;
     56     size_t start = 0;
     57     size_t end = 0;
     58     do {
     59       end = value.find('\0', start);
     60       std::string tval;
     61       if (end != value.npos)
     62         tval = value.substr(start, (end - start));
     63       else
     64         tval = value.substr(start);
     65       raw_headers.append(it->first);
     66       raw_headers.push_back(':');
     67       raw_headers.append(tval);
     68       raw_headers.push_back('\0');
     69       start = end + 1;
     70     } while (end != value.npos);
     71   }
     72 
     73   response->headers = new HttpResponseHeaders(raw_headers);
     74   response->was_fetched_via_spdy = true;
     75   return true;
     76 }
     77 
     78 void CreateSpdyHeadersFromHttpRequest(const HttpRequestInfo& info,
     79                                       const HttpRequestHeaders& request_headers,
     80                                       spdy::SpdyHeaderBlock* headers,
     81                                       bool direct) {
     82 
     83   HttpRequestHeaders::Iterator it(request_headers);
     84   while (it.GetNext()) {
     85     std::string name = StringToLowerASCII(it.name());
     86     if (name == "connection" || name == "proxy-connection" ||
     87         name == "transfer-encoding") {
     88       continue;
     89     }
     90     if (headers->find(name) == headers->end()) {
     91       (*headers)[name] = it.value();
     92     } else {
     93       std::string new_value = (*headers)[name];
     94       new_value.append(1, '\0');  // +=() doesn't append 0's
     95       new_value += it.value();
     96       (*headers)[name] = new_value;
     97     }
     98   }
     99   static const char kHttpProtocolVersion[] = "HTTP/1.1";
    100 
    101   (*headers)["version"] = kHttpProtocolVersion;
    102   (*headers)["method"] = info.method;
    103   (*headers)["host"] = GetHostAndOptionalPort(info.url);
    104   (*headers)["scheme"] = info.url.scheme();
    105   if (direct)
    106     (*headers)["url"] = HttpUtil::PathForRequest(info.url);
    107   else
    108     (*headers)["url"] = HttpUtil::SpecForRequest(info.url);
    109 
    110 }
    111 
    112 // TODO(gavinp): re-adjust this once SPDY v3 has three priority bits,
    113 // eliminating the need for this folding.
    114 int ConvertRequestPriorityToSpdyPriority(const RequestPriority priority) {
    115   DCHECK(HIGHEST <= priority && priority < NUM_PRIORITIES);
    116   switch (priority) {
    117     case LOWEST:
    118       return SPDY_PRIORITY_LOWEST - 1;
    119     case IDLE:
    120       return SPDY_PRIORITY_LOWEST;
    121     default:
    122       return priority;
    123   }
    124 }
    125 
    126 }  // namespace net
    127