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
20namespace net {
21
22bool 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
78void 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.
114int 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