diff options
author | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
---|---|---|
committer | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-26 23:55:29 +0000 |
commit | 09911bf300f1a419907a9412154760efd0b7abc3 (patch) | |
tree | f131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/browser/url_fetcher.cc | |
parent | 586acc5fe142f498261f52c66862fa417c3d52d2 (diff) | |
download | chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.zip chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.gz chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.bz2 |
Add chrome to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/url_fetcher.cc')
-rw-r--r-- | chrome/browser/url_fetcher.cc | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/chrome/browser/url_fetcher.cc b/chrome/browser/url_fetcher.cc new file mode 100644 index 0000000..0a038f0 --- /dev/null +++ b/chrome/browser/url_fetcher.cc @@ -0,0 +1,202 @@ +// Copyright 2008, Google Inc. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include "chrome/browser/url_fetcher.h" + +#include "base/string_util.h" +#include "base/thread.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/chrome_thread.h" +#include "chrome/browser/net/dns_master.h" +#include "googleurl/src/gurl.h" +#include "net/base/load_flags.h" + +URLFetcher::URLFetcher(const GURL& url, + RequestType request_type, + Delegate* d) +#pragma warning(suppress: 4355) // Okay to pass "this" here. + : core_(new Core(this, url, request_type, d)) { +} + +URLFetcher::~URLFetcher() { + core_->Stop(); +} + +URLFetcher::Core::Core(URLFetcher* fetcher, + const GURL& original_url, + RequestType request_type, + URLFetcher::Delegate* d) + : fetcher_(fetcher), + original_url_(original_url), + request_type_(request_type), + delegate_(d), + delegate_loop_(MessageLoop::current()), + io_loop_(ChromeThread::GetMessageLoop(ChromeThread::IO)), + request_(NULL), + response_code_(-1), + load_flags_(net::LOAD_NORMAL), + protect_entry_(ProtectManager::GetInstance()->Register( + original_url_.host())), + num_retries_(0) { +} + +void URLFetcher::Core::Start() { + DCHECK(delegate_loop_); + DCHECK(io_loop_); + DCHECK(request_context_) << "We need an URLRequestContext!"; + io_loop_->PostDelayedTask(FROM_HERE, NewRunnableMethod( + this, &Core::StartURLRequest), + protect_entry_->UpdateBackoff(ProtectEntry::SEND)); +} + +void URLFetcher::Core::Stop() { + DCHECK_EQ(MessageLoop::current(), delegate_loop_); + delegate_ = NULL; + io_loop_->PostTask(FROM_HERE, NewRunnableMethod( + this, &Core::CancelURLRequest)); +} + +void URLFetcher::Core::OnResponseStarted(URLRequest* request) { + DCHECK(request == request_); + DCHECK(MessageLoop::current() == io_loop_); + if (request_->status().is_success()) { + response_code_ = request_->GetResponseCode(); + response_headers_ = request_->response_headers(); + } + + int bytes_read = 0; + // Some servers may treat HEAD requests as GET requests. To free up the + // network connection as soon as possible, signal that the request has + // completed immediately, without trying to read any data back (all we care + // about is the response code and headers, which we already have). + if (request_->status().is_success() && (request_type_ != HEAD)) + request_->Read(buffer_, sizeof(buffer_), &bytes_read); + OnReadCompleted(request_, bytes_read); +} + +void URLFetcher::Core::OnReadCompleted(URLRequest* request, int bytes_read) { + DCHECK(request == request_); + DCHECK(MessageLoop::current() == io_loop_); + + url_ = request->url(); + + do { + if (!request_->status().is_success() || bytes_read <= 0) + break; + data_.append(buffer_, bytes_read); + } while (request_->Read(buffer_, sizeof(buffer_), &bytes_read)); + + if (request_->status().is_success()) + request_->GetResponseCookies(&cookies_); + + // See comments re: HEAD requests in OnResponseStarted(). + if (!request_->status().is_io_pending() || (request_type_ == HEAD)) { + delegate_loop_->PostTask(FROM_HERE, NewRunnableMethod( + this, &Core::OnCompletedURLRequest, request_->status())); + delete request_; + request_ = NULL; + } +} + +void URLFetcher::Core::StartURLRequest() { + DCHECK(MessageLoop::current() == io_loop_); + DCHECK(!request_); + + request_ = new URLRequest(original_url_, this); + request_->set_load_flags( + request_->load_flags() | net::LOAD_DISABLE_INTERCEPT | load_flags_); + request_->set_context(request_context_.get()); + + switch (request_type_) { + case GET: + break; + + case POST: + DCHECK(!upload_content_.empty()); + DCHECK(!upload_content_type_.empty()); + + request_->set_method("POST"); + if (!extra_request_headers_.empty()) + extra_request_headers_ += "\r\n"; + StringAppendF(&extra_request_headers_, + "Content-Length: %d\r\nContent-Type: %s", + upload_content_.size(), upload_content_type_.c_str()); + request_->AppendBytesToUpload(upload_content_.data(), + static_cast<int>(upload_content_.size())); + break; + + case HEAD: + request_->set_method("HEAD"); + break; + + default: + NOTREACHED(); + } + + if (!extra_request_headers_.empty()) + request_->SetExtraRequestHeaders(extra_request_headers_); + + request_->Start(); +} + +void URLFetcher::Core::CancelURLRequest() { + DCHECK(MessageLoop::current() == io_loop_); + if (request_) { + request_->Cancel(); + delete request_; + request_ = NULL; + } +} + +void URLFetcher::Core::OnCompletedURLRequest(const URLRequestStatus& status) { + DCHECK(MessageLoop::current() == delegate_loop_); + + // Checks the response from server. + if (response_code_ >= 500) { + // When encountering a server error, we will send the request again + // after backoff time. + const int wait = protect_entry_->UpdateBackoff(ProtectEntry::FAILURE); + ++num_retries_; + // Restarts the request if we still need to notify the delegate. + if (delegate_) { + if (num_retries_ <= protect_entry_->max_retries()) { + io_loop_->PostDelayedTask(FROM_HERE, NewRunnableMethod( + this, &Core::StartURLRequest), wait); + } else { + delegate_->OnURLFetchComplete(fetcher_, url_, status, response_code_, + cookies_, data_); + } + } + } else { + protect_entry_->UpdateBackoff(ProtectEntry::SUCCESS); + if (delegate_) + delegate_->OnURLFetchComplete(fetcher_, url_, status, response_code_, + cookies_, data_); + } +} |