Home | History | Annotate | Download | only in glue
      1 // Copyright (c) 2011 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 #ifndef CHROME_BROWSER_SYNC_GLUE_HTTP_BRIDGE_H_
      6 #define CHROME_BROWSER_SYNC_GLUE_HTTP_BRIDGE_H_
      7 #pragma once
      8 
      9 #include <string>
     10 
     11 #include "base/basictypes.h"
     12 #include "base/compiler_specific.h"
     13 #include "base/memory/ref_counted.h"
     14 #include "base/synchronization/lock.h"
     15 #include "base/synchronization/waitable_event.h"
     16 #include "chrome/browser/sync/engine/http_post_provider_factory.h"
     17 #include "chrome/browser/sync/engine/http_post_provider_interface.h"
     18 #include "chrome/browser/sync/engine/syncapi.h"
     19 #include "chrome/common/net/url_fetcher.h"
     20 #include "googleurl/src/gurl.h"
     21 #include "net/url_request/url_request_context.h"
     22 #include "net/url_request/url_request_context_getter.h"
     23 #include "testing/gtest/include/gtest/gtest_prod.h"
     24 
     25 class MessageLoop;
     26 class HttpBridgeTest;
     27 
     28 namespace browser_sync {
     29 
     30 // A bridge between the syncer and Chromium HTTP layers.
     31 // Provides a way for the sync backend to use Chromium directly for HTTP
     32 // requests rather than depending on a third party provider (e.g libcurl).
     33 // This is a one-time use bridge. Create one for each request you want to make.
     34 // It is RefCountedThreadSafe because it can PostTask to the io loop, and thus
     35 // needs to stick around across context switches, etc.
     36 class HttpBridge : public base::RefCountedThreadSafe<HttpBridge>,
     37                    public sync_api::HttpPostProviderInterface,
     38                    public URLFetcher::Delegate {
     39  public:
     40   // A request context used for HTTP requests bridged from the sync backend.
     41   // A bridged RequestContext has a dedicated in-memory cookie store and does
     42   // not use a cache. Thus the same type can be used for incognito mode.
     43   class RequestContext : public net::URLRequestContext {
     44    public:
     45     // |baseline_context| is used to obtain the accept-language,
     46     // accept-charsets, and proxy service information for bridged requests.
     47     // Typically |baseline_context| should be the net::URLRequestContext of the
     48     // currently active profile.
     49     explicit RequestContext(net::URLRequestContext* baseline_context);
     50 
     51     // Set the user agent for requests using this context. The default is
     52     // the browser's UA string.
     53     void set_user_agent(const std::string& ua) { user_agent_ = ua; }
     54 
     55     virtual const std::string& GetUserAgent(const GURL& url) const {
     56       // If the user agent is set explicitly return that, otherwise call the
     57       // base class method to return default value.
     58       return user_agent_.empty() ?
     59           net::URLRequestContext::GetUserAgent(url) : user_agent_;
     60     }
     61 
     62    private:
     63     // The destructor MUST be called on the IO thread.
     64     ~RequestContext();
     65 
     66     std::string user_agent_;
     67     net::URLRequestContext* baseline_context_;
     68 
     69     DISALLOW_COPY_AND_ASSIGN(RequestContext);
     70   };
     71 
     72   // Lazy-getter for RequestContext objects.
     73   class RequestContextGetter : public net::URLRequestContextGetter {
     74    public:
     75     explicit RequestContextGetter(
     76         net::URLRequestContextGetter* baseline_context_getter);
     77 
     78     void set_user_agent(const std::string& ua) { user_agent_ = ua; }
     79     bool is_user_agent_set() const { return !user_agent_.empty(); }
     80 
     81     // net::URLRequestContextGetter implementation.
     82     virtual net::URLRequestContext* GetURLRequestContext();
     83     virtual scoped_refptr<base::MessageLoopProxy> GetIOMessageLoopProxy() const;
     84 
     85    private:
     86     ~RequestContextGetter() {}
     87 
     88     // User agent to apply to the net::URLRequestContext.
     89     std::string user_agent_;
     90 
     91     scoped_refptr<net::URLRequestContextGetter> baseline_context_getter_;
     92 
     93     // Lazily initialized by GetURLRequestContext().
     94     scoped_refptr<RequestContext> context_;
     95 
     96     DISALLOW_COPY_AND_ASSIGN(RequestContextGetter);
     97   };
     98 
     99   explicit HttpBridge(RequestContextGetter* context);
    100 
    101   // sync_api::HttpPostProvider implementation.
    102   virtual void SetUserAgent(const char* user_agent);
    103   virtual void SetExtraRequestHeaders(const char* headers);
    104   virtual void SetURL(const char* url, int port);
    105   virtual void SetPostPayload(const char* content_type, int content_length,
    106                               const char* content);
    107   virtual bool MakeSynchronousPost(int* os_error_code, int* response_code);
    108   virtual void Abort();
    109 
    110   // WARNING: these response content methods are used to extract plain old data
    111   // and not null terminated strings, so you should make sure you have read
    112   // GetResponseContentLength() characters when using GetResponseContent. e.g
    113   // string r(b->GetResponseContent(), b->GetResponseContentLength()).
    114   virtual int GetResponseContentLength() const;
    115   virtual const char* GetResponseContent() const;
    116   virtual const std::string GetResponseHeaderValue(
    117       const std::string& name) const;
    118 
    119   // URLFetcher::Delegate implementation.
    120   virtual void OnURLFetchComplete(const URLFetcher* source,
    121                                   const GURL& url,
    122                                   const net::URLRequestStatus& status,
    123                                   int response_code,
    124                                   const ResponseCookies& cookies,
    125                                   const std::string& data);
    126 
    127 #if defined(UNIT_TEST)
    128   net::URLRequestContextGetter* GetRequestContextGetter() const {
    129     return context_getter_for_request_;
    130   }
    131 #endif
    132 
    133  protected:
    134   friend class base::RefCountedThreadSafe<HttpBridge>;
    135 
    136   virtual ~HttpBridge();
    137 
    138   // Protected virtual so the unit test can override to shunt network requests.
    139   virtual void MakeAsynchronousPost();
    140 
    141  private:
    142   friend class ::HttpBridgeTest;
    143 
    144   // Called on the IO loop to issue the network request. The extra level
    145   // of indirection is so that the unit test can override this behavior but we
    146   // still have a function to statically pass to PostTask.
    147   void CallMakeAsynchronousPost() { MakeAsynchronousPost(); }
    148 
    149   // Gets a customized net::URLRequestContext for bridged requests. See
    150   // RequestContext definition for details.
    151   scoped_refptr<RequestContextGetter> context_getter_for_request_;
    152 
    153   // The message loop of the thread we were created on. This is the thread that
    154   // will block on MakeSynchronousPost while the IO thread fetches data from
    155   // the network.
    156   // This should be the main syncer thread (SyncerThread) which is what blocks
    157   // on network IO through curl_easy_perform.
    158   MessageLoop* const created_on_loop_;
    159 
    160   // The URL to POST to.
    161   GURL url_for_request_;
    162 
    163   // POST payload information.
    164   std::string content_type_;
    165   std::string request_content_;
    166   std::string extra_headers_;
    167 
    168   // A waitable event we use to provide blocking semantics to
    169   // MakeSynchronousPost. We block created_on_loop_ while the IO loop fetches
    170   // network request.
    171   base::WaitableEvent http_post_completed_;
    172 
    173   struct URLFetchState {
    174     URLFetchState();
    175     ~URLFetchState();
    176     // Our hook into the network layer is a URLFetcher. USED ONLY ON THE IO
    177     // LOOP, so we can block created_on_loop_ while the fetch is in progress.
    178     // NOTE: This is not a scoped_ptr for a reason. It must be deleted on the
    179     // same thread that created it, which isn't the same thread |this| gets
    180     // deleted on. We must manually delete url_poster_ on the IO loop.
    181     URLFetcher* url_poster;
    182 
    183     // Used to support 'Abort' functionality.
    184     bool aborted;
    185 
    186     // Cached response data.
    187     bool request_completed;
    188     bool request_succeeded;
    189     int http_response_code;
    190     int os_error_code;
    191     std::string response_content;
    192     scoped_refptr<net::HttpResponseHeaders> response_headers;
    193   };
    194 
    195   // This lock synchronizes use of state involved in the flow to fetch a URL
    196   // using URLFetcher.  Because we can Abort() from any thread, for example,
    197   // this flow needs to be synchronized to gracefully clean up URLFetcher and
    198   // return appropriate values in os_error_code.
    199   mutable base::Lock fetch_state_lock_;
    200   URLFetchState fetch_state_;
    201 
    202   DISALLOW_COPY_AND_ASSIGN(HttpBridge);
    203 };
    204 
    205 class HttpBridgeFactory : public sync_api::HttpPostProviderFactory {
    206  public:
    207   explicit HttpBridgeFactory(
    208       net::URLRequestContextGetter* baseline_context_getter);
    209   virtual ~HttpBridgeFactory();
    210 
    211   // sync_api::HttpPostProviderFactory:
    212   virtual sync_api::HttpPostProviderInterface* Create() OVERRIDE;
    213   virtual void Destroy(sync_api::HttpPostProviderInterface* http) OVERRIDE;
    214 
    215  private:
    216   // This request context is built on top of the baseline context and shares
    217   // common components.
    218   HttpBridge::RequestContextGetter* GetRequestContextGetter();
    219 
    220   scoped_refptr<HttpBridge::RequestContextGetter> request_context_getter_;
    221 
    222   DISALLOW_COPY_AND_ASSIGN(HttpBridgeFactory);
    223 };
    224 
    225 }  //  namespace browser_sync
    226 
    227 #endif  // CHROME_BROWSER_SYNC_GLUE_HTTP_BRIDGE_H_
    228