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
SpdyHeadersToHttpResponse(const spdy::SpdyHeaderBlock & headers,HttpResponseInfo * response)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
CreateSpdyHeadersFromHttpRequest(const HttpRequestInfo & info,const HttpRequestHeaders & request_headers,spdy::SpdyHeaderBlock * headers,bool direct)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.
ConvertRequestPriorityToSpdyPriority(const RequestPriority priority)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