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

Side by Side Diff: chrome/browser/sync/glue/http_bridge.cc

Issue 10645004: [Sync] Move HttpBridge to sync/ (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Sync to head Created 8 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 | Annotate | Revision Log
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/sync/glue/http_bridge.h"
6
7 #include "base/message_loop.h"
8 #include "base/message_loop_proxy.h"
9 #include "base/string_number_conversions.h"
10 #include "content/public/browser/browser_thread.h"
11 #include "content/public/common/content_client.h"
12 #include "net/base/host_resolver.h"
13 #include "net/base/load_flags.h"
14 #include "net/base/net_errors.h"
15 #include "net/cookies/cookie_monster.h"
16 #include "net/http/http_cache.h"
17 #include "net/http/http_network_layer.h"
18 #include "net/http/http_response_headers.h"
19 #include "net/proxy/proxy_service.h"
20 #include "net/url_request/url_fetcher.h"
21 #include "net/url_request/url_request_context.h"
22 #include "net/url_request/url_request_status.h"
23
24 using content::BrowserThread;
25
26 namespace browser_sync {
27
28 HttpBridge::RequestContextGetter::RequestContextGetter(
29 net::URLRequestContextGetter* baseline_context_getter)
30 : baseline_context_getter_(baseline_context_getter) {
31 }
32
33 HttpBridge::RequestContextGetter::~RequestContextGetter() {}
34
35 net::URLRequestContext*
36 HttpBridge::RequestContextGetter::GetURLRequestContext() {
37 // Lazily create the context.
38 if (!context_.get()) {
39 net::URLRequestContext* baseline_context =
40 baseline_context_getter_->GetURLRequestContext();
41 context_.reset(new RequestContext(baseline_context));
42 baseline_context_getter_ = NULL;
43 }
44
45 // Apply the user agent which was set earlier.
46 if (is_user_agent_set())
47 context_->set_user_agent(user_agent_);
48
49 return context_.get();
50 }
51
52 scoped_refptr<base::SingleThreadTaskRunner>
53 HttpBridge::RequestContextGetter::GetNetworkTaskRunner() const {
54 return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
55 }
56
57 HttpBridgeFactory::HttpBridgeFactory(
58 net::URLRequestContextGetter* baseline_context_getter) {
59 DCHECK(baseline_context_getter != NULL);
60 request_context_getter_ =
61 new HttpBridge::RequestContextGetter(baseline_context_getter);
62 }
63
64 HttpBridgeFactory::~HttpBridgeFactory() {
65 }
66
67 csync::HttpPostProviderInterface* HttpBridgeFactory::Create() {
68 HttpBridge* http = new HttpBridge(request_context_getter_);
69 http->AddRef();
70 return http;
71 }
72
73 void HttpBridgeFactory::Destroy(csync::HttpPostProviderInterface* http) {
74 static_cast<HttpBridge*>(http)->Release();
75 }
76
77 HttpBridge::RequestContext::RequestContext(
78 net::URLRequestContext* baseline_context)
79 : baseline_context_(baseline_context) {
80
81 // Create empty, in-memory cookie store.
82 set_cookie_store(new net::CookieMonster(NULL, NULL));
83
84 // We don't use a cache for bridged loads, but we do want to share proxy info.
85 set_host_resolver(baseline_context->host_resolver());
86 set_proxy_service(baseline_context->proxy_service());
87 set_ssl_config_service(baseline_context->ssl_config_service());
88
89 // We want to share the HTTP session data with the network layer factory,
90 // which includes auth_cache for proxies.
91 // Session is not refcounted so we need to be careful to not lose the parent
92 // context.
93 net::HttpNetworkSession* session =
94 baseline_context->http_transaction_factory()->GetSession();
95 DCHECK(session);
96 set_http_transaction_factory(new net::HttpNetworkLayer(session));
97
98 // TODO(timsteele): We don't currently listen for pref changes of these
99 // fields or CookiePolicy; I'm not sure we want to strictly follow the
100 // default settings, since for example if the user chooses to block all
101 // cookies, sync will start failing. Also it seems like accept_lang/charset
102 // should be tied to whatever the sync servers expect (if anything). These
103 // fields should probably just be settable by sync backend; though we should
104 // figure out if we need to give the user explicit control over policies etc.
105 set_accept_language(baseline_context->accept_language());
106 set_accept_charset(baseline_context->accept_charset());
107
108 // We default to the browser's user agent. This can (and should) be overridden
109 // with set_user_agent.
110 set_user_agent(content::GetUserAgent(GURL()));
111
112 set_net_log(baseline_context->net_log());
113 }
114
115 HttpBridge::RequestContext::~RequestContext() {
116 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
117 delete http_transaction_factory();
118 }
119
120 HttpBridge::URLFetchState::URLFetchState() : url_poster(NULL),
121 aborted(false),
122 request_completed(false),
123 request_succeeded(false),
124 http_response_code(-1),
125 error_code(-1) {}
126 HttpBridge::URLFetchState::~URLFetchState() {}
127
128 HttpBridge::HttpBridge(HttpBridge::RequestContextGetter* context_getter)
129 : context_getter_for_request_(context_getter),
130 created_on_loop_(MessageLoop::current()),
131 http_post_completed_(false, false) {
132 }
133
134 HttpBridge::~HttpBridge() {
135 }
136
137 void HttpBridge::SetUserAgent(const char* user_agent) {
138 DCHECK_EQ(MessageLoop::current(), created_on_loop_);
139 if (DCHECK_IS_ON()) {
140 base::AutoLock lock(fetch_state_lock_);
141 DCHECK(!fetch_state_.request_completed);
142 }
143 context_getter_for_request_->set_user_agent(user_agent);
144 }
145
146 void HttpBridge::SetExtraRequestHeaders(const char * headers) {
147 DCHECK(extra_headers_.empty())
148 << "HttpBridge::SetExtraRequestHeaders called twice.";
149 extra_headers_.assign(headers);
150 }
151
152 void HttpBridge::SetURL(const char* url, int port) {
153 DCHECK_EQ(MessageLoop::current(), created_on_loop_);
154 if (DCHECK_IS_ON()) {
155 base::AutoLock lock(fetch_state_lock_);
156 DCHECK(!fetch_state_.request_completed);
157 }
158 DCHECK(url_for_request_.is_empty())
159 << "HttpBridge::SetURL called more than once?!";
160 GURL temp(url);
161 GURL::Replacements replacements;
162 std::string port_str = base::IntToString(port);
163 replacements.SetPort(port_str.c_str(),
164 url_parse::Component(0, port_str.length()));
165 url_for_request_ = temp.ReplaceComponents(replacements);
166 }
167
168 void HttpBridge::SetPostPayload(const char* content_type,
169 int content_length,
170 const char* content) {
171 DCHECK_EQ(MessageLoop::current(), created_on_loop_);
172 if (DCHECK_IS_ON()) {
173 base::AutoLock lock(fetch_state_lock_);
174 DCHECK(!fetch_state_.request_completed);
175 }
176 DCHECK(content_type_.empty()) << "Bridge payload already set.";
177 DCHECK_GE(content_length, 0) << "Content length < 0";
178 content_type_ = content_type;
179 if (!content || (content_length == 0)) {
180 DCHECK_EQ(content_length, 0);
181 request_content_ = " "; // TODO(timsteele): URLFetcher requires non-empty
182 // content for POSTs whereas CURL does not, for now
183 // we hack this to support the sync backend.
184 } else {
185 request_content_.assign(content, content_length);
186 }
187 }
188
189 bool HttpBridge::MakeSynchronousPost(int* error_code, int* response_code) {
190 DCHECK_EQ(MessageLoop::current(), created_on_loop_);
191 if (DCHECK_IS_ON()) {
192 base::AutoLock lock(fetch_state_lock_);
193 DCHECK(!fetch_state_.request_completed);
194 }
195 DCHECK(url_for_request_.is_valid()) << "Invalid URL for request";
196 DCHECK(!content_type_.empty()) << "Payload not set";
197
198 if (!BrowserThread::PostTask(
199 BrowserThread::IO, FROM_HERE,
200 base::Bind(&HttpBridge::CallMakeAsynchronousPost, this))) {
201 // This usually happens when we're in a unit test.
202 LOG(WARNING) << "Could not post CallMakeAsynchronousPost task";
203 return false;
204 }
205
206 // Block until network request completes or is aborted. See
207 // OnURLFetchComplete and Abort.
208 http_post_completed_.Wait();
209
210 base::AutoLock lock(fetch_state_lock_);
211 DCHECK(fetch_state_.request_completed || fetch_state_.aborted);
212 *error_code = fetch_state_.error_code;
213 *response_code = fetch_state_.http_response_code;
214 return fetch_state_.request_succeeded;
215 }
216
217 void HttpBridge::MakeAsynchronousPost() {
218 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
219 base::AutoLock lock(fetch_state_lock_);
220 DCHECK(!fetch_state_.request_completed);
221 if (fetch_state_.aborted)
222 return;
223
224 fetch_state_.url_poster = net::URLFetcher::Create(
225 url_for_request_, net::URLFetcher::POST, this);
226 fetch_state_.url_poster->SetRequestContext(context_getter_for_request_);
227 fetch_state_.url_poster->SetUploadData(content_type_, request_content_);
228 fetch_state_.url_poster->SetExtraRequestHeaders(extra_headers_);
229 fetch_state_.url_poster->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES);
230 fetch_state_.url_poster->Start();
231 }
232
233 int HttpBridge::GetResponseContentLength() const {
234 DCHECK_EQ(MessageLoop::current(), created_on_loop_);
235 base::AutoLock lock(fetch_state_lock_);
236 DCHECK(fetch_state_.request_completed);
237 return fetch_state_.response_content.size();
238 }
239
240 const char* HttpBridge::GetResponseContent() const {
241 DCHECK_EQ(MessageLoop::current(), created_on_loop_);
242 base::AutoLock lock(fetch_state_lock_);
243 DCHECK(fetch_state_.request_completed);
244 return fetch_state_.response_content.data();
245 }
246
247 const std::string HttpBridge::GetResponseHeaderValue(
248 const std::string& name) const {
249
250 DCHECK_EQ(MessageLoop::current(), created_on_loop_);
251 base::AutoLock lock(fetch_state_lock_);
252 DCHECK(fetch_state_.request_completed);
253
254 std::string value;
255 fetch_state_.response_headers->EnumerateHeader(NULL, name, &value);
256 return value;
257 }
258
259 void HttpBridge::Abort() {
260 base::AutoLock lock(fetch_state_lock_);
261 DCHECK(!fetch_state_.aborted);
262 if (fetch_state_.aborted || fetch_state_.request_completed)
263 return;
264
265 fetch_state_.aborted = true;
266 if (!BrowserThread::PostTask(
267 BrowserThread::IO, FROM_HERE,
268 base::Bind(&HttpBridge::DestroyURLFetcherOnIOThread, this,
269 fetch_state_.url_poster))) {
270 // Madness ensues.
271 NOTREACHED() << "Could not post task to delete URLFetcher";
272 }
273
274 fetch_state_.url_poster = NULL;
275 fetch_state_.error_code = net::ERR_ABORTED;
276 http_post_completed_.Signal();
277 }
278
279 void HttpBridge::DestroyURLFetcherOnIOThread(net::URLFetcher* fetcher) {
280 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
281 delete fetcher;
282 }
283
284 void HttpBridge::OnURLFetchComplete(const net::URLFetcher* source) {
285 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
286 base::AutoLock lock(fetch_state_lock_);
287 if (fetch_state_.aborted)
288 return;
289
290 fetch_state_.request_completed = true;
291 fetch_state_.request_succeeded =
292 (net::URLRequestStatus::SUCCESS == source->GetStatus().status());
293 fetch_state_.http_response_code = source->GetResponseCode();
294 fetch_state_.error_code = source->GetStatus().error();
295
296 // Use a real (non-debug) log to facilitate troubleshooting in the wild.
297 VLOG(2) << "HttpBridge::OnURLFetchComplete for: "
298 << fetch_state_.url_poster->GetURL().spec();
299 VLOG(1) << "HttpBridge received response code: "
300 << fetch_state_.http_response_code;
301
302 source->GetResponseAsString(&fetch_state_.response_content);
303 fetch_state_.response_headers = source->GetResponseHeaders();
304
305 // End of the line for url_poster_. It lives only on the IO loop.
306 // We defer deletion because we're inside a callback from a component of the
307 // URLFetcher, so it seems most natural / "polite" to let the stack unwind.
308 MessageLoop::current()->DeleteSoon(FROM_HERE, fetch_state_.url_poster);
309 fetch_state_.url_poster = NULL;
310
311 // Wake the blocked syncer thread in MakeSynchronousPost.
312 // WARNING: DONT DO ANYTHING AFTER THIS CALL! |this| may be deleted!
313 http_post_completed_.Signal();
314 }
315
316 } // namespace browser_sync
OLDNEW
« no previous file with comments | « chrome/browser/sync/glue/http_bridge.h ('k') | chrome/browser/sync/glue/http_bridge_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698