blob: 56ec4496ba5cc77bc85c18f8a7520f614420b97c [file] [log] [blame]
initial.commit586acc5fe2008-07-26 22:42:521// Copyright 2008, Google Inc.
2// All rights reserved.
3//
4// Redistribution and use in source and binary forms, with or without
5// modification, are permitted provided that the following conditions are
6// met:
7//
8// * Redistributions of source code must retain the above copyright
9// notice, this list of conditions and the following disclaimer.
10// * Redistributions in binary form must reproduce the above
11// copyright notice, this list of conditions and the following disclaimer
12// in the documentation and/or other materials provided with the
13// distribution.
14// * Neither the name of Google Inc. nor the names of its
15// contributors may be used to endorse or promote products derived from
16// this software without specific prior written permission.
17//
18// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30#include "net/http/http_network_transaction.h"
31
32#include "base/string_util.h"
33#include "net/base/client_socket_factory.h"
34#include "net/base/host_resolver.h"
35#include "net/base/load_flags.h"
36#include "net/base/upload_data_stream.h"
37#include "net/http/http_chunked_decoder.h"
38#include "net/http/http_network_session.h"
39#include "net/http/http_request_info.h"
40#include "net/http/http_util.h"
41
42// TODO(darin):
43// - authentication
44// - proxies (need to call ReconsiderProxyAfterError and handle SSL tunnel)
45// - ssl
46// - http/0.9
47// - header line continuations (i.e., lines that start with LWS)
48// - tolerate some junk (up to 4 bytes) in front of the HTTP/1.x status line
49
50namespace net {
51
52//-----------------------------------------------------------------------------
53
initial.commit586acc5fe2008-07-26 22:42:5254HttpNetworkTransaction::HttpNetworkTransaction(HttpNetworkSession* session,
55 ClientSocketFactory* csf)
56#pragma warning(suppress: 4355)
57 : io_callback_(this, &HttpNetworkTransaction::OnIOComplete),
58 user_callback_(NULL),
59 session_(session),
60 request_(NULL),
61 pac_request_(NULL),
62 socket_factory_(csf),
[email protected]e1e06262008-08-06 23:57:0763 connection_(session->connection_pool()),
initial.commit586acc5fe2008-07-26 22:42:5264 reused_socket_(false),
65 using_ssl_(false),
66 using_proxy_(false),
67 using_tunnel_(false),
[email protected]96d570e42008-08-05 22:43:0468 request_headers_bytes_sent_(0),
initial.commit586acc5fe2008-07-26 22:42:5269 header_buf_capacity_(0),
70 header_buf_len_(0),
71 header_buf_body_offset_(-1),
72 content_length_(-1), // -1 means unspecified.
73 content_read_(0),
74 read_buf_(NULL),
75 read_buf_len_(0),
76 next_state_(STATE_NONE) {
77}
78
[email protected]96d570e42008-08-05 22:43:0479void HttpNetworkTransaction::Destroy() {
80 delete this;
81}
82
83int HttpNetworkTransaction::Start(const HttpRequestInfo* request_info,
84 CompletionCallback* callback) {
85 request_ = request_info;
86
87 next_state_ = STATE_RESOLVE_PROXY;
88 int rv = DoLoop(OK);
89 if (rv == ERR_IO_PENDING)
90 user_callback_ = callback;
91 return rv;
92}
93
94int HttpNetworkTransaction::RestartIgnoringLastError(
95 CompletionCallback* callback) {
96 return ERR_FAILED; // TODO(darin): implement me!
97}
98
99int HttpNetworkTransaction::RestartWithAuth(
100 const std::wstring& username,
101 const std::wstring& password,
102 CompletionCallback* callback) {
103 return ERR_FAILED; // TODO(darin): implement me!
104}
105
106int HttpNetworkTransaction::Read(char* buf, int buf_len,
107 CompletionCallback* callback) {
108 DCHECK(response_.headers);
109 DCHECK(buf);
110 DCHECK(buf_len > 0);
111
112 if (!connection_.is_initialized())
113 return 0; // connection_ has been reset. Treat like EOF.
114
115 read_buf_ = buf;
116 read_buf_len_ = buf_len;
117
118 next_state_ = STATE_READ_BODY;
119 int rv = DoLoop(OK);
120 if (rv == ERR_IO_PENDING)
121 user_callback_ = callback;
122 return rv;
123}
124
125const HttpResponseInfo* HttpNetworkTransaction::GetResponseInfo() const {
126 return response_.headers ? &response_ : NULL;
127}
128
129LoadState HttpNetworkTransaction::GetLoadState() const {
130 // TODO(wtc): Define a new LoadState value for the
131 // STATE_INIT_CONNECTION_COMPLETE state, which delays the HTTP request.
132 switch (next_state_) {
133 case STATE_RESOLVE_PROXY_COMPLETE:
134 return LOAD_STATE_RESOLVING_PROXY_FOR_URL;
135 case STATE_RESOLVE_HOST_COMPLETE:
136 return LOAD_STATE_RESOLVING_HOST;
137 case STATE_CONNECT_COMPLETE:
138 return LOAD_STATE_CONNECTING;
139 case STATE_WRITE_HEADERS_COMPLETE:
140 case STATE_WRITE_BODY_COMPLETE:
141 return LOAD_STATE_SENDING_REQUEST;
142 case STATE_READ_HEADERS_COMPLETE:
143 return LOAD_STATE_WAITING_FOR_RESPONSE;
144 case STATE_READ_BODY_COMPLETE:
145 return LOAD_STATE_READING_RESPONSE;
146 default:
147 return LOAD_STATE_IDLE;
148 }
149}
150
151uint64 HttpNetworkTransaction::GetUploadProgress() const {
152 if (!request_body_stream_.get())
153 return 0;
154
155 return request_body_stream_->position();
156}
157
initial.commit586acc5fe2008-07-26 22:42:52158HttpNetworkTransaction::~HttpNetworkTransaction() {
159 // If we still have an open socket, then make sure to close it so we don't
160 // try to reuse it later on.
161 if (connection_.is_initialized())
162 connection_.set_socket(NULL);
163
164 if (pac_request_)
165 session_->proxy_service()->CancelPacRequest(pac_request_);
166}
167
168void HttpNetworkTransaction::BuildRequestHeaders() {
169 std::string path;
170 if (using_proxy_) {
171 // TODO(darin): GURL should have a method for this.
172 path = request_->url.spec();
173 size_t ref_pos = path.rfind('#');
174 if (ref_pos != std::string::npos)
175 path.erase(ref_pos);
176 } else {
177 path = request_->url.PathForRequest();
178 }
179
180 request_headers_ = request_->method + " " + path + " HTTP/1.1\r\n" +
181 "Host: " + request_->url.host();
182 if (request_->url.IntPort() != -1)
183 request_headers_ += ":" + request_->url.port();
184 request_headers_ += "\r\n";
185
186 // For compat with HTTP/1.0 servers and proxies:
187 if (using_proxy_)
188 request_headers_ += "Proxy-";
189 request_headers_ += "Connection: keep-alive\r\n";
190
191 if (!request_->user_agent.empty())
192 request_headers_ += "User-Agent: " + request_->user_agent + "\r\n";
193
194 // Our consumer should have made sure that this is a safe referrer. See for
195 // instance WebCore::FrameLoader::HideReferrer.
196 if (request_->referrer.is_valid())
197 request_headers_ += "Referer: " + request_->referrer.spec() + "\r\n";
198
199 // Add a content length header?
200 if (request_->upload_data) {
201 request_body_stream_.reset(new UploadDataStream(request_->upload_data));
202 request_headers_ +=
203 "Content-Length: " + Uint64ToString(request_body_stream_->size()) +
204 "\r\n";
205 } else if (request_->method == "POST" || request_->method == "PUT" ||
206 request_->method == "HEAD") {
207 // An empty POST/PUT request still needs a content length. As for HEAD,
208 // IE and Safari also add a content length header. Presumably it is to
209 // support sending a HEAD request to an URL that only expects to be sent a
210 // POST or some other method that normally would have a message body.
211 request_headers_ += "Content-Length: 0\r\n";
212 }
213
214 // Honor load flags that impact proxy caches.
215 if (request_->load_flags & LOAD_BYPASS_CACHE) {
216 request_headers_ += "Pragma: no-cache\r\nCache-Control: no-cache\r\n";
217 } else if (request_->load_flags & LOAD_VALIDATE_CACHE) {
218 request_headers_ += "Cache-Control: max-age=0\r\n";
219 }
220
221 // TODO(darin): Need to prune out duplicate headers.
222
223 request_headers_ += request_->extra_headers;
224 request_headers_ += "\r\n";
225}
226
227void HttpNetworkTransaction::DoCallback(int rv) {
228 DCHECK(rv != ERR_IO_PENDING);
229 DCHECK(user_callback_);
230
[email protected]96d570e42008-08-05 22:43:04231 // Since Run may result in Read being called, clear user_callback_ up front.
initial.commit586acc5fe2008-07-26 22:42:52232 CompletionCallback* c = user_callback_;
233 user_callback_ = NULL;
234 c->Run(rv);
235}
236
237void HttpNetworkTransaction::OnIOComplete(int result) {
238 int rv = DoLoop(result);
239 if (rv != ERR_IO_PENDING)
240 DoCallback(rv);
241}
242
243int HttpNetworkTransaction::DoLoop(int result) {
244 DCHECK(next_state_ != STATE_NONE);
245
246 int rv = result;
247 do {
248 State state = next_state_;
249 next_state_ = STATE_NONE;
250 switch (state) {
251 case STATE_RESOLVE_PROXY:
[email protected]96d570e42008-08-05 22:43:04252 DCHECK(rv == OK);
initial.commit586acc5fe2008-07-26 22:42:52253 rv = DoResolveProxy();
254 break;
255 case STATE_RESOLVE_PROXY_COMPLETE:
256 rv = DoResolveProxyComplete(rv);
257 break;
258 case STATE_INIT_CONNECTION:
[email protected]96d570e42008-08-05 22:43:04259 DCHECK(rv == OK);
initial.commit586acc5fe2008-07-26 22:42:52260 rv = DoInitConnection();
261 break;
262 case STATE_INIT_CONNECTION_COMPLETE:
263 rv = DoInitConnectionComplete(rv);
264 break;
265 case STATE_RESOLVE_HOST:
[email protected]96d570e42008-08-05 22:43:04266 DCHECK(rv == OK);
initial.commit586acc5fe2008-07-26 22:42:52267 rv = DoResolveHost();
268 break;
269 case STATE_RESOLVE_HOST_COMPLETE:
270 rv = DoResolveHostComplete(rv);
271 break;
272 case STATE_CONNECT:
[email protected]96d570e42008-08-05 22:43:04273 DCHECK(rv == OK);
initial.commit586acc5fe2008-07-26 22:42:52274 rv = DoConnect();
275 break;
276 case STATE_CONNECT_COMPLETE:
277 rv = DoConnectComplete(rv);
278 break;
279 case STATE_WRITE_HEADERS:
[email protected]96d570e42008-08-05 22:43:04280 DCHECK(rv == OK);
initial.commit586acc5fe2008-07-26 22:42:52281 rv = DoWriteHeaders();
282 break;
283 case STATE_WRITE_HEADERS_COMPLETE:
284 rv = DoWriteHeadersComplete(rv);
285 break;
286 case STATE_WRITE_BODY:
[email protected]96d570e42008-08-05 22:43:04287 DCHECK(rv == OK);
initial.commit586acc5fe2008-07-26 22:42:52288 rv = DoWriteBody();
289 break;
290 case STATE_WRITE_BODY_COMPLETE:
291 rv = DoWriteBodyComplete(rv);
292 break;
293 case STATE_READ_HEADERS:
[email protected]96d570e42008-08-05 22:43:04294 DCHECK(rv == OK);
initial.commit586acc5fe2008-07-26 22:42:52295 rv = DoReadHeaders();
296 break;
297 case STATE_READ_HEADERS_COMPLETE:
298 rv = DoReadHeadersComplete(rv);
299 break;
300 case STATE_READ_BODY:
[email protected]96d570e42008-08-05 22:43:04301 DCHECK(rv == OK);
initial.commit586acc5fe2008-07-26 22:42:52302 rv = DoReadBody();
303 break;
304 case STATE_READ_BODY_COMPLETE:
305 rv = DoReadBodyComplete(rv);
306 break;
307 default:
308 NOTREACHED() << "bad state";
309 rv = ERR_FAILED;
[email protected]96d570e42008-08-05 22:43:04310 break;
initial.commit586acc5fe2008-07-26 22:42:52311 }
312 } while (rv != ERR_IO_PENDING && next_state_ != STATE_NONE);
313
314 return rv;
315}
316
317int HttpNetworkTransaction::DoResolveProxy() {
318 DCHECK(!pac_request_);
319
320 next_state_ = STATE_RESOLVE_PROXY_COMPLETE;
321
322 return session_->proxy_service()->ResolveProxy(
323 request_->url, &proxy_info_, &io_callback_, &pac_request_);
324}
325
326int HttpNetworkTransaction::DoResolveProxyComplete(int result) {
327 next_state_ = STATE_INIT_CONNECTION;
328
329 pac_request_ = NULL;
330
331 if (result != OK) {
332 DLOG(ERROR) << "Failed to resolve proxy: " << result;
333 proxy_info_.UseDirect();
334 }
335 return OK;
336}
337
338int HttpNetworkTransaction::DoInitConnection() {
339 DCHECK(!connection_.is_initialized());
340
341 next_state_ = STATE_INIT_CONNECTION_COMPLETE;
342
343 using_ssl_ = request_->url.SchemeIs("https");
344 using_proxy_ = !proxy_info_.is_direct() && !using_ssl_;
345 using_tunnel_ = !proxy_info_.is_direct() && using_ssl_;
346
347 // Build the string used to uniquely identify connections of this type.
348 std::string connection_group;
349 if (using_proxy_ || using_tunnel_)
[email protected]82f954e2008-08-12 05:11:38350 connection_group = "proxy/" + proxy_info_.proxy_server() + "/";
initial.commit586acc5fe2008-07-26 22:42:52351 if (!using_proxy_)
352 connection_group.append(request_->url.GetOrigin().spec());
353
[email protected]96d570e42008-08-05 22:43:04354 DCHECK(!connection_group.empty());
initial.commit586acc5fe2008-07-26 22:42:52355 return connection_.Init(connection_group, &io_callback_);
356}
357
358int HttpNetworkTransaction::DoInitConnectionComplete(int result) {
359 if (result < 0)
360 return result;
361
362 DCHECK(connection_.is_initialized());
363
364 // Set the reused_socket_ flag to indicate that we are using a keep-alive
365 // connection. This flag is used to handle errors that occur while we are
366 // trying to reuse a keep-alive connection.
367 if (reused_socket_ = (connection_.socket() != NULL)) {
368 next_state_ = STATE_WRITE_HEADERS;
369 } else {
370 next_state_ = STATE_RESOLVE_HOST;
371 }
372 return OK;
373}
374
375int HttpNetworkTransaction::DoResolveHost() {
376 next_state_ = STATE_RESOLVE_HOST_COMPLETE;
377
initial.commit586acc5fe2008-07-26 22:42:52378 std::string host;
379 int port;
380
381 // Determine the host and port to connect to.
382 if (using_proxy_ || using_tunnel_) {
[email protected]82f954e2008-08-12 05:11:38383 const std::string& proxy = proxy_info_.proxy_server();
initial.commit586acc5fe2008-07-26 22:42:52384 StringTokenizer t(proxy, ":");
385 // TODO(darin): Handle errors here. Perhaps HttpProxyInfo should do this
386 // before claiming a proxy server configuration.
387 t.GetNext();
388 host = t.token();
389 t.GetNext();
390 port = static_cast<int>(StringToInt64(t.token()));
391 } else {
[email protected]96d570e42008-08-05 22:43:04392 // Direct connection
initial.commit586acc5fe2008-07-26 22:42:52393 host = request_->url.host();
394 port = request_->url.IntPort();
[email protected]96d570e42008-08-05 22:43:04395 if (port == url_parse::PORT_UNSPECIFIED) {
initial.commit586acc5fe2008-07-26 22:42:52396 if (using_ssl_) {
397 port = 443; // Default HTTPS port
398 } else {
399 port = 80; // Default HTTP port
400 }
401 }
402 }
403
[email protected]96d570e42008-08-05 22:43:04404 return resolver_.Resolve(host, port, &addresses_, &io_callback_);
initial.commit586acc5fe2008-07-26 22:42:52405}
406
407int HttpNetworkTransaction::DoResolveHostComplete(int result) {
initial.commit586acc5fe2008-07-26 22:42:52408 if (result == OK)
409 next_state_ = STATE_CONNECT;
410 return result;
411}
412
413int HttpNetworkTransaction::DoConnect() {
414 next_state_ = STATE_CONNECT_COMPLETE;
415
416 DCHECK(!connection_.socket());
417
418 ClientSocket* s = socket_factory_->CreateTCPClientSocket(addresses_);
419
420 // If we are using a direct SSL connection, then go ahead and create the SSL
421 // wrapper socket now. Otherwise, we need to first issue a CONNECT request.
422 if (using_ssl_ && !using_tunnel_)
423 s = socket_factory_->CreateSSLClientSocket(s, request_->url.host());
424
425 connection_.set_socket(s);
426 return connection_.socket()->Connect(&io_callback_);
427}
428
429int HttpNetworkTransaction::DoConnectComplete(int result) {
430 if (result == OK)
431 next_state_ = STATE_WRITE_HEADERS;
432 return result;
433}
434
435int HttpNetworkTransaction::DoWriteHeaders() {
436 next_state_ = STATE_WRITE_HEADERS_COMPLETE;
437
438 // This is constructed lazily (instead of within our Start method), so that
439 // we have proxy info available.
440 if (request_headers_.empty())
441 BuildRequestHeaders();
442
443 // Record our best estimate of the 'request time' as the time when we send
444 // out the first bytes of the request headers.
[email protected]96d570e42008-08-05 22:43:04445 if (request_headers_bytes_sent_ == 0)
initial.commit586acc5fe2008-07-26 22:42:52446 response_.request_time = Time::Now();
447
[email protected]96d570e42008-08-05 22:43:04448 const char* buf = request_headers_.data() + request_headers_bytes_sent_;
449 int buf_len = static_cast<int>(request_headers_.size() -
450 request_headers_bytes_sent_);
initial.commit586acc5fe2008-07-26 22:42:52451 DCHECK(buf_len > 0);
452
453 return connection_.socket()->Write(buf, buf_len, &io_callback_);
454}
455
456int HttpNetworkTransaction::DoWriteHeadersComplete(int result) {
457 if (result < 0)
458 return HandleIOError(result);
459
[email protected]96d570e42008-08-05 22:43:04460 request_headers_bytes_sent_ += result;
461 if (request_headers_bytes_sent_ < request_headers_.size()) {
initial.commit586acc5fe2008-07-26 22:42:52462 next_state_ = STATE_WRITE_HEADERS;
463 } else if (request_->upload_data) {
464 next_state_ = STATE_WRITE_BODY;
465 } else {
466 next_state_ = STATE_READ_HEADERS;
467 }
468 return OK;
469}
470
471int HttpNetworkTransaction::DoWriteBody() {
472 next_state_ = STATE_WRITE_BODY_COMPLETE;
473
474 DCHECK(request_->upload_data);
475 DCHECK(request_body_stream_.get());
476
477 const char* buf = request_body_stream_->buf();
478 int buf_len = static_cast<int>(request_body_stream_->buf_len());
479
480 return connection_.socket()->Write(buf, buf_len, &io_callback_);
481}
482
483int HttpNetworkTransaction::DoWriteBodyComplete(int result) {
484 if (result < 0)
485 return HandleIOError(result);
486
487 request_body_stream_->DidConsume(result);
488
489 if (request_body_stream_->position() < request_body_stream_->size()) {
490 next_state_ = STATE_WRITE_BODY;
491 } else {
492 next_state_ = STATE_READ_HEADERS;
493 }
494 return OK;
495}
496
497int HttpNetworkTransaction::DoReadHeaders() {
498 next_state_ = STATE_READ_HEADERS_COMPLETE;
499
500 // Grow the read buffer if necessary.
501 if (header_buf_len_ == header_buf_capacity_) {
502 header_buf_capacity_ += kHeaderBufInitialSize;
503 header_buf_.reset(static_cast<char*>(
504 realloc(header_buf_.release(), header_buf_capacity_)));
505 }
506
507 char* buf = header_buf_.get() + header_buf_len_;
508 int buf_len = header_buf_capacity_ - header_buf_len_;
509
510 return connection_.socket()->Read(buf, buf_len, &io_callback_);
511}
512
513int HttpNetworkTransaction::DoReadHeadersComplete(int result) {
514 if (result < 0)
515 return HandleIOError(result);
516
517 // Record our best estimate of the 'response time' as the time when we read
518 // the first bytes of the response headers.
519 if (header_buf_len_ == 0)
520 response_.response_time = Time::Now();
521
522 if (result == 0) {
523 // The socket was closed before we found end-of-headers. Assume that EOF
524 // is end-of-headers.
525 header_buf_body_offset_ = header_buf_len_;
526 } else {
527 header_buf_len_ += result;
528 DCHECK(header_buf_len_ <= header_buf_capacity_);
529
530 // TODO(darin): Check for a HTTP/0.9 response.
531
532 int eoh = HttpUtil::LocateEndOfHeaders(header_buf_.get(), header_buf_len_);
[email protected]96d570e42008-08-05 22:43:04533 if (eoh == -1) {
initial.commit586acc5fe2008-07-26 22:42:52534 next_state_ = STATE_READ_HEADERS; // Read more.
535 return OK;
536 }
[email protected]96d570e42008-08-05 22:43:04537 header_buf_body_offset_ = eoh;
initial.commit586acc5fe2008-07-26 22:42:52538 }
539
540 // And, we are done with the Start sequence.
initial.commit586acc5fe2008-07-26 22:42:52541 return DidReadResponseHeaders();
542}
543
544int HttpNetworkTransaction::DoReadBody() {
545 DCHECK(read_buf_);
546 DCHECK(read_buf_len_ > 0);
547 DCHECK(connection_.is_initialized());
548
549 next_state_ = STATE_READ_BODY_COMPLETE;
550
[email protected]96d570e42008-08-05 22:43:04551 // We may have some data remaining in the header buffer.
initial.commit586acc5fe2008-07-26 22:42:52552 if (header_buf_.get() && header_buf_body_offset_ < header_buf_len_) {
553 int n = std::min(read_buf_len_, header_buf_len_ - header_buf_body_offset_);
554 memcpy(read_buf_, header_buf_.get() + header_buf_body_offset_, n);
555 header_buf_body_offset_ += n;
[email protected]96d570e42008-08-05 22:43:04556 if (header_buf_body_offset_ == header_buf_len_) {
initial.commit586acc5fe2008-07-26 22:42:52557 header_buf_.reset();
[email protected]96d570e42008-08-05 22:43:04558 header_buf_capacity_ = 0;
559 header_buf_len_ = 0;
560 header_buf_body_offset_ = -1;
561 }
initial.commit586acc5fe2008-07-26 22:42:52562 return n;
563 }
564
565 return connection_.socket()->Read(read_buf_, read_buf_len_, &io_callback_);
566}
567
568int HttpNetworkTransaction::DoReadBodyComplete(int result) {
569 // We are done with the Read call.
570
[email protected]96d570e42008-08-05 22:43:04571 bool unfiltered_eof = (result == 0);
572
initial.commit586acc5fe2008-07-26 22:42:52573 // Filter incoming data if appropriate. FilterBuf may return an error.
574 if (result > 0 && chunked_decoder_.get()) {
575 result = chunked_decoder_->FilterBuf(read_buf_, result);
[email protected]96d570e42008-08-05 22:43:04576 if (result == 0 && !chunked_decoder_->reached_eof()) {
initial.commit586acc5fe2008-07-26 22:42:52577 // Don't signal completion of the Read call yet or else it'll look like
578 // we received end-of-file. Wait for more data.
579 next_state_ = STATE_READ_BODY;
580 return OK;
581 }
582 }
583
584 bool done = false, keep_alive = false;
585 if (result < 0) {
586 // Error while reading the socket.
587 done = true;
588 } else {
589 content_read_ += result;
[email protected]96d570e42008-08-05 22:43:04590 if (unfiltered_eof ||
591 (content_length_ != -1 && content_read_ >= content_length_) ||
initial.commit586acc5fe2008-07-26 22:42:52592 (chunked_decoder_.get() && chunked_decoder_->reached_eof())) {
593 done = true;
594 keep_alive = response_.headers->IsKeepAlive();
[email protected]96d570e42008-08-05 22:43:04595 // We can't reuse the connection if we read more than the advertised
596 // content length.
597 if (unfiltered_eof ||
598 (content_length_ != -1 && content_read_ > content_length_))
599 keep_alive = false;
initial.commit586acc5fe2008-07-26 22:42:52600 }
601 }
602
[email protected]96d570e42008-08-05 22:43:04603 // Clean up the HttpConnection if we are done.
initial.commit586acc5fe2008-07-26 22:42:52604 if (done) {
605 if (!keep_alive)
606 connection_.set_socket(NULL);
607 connection_.Reset();
[email protected]96d570e42008-08-05 22:43:04608 // The next Read call will return 0 (EOF).
initial.commit586acc5fe2008-07-26 22:42:52609 }
610
611 // Clear these to avoid leaving around old state.
612 read_buf_ = NULL;
613 read_buf_len_ = 0;
614
615 return result;
616}
617
618int HttpNetworkTransaction::DidReadResponseHeaders() {
619 scoped_refptr<HttpResponseHeaders> headers = new HttpResponseHeaders(
620 HttpUtil::AssembleRawHeaders(header_buf_.get(), header_buf_body_offset_));
621
622 // Check for an intermediate 100 Continue response. An origin server is
623 // allowed to send this response even if we didn't ask for it, so we just
624 // need to skip over it.
625 if (headers->response_code() == 100) {
[email protected]96d570e42008-08-05 22:43:04626 header_buf_len_ -= header_buf_body_offset_;
627 // If we've already received some bytes after the 100 Continue response,
628 // move them to the beginning of header_buf_.
629 if (header_buf_len_) {
630 memmove(header_buf_.get(), header_buf_.get() + header_buf_body_offset_,
631 header_buf_len_);
632 }
initial.commit586acc5fe2008-07-26 22:42:52633 header_buf_body_offset_ = -1;
634 next_state_ = STATE_READ_HEADERS;
635 return OK;
636 }
637
638 response_.headers = headers;
639 response_.vary_data.Init(*request_, *response_.headers);
640
641 // Figure how to determine EOF:
642
643 // For certain responses, we know the content length is always 0.
644 switch (response_.headers->response_code()) {
[email protected]96d570e42008-08-05 22:43:04645 case 204: // No Content
646 case 205: // Reset Content
647 case 304: // Not Modified
initial.commit586acc5fe2008-07-26 22:42:52648 content_length_ = 0;
649 break;
650 }
651
652 if (content_length_ == -1) {
653 // Ignore spurious chunked responses from HTTP/1.0 servers and proxies.
654 // Otherwise "Transfer-Encoding: chunked" trumps "Content-Length: N"
655 const std::string& status_line = response_.headers->GetStatusLine();
656 if (!StartsWithASCII(status_line, "HTTP/1.0 ", true) &&
657 response_.headers->HasHeaderValue("Transfer-Encoding", "chunked")) {
658 chunked_decoder_.reset(new HttpChunkedDecoder());
659 } else {
660 content_length_ = response_.headers->GetContentLength();
661 // If content_length_ is still -1, then we have to wait for the server to
662 // close the connection.
663 }
664 }
665
666 return OK;
667}
668
[email protected]96d570e42008-08-05 22:43:04669// This method determines whether it is safe to resend the request after an
670// IO error. It can only be called in response to request header or body
671// write errors or response header read errors. It should not be used in
672// other cases, such as a Connect error.
initial.commit586acc5fe2008-07-26 22:42:52673int HttpNetworkTransaction::HandleIOError(int error) {
674 switch (error) {
675 // If we try to reuse a connection that the server is in the process of
676 // closing, we may end up successfully writing out our request (or a
677 // portion of our request) only to find a connection error when we try to
678 // read from (or finish writing to) the socket.
679 case ERR_CONNECTION_RESET:
680 case ERR_CONNECTION_CLOSED:
681 case ERR_CONNECTION_ABORTED:
682 if (reused_socket_ && // We reused a keep-alive connection.
[email protected]96d570e42008-08-05 22:43:04683 !header_buf_len_) { // We haven't received any response header yet.
initial.commit586acc5fe2008-07-26 22:42:52684 connection_.set_socket(NULL);
685 connection_.Reset();
[email protected]96d570e42008-08-05 22:43:04686 request_headers_bytes_sent_ = 0;
initial.commit586acc5fe2008-07-26 22:42:52687 if (request_body_stream_.get())
688 request_body_stream_->Reset();
[email protected]96d570e42008-08-05 22:43:04689 next_state_ = STATE_INIT_CONNECTION; // Resend the request.
initial.commit586acc5fe2008-07-26 22:42:52690 error = OK;
691 }
692 break;
693 }
694 return error;
695}
696
initial.commit586acc5fe2008-07-26 22:42:52697} // namespace net