Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(94)

Side by Side Diff: net/quic/quic_in_memory_cache.cc

Issue 337093003: QuicServer: Use Chrome's header parsing rather than Balsa (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@quic_server_3
Patch Set: (mark StringPieceUtils as copied, not added) Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/quic/quic_in_memory_cache.h" 5 #include "net/quic/quic_in_memory_cache.h"
6 6
7 #include "base/files/file_enumerator.h" 7 #include "base/files/file_enumerator.h"
8 #include "base/stl_util.h" 8 #include "base/stl_util.h"
9 #include "base/strings/string_number_conversions.h" 9 #include "base/strings/string_number_conversions.h"
10 #include "net/tools/balsa/balsa_headers.h" 10 #include "net/http/http_util.h"
11 #include "net/quic/string_piece_utils.h"
11 12
12 using base::FilePath; 13 using base::FilePath;
13 using base::StringPiece; 14 using base::StringPiece;
14 using std::string; 15 using std::string;
15 16
16 // Specifies the directory used during QuicInMemoryCache 17 // Specifies the directory used during QuicInMemoryCache
17 // construction to seed the cache. Cache directory can be 18 // construction to seed the cache. Cache directory can be
18 // generated using `wget -p --save-headers <url> 19 // generated using `wget -p --save-headers <url>
19 20
20 namespace net { 21 namespace net {
21 22
22 FilePath::StringType g_quic_in_memory_cache_dir = FILE_PATH_LITERAL(""); 23 FilePath::StringType g_quic_in_memory_cache_dir = FILE_PATH_LITERAL("");
23 24
24 namespace { 25 QuicInMemoryCache::Response::Response()
26 : response_type_(REGULAR_RESPONSE), headers_(NULL) {
Ryan Hamilton 2014/06/19 00:15:44 One per line, unless the whole thing fits on one l
dmz 2014/06/19 21:17:02 You're right, it does not.
27 }
25 28
26 // BalsaVisitor implementation (glue) which caches response bodies. 29 QuicInMemoryCache::Response::~Response() {
27 class CachingBalsaVisitor : public NoOpBalsaVisitor { 30 }
28 public:
29 CachingBalsaVisitor() : done_framing_(false) {}
30 virtual void ProcessBodyData(const char* input, size_t size) OVERRIDE {
31 AppendToBody(input, size);
32 }
33 virtual void MessageDone() OVERRIDE {
34 done_framing_ = true;
35 }
36 virtual void HandleHeaderError(BalsaFrame* framer) OVERRIDE {
37 UnhandledError();
38 }
39 virtual void HandleHeaderWarning(BalsaFrame* framer) OVERRIDE {
40 UnhandledError();
41 }
42 virtual void HandleChunkingError(BalsaFrame* framer) OVERRIDE {
43 UnhandledError();
44 }
45 virtual void HandleBodyError(BalsaFrame* framer) OVERRIDE {
46 UnhandledError();
47 }
48 void UnhandledError() {
49 LOG(DFATAL) << "Unhandled error framing HTTP.";
50 }
51 void AppendToBody(const char* input, size_t size) {
52 body_.append(input, size);
53 }
54 bool done_framing() const { return done_framing_; }
55 const string& body() const { return body_; }
56
57 private:
58 bool done_framing_;
59 string body_;
60 };
61
62 } // namespace
63 31
64 // static 32 // static
65 QuicInMemoryCache* QuicInMemoryCache::GetInstance() { 33 QuicInMemoryCache* QuicInMemoryCache::GetInstance() {
66 return Singleton<QuicInMemoryCache>::get(); 34 return Singleton<QuicInMemoryCache>::get();
67 } 35 }
68 36
69 const QuicInMemoryCache::Response* QuicInMemoryCache::GetResponse( 37 const QuicInMemoryCache::Response* QuicInMemoryCache::GetResponse(
70 const BalsaHeaders& request_headers) const { 38 const HttpRequestLine& request) const {
71 ResponseMap::const_iterator it = responses_.find(GetKey(request_headers)); 39 ResponseMap::const_iterator it = responses_.find(request.FullPath());
72 if (it == responses_.end()) { 40 if (it == responses_.end()) {
73 return NULL; 41 return NULL;
74 } 42 }
75 return it->second; 43 return it->second;
76 } 44 }
77 45
78 void QuicInMemoryCache::AddSimpleResponse(StringPiece method, 46 void QuicInMemoryCache::AddSimpleResponse(StringPiece method,
79 StringPiece path, 47 StringPiece path,
80 StringPiece version, 48 StringPiece version,
81 StringPiece response_code, 49 StringPiece response_code,
82 StringPiece response_detail, 50 StringPiece response_detail,
83 StringPiece body) { 51 StringPiece body) {
84 BalsaHeaders request_headers, response_headers; 52 HttpRequestLine request_line(method, path, version, "");
85 request_headers.SetRequestFirstlineFromStringPieces(method,
86 path,
87 version);
88 response_headers.SetRequestFirstlineFromStringPieces(version,
89 response_code,
90 response_detail);
91 response_headers.AppendHeader("content-length",
92 base::IntToString(body.length()));
93 53
94 AddResponse(request_headers, response_headers, body); 54 scoped_refptr<HttpResponseHeaders> response_headers =
55 new HttpResponseHeaders("");
56 response_headers->ReplaceStatusLine(response_code.as_string() + " " +
57 response_detail.as_string() + " " +
58 body.as_string());
59 response_headers->AddHeader("content-length: " +
60 base::IntToString(body.length()));
61
62 AddResponse(request_line, response_headers, body);
95 } 63 }
96 64
97 void QuicInMemoryCache::AddResponse(const BalsaHeaders& request_headers, 65 void QuicInMemoryCache::AddResponse(
98 const BalsaHeaders& response_headers, 66 const HttpRequestLine& request_line,
99 StringPiece response_body) { 67 scoped_refptr<HttpResponseHeaders> response_headers,
100 VLOG(1) << "Adding response for: " << GetKey(request_headers); 68 StringPiece response_body) {
101 if (ContainsKey(responses_, GetKey(request_headers))) { 69 VLOG(1) << "Adding response for: " << request_line.FullPath();
70 if (ContainsKey(responses_, request_line.FullPath())) {
102 LOG(DFATAL) << "Response for given request already exists!"; 71 LOG(DFATAL) << "Response for given request already exists!";
103 return; 72 return;
104 } 73 }
105 Response* new_response = new Response(); 74 Response* new_response = new Response();
106 new_response->set_headers(response_headers); 75 new_response->set_headers(response_headers);
107 new_response->set_body(response_body); 76 new_response->set_body(response_body);
108 responses_[GetKey(request_headers)] = new_response; 77 responses_[request_line.FullPath()] = new_response;
109 } 78 }
110 79
111 void QuicInMemoryCache::AddSpecialResponse(StringPiece method, 80 void QuicInMemoryCache::AddSpecialResponse(StringPiece method,
112 StringPiece path, 81 StringPiece path,
113 StringPiece version, 82 StringPiece version,
114 SpecialResponseType response_type) { 83 SpecialResponseType response_type) {
115 BalsaHeaders request_headers, response_headers; 84 HttpRequestLine request_line(method, path, version, "");
116 request_headers.SetRequestFirstlineFromStringPieces(method, 85 AddResponse(request_line, new HttpResponseHeaders(""), "");
117 path, 86 responses_[request_line.FullPath()]->response_type_ = response_type;
118 version);
119 AddResponse(request_headers, response_headers, "");
120 responses_[GetKey(request_headers)]->response_type_ = response_type;
121 } 87 }
122 88
123 QuicInMemoryCache::QuicInMemoryCache() { 89 QuicInMemoryCache::QuicInMemoryCache() {
124 Initialize(); 90 Initialize();
125 } 91 }
126 92
127 void QuicInMemoryCache::ResetForTests() { 93 void QuicInMemoryCache::ResetForTests() {
128 STLDeleteValues(&responses_); 94 STLDeleteValues(&responses_);
129 Initialize(); 95 Initialize();
130 } 96 }
(...skipping 13 matching lines...) Expand all
144 base::FileEnumerator::FILES); 110 base::FileEnumerator::FILES);
145 111
146 FilePath file = file_list.Next(); 112 FilePath file = file_list.Next();
147 while (!file.empty()) { 113 while (!file.empty()) {
148 // Need to skip files in .svn directories 114 // Need to skip files in .svn directories
149 if (file.value().find(FILE_PATH_LITERAL("/.svn/")) != std::string::npos) { 115 if (file.value().find(FILE_PATH_LITERAL("/.svn/")) != std::string::npos) {
150 file = file_list.Next(); 116 file = file_list.Next();
151 continue; 117 continue;
152 } 118 }
153 119
154 BalsaHeaders request_headers, response_headers;
155
156 string file_contents; 120 string file_contents;
157 base::ReadFileToString(file, &file_contents); 121 base::ReadFileToString(file, &file_contents);
158 122
159 // Frame HTTP. 123 int headers_end = HttpUtil::LocateEndOfHeaders(file_contents.c_str(),
160 CachingBalsaVisitor caching_visitor; 124 file_contents.size());
161 BalsaFrame framer; 125 if (headers_end < 1) {
162 framer.set_balsa_headers(&response_headers); 126 LOG(DFATAL) << "Could not find end of headers in file: " << file.value();
163 framer.set_balsa_visitor(&caching_visitor);
164 size_t processed = 0;
165 while (processed < file_contents.length() &&
166 !caching_visitor.done_framing()) {
167 processed += framer.ProcessInput(file_contents.c_str() + processed,
168 file_contents.length() - processed);
169 } 127 }
170 128
171 string response_headers_str; 129 string raw_headers =
172 response_headers.DumpToString(&response_headers_str); 130 HttpUtil::AssembleRawHeaders(file_contents.c_str(), headers_end);
173 if (!caching_visitor.done_framing()) {
174 LOG(DFATAL) << "Did not frame entire message from file: " << file.value()
175 << " (" << processed << " of " << file_contents.length()
176 << " bytes).";
177 }
178 if (processed < file_contents.length()) {
179 // Didn't frame whole file. Assume remainder is body.
180 // This sometimes happens as a result of incompatibilities between
181 // BalsaFramer and wget's serialization of HTTP sans content-length.
182 caching_visitor.AppendToBody(file_contents.c_str() + processed,
183 file_contents.length() - processed);
184 processed += file_contents.length();
185 }
186 131
187 string utf8_file = file.AsUTF8Unsafe(); 132 scoped_refptr<HttpResponseHeaders> response_headers =
188 StringPiece base = utf8_file; 133 new HttpResponseHeaders(raw_headers);
189 if (response_headers.HasHeader("X-Original-Url")) { 134
190 base = response_headers.GetHeader("X-Original-Url"); 135 string base_str;
191 response_headers.RemoveAllOfHeader("X-Original-Url"); 136 StringPiece base;
137 if (response_headers->HasHeader("X-Original-Url")) {
138 if (!response_headers->GetNormalizedHeader("X-Original-Url", &base_str)) {
139 LOG(DFATAL) << "Failed to read X-Original-Url in file: "
140 << file.value();
141 }
142 base = base_str;
143 response_headers->RemoveHeader("X-Original-Url");
192 // Remove the protocol so that the string is of the form host + path, 144 // Remove the protocol so that the string is of the form host + path,
193 // which is parsed properly below. 145 // which is parsed properly below.
194 if (StringPieceUtils::StartsWithIgnoreCase(base, "https://")) { 146 if (StringPieceUtils::StartsWithIgnoreCase(base, "https://")) {
195 base.remove_prefix(8); 147 base.remove_prefix(8);
196 } else if (StringPieceUtils::StartsWithIgnoreCase(base, "http://")) { 148 } else if (StringPieceUtils::StartsWithIgnoreCase(base, "http://")) {
197 base.remove_prefix(7); 149 base.remove_prefix(7);
198 } 150 }
151 } else {
152 base_str = file.AsUTF8Unsafe();
153 base = base_str;
199 } 154 }
200 int path_start = base.find_first_of('/'); 155 int path_start = base.find_first_of('/');
201 DCHECK_LT(0, path_start); 156 DCHECK_LT(0, path_start);
202 StringPiece host(base.substr(0, path_start)); 157 StringPiece host(base.substr(0, path_start));
203 StringPiece path(base.substr(path_start)); 158 StringPiece path(base.substr(path_start));
204 if (path[path.length() - 1] == ',') { 159 if (path[path.length() - 1] == ',') {
205 path.remove_suffix(1); 160 path.remove_suffix(1);
206 } 161 }
207 // Set up request headers. Assume method is GET and protocol is HTTP/1.1. 162 // Set up request headers. Assume method is GET and protocol is HTTP/1.1.
208 request_headers.SetRequestFirstlineFromStringPieces("GET", 163 HttpRequestLine request_line("GET", path, "HTTP/1.1", host);
209 path,
210 "HTTP/1.1");
211 request_headers.ReplaceOrAppendHeader("host", host);
212 164
213 VLOG(1) << "Inserting 'http://" << GetKey(request_headers) 165 VLOG(1) << "Inserting 'http://" << request_line.FullPath()
214 << "' into QuicInMemoryCache."; 166 << "' into QuicInMemoryCache.";
215 167
216 AddResponse(request_headers, response_headers, caching_visitor.body()); 168 StringPiece body(file_contents.c_str() + headers_end,
169 file_contents.size() - headers_end);
170
171 AddResponse(request_line, response_headers, body);
217 172
218 file = file_list.Next(); 173 file = file_list.Next();
219 } 174 }
220 } 175 }
221 176
222 QuicInMemoryCache::~QuicInMemoryCache() { 177 QuicInMemoryCache::~QuicInMemoryCache() {
223 STLDeleteValues(&responses_); 178 STLDeleteValues(&responses_);
224 } 179 }
225 180
226 string QuicInMemoryCache::GetKey(const BalsaHeaders& request_headers) const {
227 StringPiece uri = request_headers.request_uri();
228 if (uri.size() == 0) {
229 return "";
230 }
231 StringPiece host;
232 if (uri[0] == '/') {
233 host = request_headers.GetHeader("host");
234 } else if (StringPieceUtils::StartsWithIgnoreCase(uri, "https://")) {
235 uri.remove_prefix(8);
236 } else if (StringPieceUtils::StartsWithIgnoreCase(uri, "http://")) {
237 uri.remove_prefix(7);
238 }
239 return host.as_string() + uri.as_string();
240 }
241
242 } // namespace net 181 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698