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

Side by Side Diff: net/websockets/websocket_handshake_handler.cc

Issue 266243004: Clang format slam. Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 7 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 | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 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/websockets/websocket_handshake_handler.h" 5 #include "net/websockets/websocket_handshake_handler.h"
6 6
7 #include <limits> 7 #include <limits>
8 8
9 #include "base/base64.h" 9 #include "base/base64.h"
10 #include "base/sha1.h" 10 #include "base/sha1.h"
11 #include "base/strings/string_number_conversions.h" 11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_piece.h" 12 #include "base/strings/string_piece.h"
13 #include "base/strings/string_tokenizer.h" 13 #include "base/strings/string_tokenizer.h"
14 #include "base/strings/string_util.h" 14 #include "base/strings/string_util.h"
15 #include "base/strings/stringprintf.h" 15 #include "base/strings/stringprintf.h"
16 #include "net/http/http_request_headers.h" 16 #include "net/http/http_request_headers.h"
17 #include "net/http/http_response_headers.h" 17 #include "net/http/http_response_headers.h"
18 #include "net/http/http_util.h" 18 #include "net/http/http_util.h"
19 #include "net/websockets/websocket_handshake_constants.h" 19 #include "net/websockets/websocket_handshake_constants.h"
20 #include "url/gurl.h" 20 #include "url/gurl.h"
21 21
22 namespace net { 22 namespace net {
23 namespace { 23 namespace {
24 24
25 const int kVersionHeaderValueForRFC6455 = 13; 25 const int kVersionHeaderValueForRFC6455 = 13;
26 26
27 // Splits |handshake_message| into Status-Line or Request-Line (including CRLF) 27 // Splits |handshake_message| into Status-Line or Request-Line (including CRLF)
28 // and headers (excluding 2nd CRLF of double CRLFs at the end of a handshake 28 // and headers (excluding 2nd CRLF of double CRLFs at the end of a handshake
29 // response). 29 // response).
30 void ParseHandshakeHeader( 30 void ParseHandshakeHeader(const char* handshake_message,
31 const char* handshake_message, int len, 31 int len,
32 std::string* request_line, 32 std::string* request_line,
33 std::string* headers) { 33 std::string* headers) {
34 size_t i = base::StringPiece(handshake_message, len).find_first_of("\r\n"); 34 size_t i = base::StringPiece(handshake_message, len).find_first_of("\r\n");
35 if (i == base::StringPiece::npos) { 35 if (i == base::StringPiece::npos) {
36 *request_line = std::string(handshake_message, len); 36 *request_line = std::string(handshake_message, len);
37 *headers = ""; 37 *headers = "";
38 return; 38 return;
39 } 39 }
40 // |request_line| includes \r\n. 40 // |request_line| includes \r\n.
41 *request_line = std::string(handshake_message, i + 2); 41 *request_line = std::string(handshake_message, i + 2);
42 42
43 int header_len = len - (i + 2) - 2; 43 int header_len = len - (i + 2) - 2;
44 if (header_len > 0) { 44 if (header_len > 0) {
45 // |handshake_message| includes trailing \r\n\r\n. 45 // |handshake_message| includes trailing \r\n\r\n.
46 // |headers| doesn't include 2nd \r\n. 46 // |headers| doesn't include 2nd \r\n.
47 *headers = std::string(handshake_message + i + 2, header_len); 47 *headers = std::string(handshake_message + i + 2, header_len);
48 } else { 48 } else {
49 *headers = ""; 49 *headers = "";
50 } 50 }
51 } 51 }
52 52
53 void FetchHeaders(const std::string& headers, 53 void FetchHeaders(const std::string& headers,
54 const char* const headers_to_get[], 54 const char* const headers_to_get[],
55 size_t headers_to_get_len, 55 size_t headers_to_get_len,
56 std::vector<std::string>* values) { 56 std::vector<std::string>* values) {
57 net::HttpUtil::HeadersIterator iter(headers.begin(), headers.end(), "\r\n"); 57 net::HttpUtil::HeadersIterator iter(headers.begin(), headers.end(), "\r\n");
58 while (iter.GetNext()) { 58 while (iter.GetNext()) {
59 for (size_t i = 0; i < headers_to_get_len; i++) { 59 for (size_t i = 0; i < headers_to_get_len; i++) {
60 if (LowerCaseEqualsASCII(iter.name_begin(), iter.name_end(), 60 if (LowerCaseEqualsASCII(
61 headers_to_get[i])) { 61 iter.name_begin(), iter.name_end(), headers_to_get[i])) {
62 values->push_back(iter.values()); 62 values->push_back(iter.values());
63 } 63 }
64 } 64 }
65 } 65 }
66 } 66 }
67 67
68 bool GetHeaderName(std::string::const_iterator line_begin, 68 bool GetHeaderName(std::string::const_iterator line_begin,
69 std::string::const_iterator line_end, 69 std::string::const_iterator line_end,
70 std::string::const_iterator* name_begin, 70 std::string::const_iterator* name_begin,
71 std::string::const_iterator* name_end) { 71 std::string::const_iterator* name_end) {
72 std::string::const_iterator colon = std::find(line_begin, line_end, ':'); 72 std::string::const_iterator colon = std::find(line_begin, line_end, ':');
73 if (colon == line_end) { 73 if (colon == line_end) {
74 return false; 74 return false;
75 } 75 }
76 *name_begin = line_begin; 76 *name_begin = line_begin;
77 *name_end = colon; 77 *name_end = colon;
78 if (*name_begin == *name_end || net::HttpUtil::IsLWS(**name_begin)) 78 if (*name_begin == *name_end || net::HttpUtil::IsLWS(**name_begin))
79 return false; 79 return false;
80 net::HttpUtil::TrimLWS(name_begin, name_end); 80 net::HttpUtil::TrimLWS(name_begin, name_end);
81 return true; 81 return true;
82 } 82 }
83 83
84 // Similar to HttpUtil::StripHeaders, but it preserves malformed headers, that 84 // Similar to HttpUtil::StripHeaders, but it preserves malformed headers, that
85 // is, lines that are not formatted as "<name>: <value>\r\n". 85 // is, lines that are not formatted as "<name>: <value>\r\n".
86 std::string FilterHeaders( 86 std::string FilterHeaders(const std::string& headers,
87 const std::string& headers, 87 const char* const headers_to_remove[],
88 const char* const headers_to_remove[], 88 size_t headers_to_remove_len) {
89 size_t headers_to_remove_len) {
90 std::string filtered_headers; 89 std::string filtered_headers;
91 90
92 base::StringTokenizer lines(headers.begin(), headers.end(), "\r\n"); 91 base::StringTokenizer lines(headers.begin(), headers.end(), "\r\n");
93 while (lines.GetNext()) { 92 while (lines.GetNext()) {
94 std::string::const_iterator line_begin = lines.token_begin(); 93 std::string::const_iterator line_begin = lines.token_begin();
95 std::string::const_iterator line_end = lines.token_end(); 94 std::string::const_iterator line_end = lines.token_end();
96 std::string::const_iterator name_begin; 95 std::string::const_iterator name_begin;
97 std::string::const_iterator name_end; 96 std::string::const_iterator name_end;
98 bool should_remove = false; 97 bool should_remove = false;
99 if (GetHeaderName(line_begin, line_end, &name_begin, &name_end)) { 98 if (GetHeaderName(line_begin, line_end, &name_begin, &name_end)) {
100 for (size_t i = 0; i < headers_to_remove_len; ++i) { 99 for (size_t i = 0; i < headers_to_remove_len; ++i) {
101 if (LowerCaseEqualsASCII(name_begin, name_end, headers_to_remove[i])) { 100 if (LowerCaseEqualsASCII(name_begin, name_end, headers_to_remove[i])) {
102 should_remove = true; 101 should_remove = true;
103 break; 102 break;
104 } 103 }
105 } 104 }
106 } 105 }
107 if (!should_remove) { 106 if (!should_remove) {
108 filtered_headers.append(line_begin, line_end); 107 filtered_headers.append(line_begin, line_end);
109 filtered_headers.append("\r\n"); 108 filtered_headers.append("\r\n");
110 } 109 }
111 } 110 }
112 return filtered_headers; 111 return filtered_headers;
113 } 112 }
114 113
115 bool CheckVersionInRequest(const std::string& request_headers) { 114 bool CheckVersionInRequest(const std::string& request_headers) {
116 std::vector<std::string> values; 115 std::vector<std::string> values;
117 const char* const headers_to_get[1] = { 116 const char* const headers_to_get[1] = {
118 websockets::kSecWebSocketVersionLowercase}; 117 websockets::kSecWebSocketVersionLowercase};
119 FetchHeaders(request_headers, headers_to_get, 1, &values); 118 FetchHeaders(request_headers, headers_to_get, 1, &values);
120 DCHECK_LE(values.size(), 1U); 119 DCHECK_LE(values.size(), 1U);
121 if (values.empty()) 120 if (values.empty())
122 return false; 121 return false;
123 122
124 int version; 123 int version;
125 bool conversion_success = base::StringToInt(values[0], &version); 124 bool conversion_success = base::StringToInt(values[0], &version);
126 if (!conversion_success) 125 if (!conversion_success)
127 return false; 126 return false;
128 127
(...skipping 16 matching lines...) Expand all
145 response_message->reserve(response_message->size() + extra_size); 144 response_message->reserve(response_message->size() + extra_size);
146 response_message->append(header.begin(), header.end()); 145 response_message->append(header.begin(), header.end());
147 response_message->append(kColonSpace, kColonSpace + kColonSpaceSize); 146 response_message->append(kColonSpace, kColonSpace + kColonSpaceSize);
148 response_message->append(value.begin(), value.end()); 147 response_message->append(value.begin(), value.end());
149 response_message->append(kCrNl, kCrNl + kCrNlSize); 148 response_message->append(kCrNl, kCrNl + kCrNlSize);
150 } 149 }
151 150
152 } // namespace 151 } // namespace
153 152
154 WebSocketHandshakeRequestHandler::WebSocketHandshakeRequestHandler() 153 WebSocketHandshakeRequestHandler::WebSocketHandshakeRequestHandler()
155 : original_length_(0), 154 : original_length_(0), raw_length_(0) {
156 raw_length_(0) {} 155 }
157 156
158 bool WebSocketHandshakeRequestHandler::ParseRequest( 157 bool WebSocketHandshakeRequestHandler::ParseRequest(const char* data,
159 const char* data, int length) { 158 int length) {
160 DCHECK_GT(length, 0); 159 DCHECK_GT(length, 0);
161 std::string input(data, length); 160 std::string input(data, length);
162 int input_header_length = 161 int input_header_length =
163 HttpUtil::LocateEndOfHeaders(input.data(), input.size(), 0); 162 HttpUtil::LocateEndOfHeaders(input.data(), input.size(), 0);
164 if (input_header_length <= 0) 163 if (input_header_length <= 0)
165 return false; 164 return false;
166 165
167 ParseHandshakeHeader(input.data(), 166 ParseHandshakeHeader(
168 input_header_length, 167 input.data(), input_header_length, &request_line_, &headers_);
169 &request_line_,
170 &headers_);
171 168
172 if (!CheckVersionInRequest(headers_)) { 169 if (!CheckVersionInRequest(headers_)) {
173 NOTREACHED(); 170 NOTREACHED();
174 return false; 171 return false;
175 } 172 }
176 173
177 original_length_ = input_header_length; 174 original_length_ = input_header_length;
178 return true; 175 return true;
179 } 176 }
180 177
181 size_t WebSocketHandshakeRequestHandler::original_length() const { 178 size_t WebSocketHandshakeRequestHandler::original_length() const {
182 return original_length_; 179 return original_length_;
183 } 180 }
184 181
185 void WebSocketHandshakeRequestHandler::AppendHeaderIfMissing( 182 void WebSocketHandshakeRequestHandler::AppendHeaderIfMissing(
186 const std::string& name, const std::string& value) { 183 const std::string& name,
184 const std::string& value) {
187 DCHECK(!headers_.empty()); 185 DCHECK(!headers_.empty());
188 HttpUtil::AppendHeaderIfMissing(name.c_str(), value, &headers_); 186 HttpUtil::AppendHeaderIfMissing(name.c_str(), value, &headers_);
189 } 187 }
190 188
191 void WebSocketHandshakeRequestHandler::RemoveHeaders( 189 void WebSocketHandshakeRequestHandler::RemoveHeaders(
192 const char* const headers_to_remove[], 190 const char* const headers_to_remove[],
193 size_t headers_to_remove_len) { 191 size_t headers_to_remove_len) {
194 DCHECK(!headers_.empty()); 192 DCHECK(!headers_.empty());
195 headers_ = FilterHeaders( 193 headers_ = FilterHeaders(headers_, headers_to_remove, headers_to_remove_len);
196 headers_, headers_to_remove, headers_to_remove_len);
197 } 194 }
198 195
199 HttpRequestInfo WebSocketHandshakeRequestHandler::GetRequestInfo( 196 HttpRequestInfo WebSocketHandshakeRequestHandler::GetRequestInfo(
200 const GURL& url, std::string* challenge) { 197 const GURL& url,
198 std::string* challenge) {
201 HttpRequestInfo request_info; 199 HttpRequestInfo request_info;
202 request_info.url = url; 200 request_info.url = url;
203 size_t method_end = base::StringPiece(request_line_).find_first_of(" "); 201 size_t method_end = base::StringPiece(request_line_).find_first_of(" ");
204 if (method_end != base::StringPiece::npos) 202 if (method_end != base::StringPiece::npos)
205 request_info.method = std::string(request_line_.data(), method_end); 203 request_info.method = std::string(request_line_.data(), method_end);
206 204
207 request_info.extra_headers.Clear(); 205 request_info.extra_headers.Clear();
208 request_info.extra_headers.AddHeadersFromString(headers_); 206 request_info.extra_headers.AddHeadersFromString(headers_);
209 207
210 request_info.extra_headers.RemoveHeader(websockets::kUpgrade); 208 request_info.extra_headers.RemoveHeader(websockets::kUpgrade);
211 request_info.extra_headers.RemoveHeader(HttpRequestHeaders::kConnection); 209 request_info.extra_headers.RemoveHeader(HttpRequestHeaders::kConnection);
212 210
213 std::string key; 211 std::string key;
214 bool header_present = request_info.extra_headers.GetHeader( 212 bool header_present =
215 websockets::kSecWebSocketKey, &key); 213 request_info.extra_headers.GetHeader(websockets::kSecWebSocketKey, &key);
216 DCHECK(header_present); 214 DCHECK(header_present);
217 request_info.extra_headers.RemoveHeader(websockets::kSecWebSocketKey); 215 request_info.extra_headers.RemoveHeader(websockets::kSecWebSocketKey);
218 *challenge = key; 216 *challenge = key;
219 return request_info; 217 return request_info;
220 } 218 }
221 219
222 bool WebSocketHandshakeRequestHandler::GetRequestHeaderBlock( 220 bool WebSocketHandshakeRequestHandler::GetRequestHeaderBlock(
223 const GURL& url, 221 const GURL& url,
224 SpdyHeaderBlock* headers, 222 SpdyHeaderBlock* headers,
225 std::string* challenge, 223 std::string* challenge,
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
299 raw_length_ = raw_request.size(); 297 raw_length_ = raw_request.size();
300 return raw_request; 298 return raw_request;
301 } 299 }
302 300
303 size_t WebSocketHandshakeRequestHandler::raw_length() const { 301 size_t WebSocketHandshakeRequestHandler::raw_length() const {
304 DCHECK_GT(raw_length_, 0); 302 DCHECK_GT(raw_length_, 0);
305 return raw_length_; 303 return raw_length_;
306 } 304 }
307 305
308 WebSocketHandshakeResponseHandler::WebSocketHandshakeResponseHandler() 306 WebSocketHandshakeResponseHandler::WebSocketHandshakeResponseHandler()
309 : original_header_length_(0) {} 307 : original_header_length_(0) {
308 }
310 309
311 WebSocketHandshakeResponseHandler::~WebSocketHandshakeResponseHandler() {} 310 WebSocketHandshakeResponseHandler::~WebSocketHandshakeResponseHandler() {
311 }
312 312
313 size_t WebSocketHandshakeResponseHandler::ParseRawResponse( 313 size_t WebSocketHandshakeResponseHandler::ParseRawResponse(const char* data,
314 const char* data, int length) { 314 int length) {
315 DCHECK_GT(length, 0); 315 DCHECK_GT(length, 0);
316 if (HasResponse()) { 316 if (HasResponse()) {
317 DCHECK(!status_line_.empty()); 317 DCHECK(!status_line_.empty());
318 // headers_ might be empty for wrong response from server. 318 // headers_ might be empty for wrong response from server.
319 319
320 return 0; 320 return 0;
321 } 321 }
322 322
323 size_t old_original_length = original_.size(); 323 size_t old_original_length = original_.size();
324 324
325 original_.append(data, length); 325 original_.append(data, length);
326 // TODO(ukai): fail fast when response gives wrong status code. 326 // TODO(ukai): fail fast when response gives wrong status code.
327 original_header_length_ = HttpUtil::LocateEndOfHeaders( 327 original_header_length_ =
328 original_.data(), original_.size(), 0); 328 HttpUtil::LocateEndOfHeaders(original_.data(), original_.size(), 0);
329 if (!HasResponse()) 329 if (!HasResponse())
330 return length; 330 return length;
331 331
332 ParseHandshakeHeader(original_.data(), 332 ParseHandshakeHeader(
333 original_header_length_, 333 original_.data(), original_header_length_, &status_line_, &headers_);
334 &status_line_,
335 &headers_);
336 int header_size = status_line_.size() + headers_.size(); 334 int header_size = status_line_.size() + headers_.size();
337 DCHECK_GE(original_header_length_, header_size); 335 DCHECK_GE(original_header_length_, header_size);
338 header_separator_ = std::string(original_.data() + header_size, 336 header_separator_ = std::string(original_.data() + header_size,
339 original_header_length_ - header_size); 337 original_header_length_ - header_size);
340 return original_header_length_ - old_original_length; 338 return original_header_length_ - old_original_length;
341 } 339 }
342 340
343 bool WebSocketHandshakeResponseHandler::HasResponse() const { 341 bool WebSocketHandshakeResponseHandler::HasResponse() const {
344 return original_header_length_ > 0 && 342 return original_header_length_ > 0 &&
345 static_cast<size_t>(original_header_length_) <= original_.size(); 343 static_cast<size_t>(original_header_length_) <= original_.size();
346 } 344 }
347 345
348 void ComputeSecWebSocketAccept(const std::string& key, 346 void ComputeSecWebSocketAccept(const std::string& key, std::string* accept) {
349 std::string* accept) {
350 DCHECK(accept); 347 DCHECK(accept);
351 348
352 std::string hash = 349 std::string hash = base::SHA1HashString(key + websockets::kWebSocketGuid);
353 base::SHA1HashString(key + websockets::kWebSocketGuid);
354 base::Base64Encode(hash, accept); 350 base::Base64Encode(hash, accept);
355 } 351 }
356 352
357 bool WebSocketHandshakeResponseHandler::ParseResponseInfo( 353 bool WebSocketHandshakeResponseHandler::ParseResponseInfo(
358 const HttpResponseInfo& response_info, 354 const HttpResponseInfo& response_info,
359 const std::string& challenge) { 355 const std::string& challenge) {
360 if (!response_info.headers.get()) 356 if (!response_info.headers.get())
361 return false; 357 return false;
362 358
363 // TODO(ricea): Eliminate all the reallocations and string copies. 359 // TODO(ricea): Eliminate all the reallocations and string copies.
364 std::string response_message; 360 std::string response_message;
365 response_message = response_info.headers->GetStatusLine(); 361 response_message = response_info.headers->GetStatusLine();
366 response_message += "\r\n"; 362 response_message += "\r\n";
367 363
368 AppendHeader(websockets::kUpgrade, 364 AppendHeader(
369 websockets::kWebSocketLowercase, 365 websockets::kUpgrade, websockets::kWebSocketLowercase, &response_message);
370 &response_message);
371 366
372 AppendHeader( 367 AppendHeader(
373 HttpRequestHeaders::kConnection, websockets::kUpgrade, &response_message); 368 HttpRequestHeaders::kConnection, websockets::kUpgrade, &response_message);
374 369
375 std::string websocket_accept; 370 std::string websocket_accept;
376 ComputeSecWebSocketAccept(challenge, &websocket_accept); 371 ComputeSecWebSocketAccept(challenge, &websocket_accept);
377 AppendHeader( 372 AppendHeader(
378 websockets::kSecWebSocketAccept, websocket_accept, &response_message); 373 websockets::kSecWebSocketAccept, websocket_accept, &response_message);
379 374
380 void* iter = NULL; 375 void* iter = NULL;
381 std::string name; 376 std::string name;
382 std::string value; 377 std::string value;
383 while (response_info.headers->EnumerateHeaderLines(&iter, &name, &value)) { 378 while (response_info.headers->EnumerateHeaderLines(&iter, &name, &value)) {
384 AppendHeader(name, value, &response_message); 379 AppendHeader(name, value, &response_message);
385 } 380 }
386 response_message += "\r\n"; 381 response_message += "\r\n";
387 382
388 return ParseRawResponse(response_message.data(), 383 return ParseRawResponse(response_message.data(), response_message.size()) ==
389 response_message.size()) == response_message.size(); 384 response_message.size();
390 } 385 }
391 386
392 bool WebSocketHandshakeResponseHandler::ParseResponseHeaderBlock( 387 bool WebSocketHandshakeResponseHandler::ParseResponseHeaderBlock(
393 const SpdyHeaderBlock& headers, 388 const SpdyHeaderBlock& headers,
394 const std::string& challenge, 389 const std::string& challenge,
395 int spdy_protocol_version) { 390 int spdy_protocol_version) {
396 SpdyHeaderBlock::const_iterator status; 391 SpdyHeaderBlock::const_iterator status;
397 if (spdy_protocol_version <= 2) 392 if (spdy_protocol_version <= 2)
398 status = headers.find("status"); 393 status = headers.find("status");
399 else 394 else
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
446 LowerCaseEqualsASCII(iter->first, 441 LowerCaseEqualsASCII(iter->first,
447 websockets::kSecWebSocketExtensionsSpdy3))) 442 websockets::kSecWebSocketExtensionsSpdy3)))
448 AppendHeader(iter->first.substr(1), tval, &response_message); 443 AppendHeader(iter->first.substr(1), tval, &response_message);
449 else 444 else
450 AppendHeader(iter->first, tval, &response_message); 445 AppendHeader(iter->first, tval, &response_message);
451 start = end + 1; 446 start = end + 1;
452 } while (end != std::string::npos); 447 } while (end != std::string::npos);
453 } 448 }
454 response_message += "\r\n"; 449 response_message += "\r\n";
455 450
456 return ParseRawResponse(response_message.data(), 451 return ParseRawResponse(response_message.data(), response_message.size()) ==
457 response_message.size()) == response_message.size(); 452 response_message.size();
458 } 453 }
459 454
460 void WebSocketHandshakeResponseHandler::GetHeaders( 455 void WebSocketHandshakeResponseHandler::GetHeaders(
461 const char* const headers_to_get[], 456 const char* const headers_to_get[],
462 size_t headers_to_get_len, 457 size_t headers_to_get_len,
463 std::vector<std::string>* values) { 458 std::vector<std::string>* values) {
464 DCHECK(HasResponse()); 459 DCHECK(HasResponse());
465 DCHECK(!status_line_.empty()); 460 DCHECK(!status_line_.empty());
466 // headers_ might be empty for wrong response from server. 461 // headers_ might be empty for wrong response from server.
467 if (headers_.empty()) 462 if (headers_.empty())
(...skipping 21 matching lines...) Expand all
489 484
490 std::string WebSocketHandshakeResponseHandler::GetResponse() { 485 std::string WebSocketHandshakeResponseHandler::GetResponse() {
491 DCHECK(HasResponse()); 486 DCHECK(HasResponse());
492 DCHECK(!status_line_.empty()); 487 DCHECK(!status_line_.empty());
493 // headers_ might be empty for wrong response from server. 488 // headers_ might be empty for wrong response from server.
494 489
495 return status_line_ + headers_ + header_separator_; 490 return status_line_ + headers_ + header_separator_;
496 } 491 }
497 492
498 } // namespace net 493 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698