OLD | NEW |
| (Empty) |
1 // Copyright (c) 2006-2008 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 "chrome/browser/url_fetcher.h" | |
6 | |
7 #include "base/compiler_specific.h" | |
8 #include "base/string_util.h" | |
9 #include "base/thread.h" | |
10 #include "chrome/browser/browser_process.h" | |
11 #include "chrome/browser/chrome_thread.h" | |
12 #include "googleurl/src/gurl.h" | |
13 #include "net/base/load_flags.h" | |
14 | |
15 URLFetcher::URLFetcher(const GURL& url, | |
16 RequestType request_type, | |
17 Delegate* d) | |
18 : ALLOW_THIS_IN_INITIALIZER_LIST( | |
19 core_(new Core(this, url, request_type, d))) { | |
20 } | |
21 | |
22 URLFetcher::~URLFetcher() { | |
23 core_->Stop(); | |
24 } | |
25 | |
26 URLFetcher::Core::Core(URLFetcher* fetcher, | |
27 const GURL& original_url, | |
28 RequestType request_type, | |
29 URLFetcher::Delegate* d) | |
30 : fetcher_(fetcher), | |
31 original_url_(original_url), | |
32 request_type_(request_type), | |
33 delegate_(d), | |
34 delegate_loop_(MessageLoop::current()), | |
35 io_loop_(ChromeThread::GetMessageLoop(ChromeThread::IO)), | |
36 request_(NULL), | |
37 load_flags_(net::LOAD_NORMAL), | |
38 response_code_(-1), | |
39 protect_entry_(URLFetcherProtectManager::GetInstance()->Register( | |
40 original_url_.host())), | |
41 num_retries_(0) { | |
42 } | |
43 | |
44 void URLFetcher::Core::Start() { | |
45 DCHECK(delegate_loop_); | |
46 DCHECK(io_loop_); | |
47 DCHECK(request_context_) << "We need an URLRequestContext!"; | |
48 io_loop_->PostDelayedTask(FROM_HERE, NewRunnableMethod( | |
49 this, &Core::StartURLRequest), | |
50 protect_entry_->UpdateBackoff(URLFetcherProtectEntry::SEND)); | |
51 } | |
52 | |
53 void URLFetcher::Core::Stop() { | |
54 DCHECK_EQ(MessageLoop::current(), delegate_loop_); | |
55 delegate_ = NULL; | |
56 io_loop_->PostTask(FROM_HERE, NewRunnableMethod( | |
57 this, &Core::CancelURLRequest)); | |
58 } | |
59 | |
60 void URLFetcher::Core::OnResponseStarted(URLRequest* request) { | |
61 DCHECK(request == request_); | |
62 DCHECK(MessageLoop::current() == io_loop_); | |
63 if (request_->status().is_success()) { | |
64 response_code_ = request_->GetResponseCode(); | |
65 response_headers_ = request_->response_headers(); | |
66 } | |
67 | |
68 int bytes_read = 0; | |
69 // Some servers may treat HEAD requests as GET requests. To free up the | |
70 // network connection as soon as possible, signal that the request has | |
71 // completed immediately, without trying to read any data back (all we care | |
72 // about is the response code and headers, which we already have). | |
73 if (request_->status().is_success() && (request_type_ != HEAD)) | |
74 request_->Read(buffer_, sizeof(buffer_), &bytes_read); | |
75 OnReadCompleted(request_, bytes_read); | |
76 } | |
77 | |
78 void URLFetcher::Core::OnReadCompleted(URLRequest* request, int bytes_read) { | |
79 DCHECK(request == request_); | |
80 DCHECK(MessageLoop::current() == io_loop_); | |
81 | |
82 url_ = request->url(); | |
83 | |
84 do { | |
85 if (!request_->status().is_success() || bytes_read <= 0) | |
86 break; | |
87 data_.append(buffer_, bytes_read); | |
88 } while (request_->Read(buffer_, sizeof(buffer_), &bytes_read)); | |
89 | |
90 if (request_->status().is_success()) | |
91 request_->GetResponseCookies(&cookies_); | |
92 | |
93 // See comments re: HEAD requests in OnResponseStarted(). | |
94 if (!request_->status().is_io_pending() || (request_type_ == HEAD)) { | |
95 delegate_loop_->PostTask(FROM_HERE, NewRunnableMethod( | |
96 this, &Core::OnCompletedURLRequest, request_->status())); | |
97 delete request_; | |
98 request_ = NULL; | |
99 } | |
100 } | |
101 | |
102 void URLFetcher::Core::StartURLRequest() { | |
103 DCHECK(MessageLoop::current() == io_loop_); | |
104 DCHECK(!request_); | |
105 | |
106 request_ = new URLRequest(original_url_, this); | |
107 request_->set_load_flags( | |
108 request_->load_flags() | net::LOAD_DISABLE_INTERCEPT | load_flags_); | |
109 request_->set_context(request_context_.get()); | |
110 | |
111 switch (request_type_) { | |
112 case GET: | |
113 break; | |
114 | |
115 case POST: | |
116 DCHECK(!upload_content_.empty()); | |
117 DCHECK(!upload_content_type_.empty()); | |
118 | |
119 request_->set_method("POST"); | |
120 if (!extra_request_headers_.empty()) | |
121 extra_request_headers_ += "\r\n"; | |
122 StringAppendF(&extra_request_headers_, | |
123 "Content-Type: %s", upload_content_type_.c_str()); | |
124 request_->AppendBytesToUpload(upload_content_.data(), | |
125 static_cast<int>(upload_content_.size())); | |
126 break; | |
127 | |
128 case HEAD: | |
129 request_->set_method("HEAD"); | |
130 break; | |
131 | |
132 default: | |
133 NOTREACHED(); | |
134 } | |
135 | |
136 if (!extra_request_headers_.empty()) | |
137 request_->SetExtraRequestHeaders(extra_request_headers_); | |
138 | |
139 request_->Start(); | |
140 } | |
141 | |
142 void URLFetcher::Core::CancelURLRequest() { | |
143 DCHECK(MessageLoop::current() == io_loop_); | |
144 if (request_) { | |
145 request_->Cancel(); | |
146 delete request_; | |
147 request_ = NULL; | |
148 } | |
149 // Release the reference to the request context. There could be multiple | |
150 // references to URLFetcher::Core at this point so it may take a while to | |
151 // delete the object, but we cannot delay the destruction of the request | |
152 // context. | |
153 request_context_ = NULL; | |
154 } | |
155 | |
156 void URLFetcher::Core::OnCompletedURLRequest(const URLRequestStatus& status) { | |
157 DCHECK(MessageLoop::current() == delegate_loop_); | |
158 | |
159 // Checks the response from server. | |
160 if (response_code_ >= 500) { | |
161 // When encountering a server error, we will send the request again | |
162 // after backoff time. | |
163 const int wait = | |
164 protect_entry_->UpdateBackoff(URLFetcherProtectEntry::FAILURE); | |
165 ++num_retries_; | |
166 // Restarts the request if we still need to notify the delegate. | |
167 if (delegate_) { | |
168 if (num_retries_ <= protect_entry_->max_retries()) { | |
169 io_loop_->PostDelayedTask(FROM_HERE, NewRunnableMethod( | |
170 this, &Core::StartURLRequest), wait); | |
171 } else { | |
172 delegate_->OnURLFetchComplete(fetcher_, url_, status, response_code_, | |
173 cookies_, data_); | |
174 } | |
175 } | |
176 } else { | |
177 protect_entry_->UpdateBackoff(URLFetcherProtectEntry::SUCCESS); | |
178 if (delegate_) | |
179 delegate_->OnURLFetchComplete(fetcher_, url_, status, response_code_, | |
180 cookies_, data_); | |
181 } | |
182 } | |
OLD | NEW |