Home | History | Annotate | Download | only in chrome_frame
      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_FRAME_PROTOCOL_SINK_WRAP_H_
      6 #define CHROME_FRAME_PROTOCOL_SINK_WRAP_H_
      7 
      8 #include <exdisp.h>
      9 #include <urlmon.h>
     10 #include <atlbase.h>
     11 #include <atlcom.h>
     12 
     13 #include <map>
     14 #include <string>
     15 
     16 #include "base/basictypes.h"
     17 #include "base/memory/ref_counted.h"
     18 #include "base/win/scoped_comptr.h"
     19 #include "base/win/scoped_bstr.h"
     20 #include "chrome_frame/chrome_frame_delegate.h"
     21 #include "chrome_frame/http_negotiate.h"
     22 #include "chrome_frame/ie8_types.h"
     23 #include "chrome_frame/utils.h"
     24 #include "chrome_frame/vtable_patch_manager.h"
     25 
     26 // Typedefs for IInternetProtocol and related methods that we patch.
     27 typedef HRESULT (STDMETHODCALLTYPE* InternetProtocol_Start_Fn)(
     28     IInternetProtocol* this_object, LPCWSTR url,
     29     IInternetProtocolSink* prot_sink, IInternetBindInfo* bind_info,
     30     DWORD flags, HANDLE_PTR reserved);
     31 typedef HRESULT (STDMETHODCALLTYPE* InternetProtocol_Read_Fn)(
     32     IInternetProtocol* this_object, void* buffer, ULONG size,
     33     ULONG* size_read);
     34 typedef HRESULT (STDMETHODCALLTYPE* InternetProtocol_StartEx_Fn)(
     35     IInternetProtocolEx* this_object, IUri* uri,
     36     IInternetProtocolSink* prot_sink, IInternetBindInfo* bind_info,
     37     DWORD flags, HANDLE_PTR reserved);
     38 typedef HRESULT (STDMETHODCALLTYPE* InternetProtocol_LockRequest_Fn)(
     39     IInternetProtocol* this_object, DWORD options);
     40 typedef HRESULT (STDMETHODCALLTYPE* InternetProtocol_UnlockRequest_Fn)(
     41     IInternetProtocol* this_object);
     42 typedef HRESULT (STDMETHODCALLTYPE* InternetProtocol_Abort_Fn)(
     43     IInternetProtocol* this_object,  HRESULT hr, DWORD options);
     44 typedef HRESULT (STDMETHODCALLTYPE* InternetProtocol_Terminate_Fn)(
     45     IInternetProtocol* this_object, DWORD options);
     46 
     47 class ProtData;
     48 
     49 // A class to wrap protocol sink in IInternetProtocol::Start[Ex] for
     50 // HTTP and HTTPS protocols.
     51 //
     52 // This is an alternative to a mime filter and we have to do this in order
     53 // to inspect initial portion of HTML for 'chrome' meta tag and report
     54 // a different mime type in that case.
     55 //
     56 // We implement several documented interfaces
     57 // supported by the original sink provided by urlmon. There are a few
     58 // undocumented interfaces that we have chosen not to implement
     59 // but delegate simply the QI.
     60 class ProtocolSinkWrap
     61     : public CComObjectRootEx<CComMultiThreadModel>,
     62       public IInternetProtocolSink {
     63  public:
     64 BEGIN_COM_MAP(ProtocolSinkWrap)
     65   COM_INTERFACE_ENTRY(IInternetProtocolSink)
     66   COM_INTERFACE_BLIND_DELEGATE()
     67 END_COM_MAP()
     68 
     69   static base::win::ScopedComPtr<IInternetProtocolSink> CreateNewSink(
     70       IInternetProtocolSink* sink, ProtData* prot_data);
     71 
     72   // Enables or disables activation of Chrome Frame via the X-UA-Compatible
     73   // header or meta tag. The tag/header is respected by default.
     74   static void set_ignore_xua(bool ignore_xua) { ignore_xua_ = ignore_xua; }
     75   static bool ignore_xua() { return ignore_xua_; }
     76 
     77   // Apparently this has to be public, to satisfy COM_INTERFACE_BLIND_DELEGATE
     78   IInternetProtocolSink* delegate() {
     79     return delegate_;
     80   }
     81 
     82  protected:
     83   ProtocolSinkWrap();
     84   ~ProtocolSinkWrap();
     85 
     86  private:
     87   static bool ignore_xua_;
     88 
     89   // IInternetProtocolSink methods
     90   STDMETHOD(Switch)(PROTOCOLDATA* protocol_data);
     91   STDMETHOD(ReportProgress)(ULONG status_code, LPCWSTR status_text);
     92   STDMETHOD(ReportData)(DWORD flags, ULONG progress, ULONG max_progress);
     93   STDMETHOD(ReportResult)(HRESULT result, DWORD error, LPCWSTR result_text);
     94 
     95   // Remember original sink
     96   base::win::ScopedComPtr<IInternetProtocolSink> delegate_;
     97   base::win::ScopedComPtr<IServiceProvider> delegate_service_provider_;
     98   scoped_refptr<ProtData> prot_data_;
     99   DISALLOW_COPY_AND_ASSIGN(ProtocolSinkWrap);
    100 };
    101 
    102 class ProtData : public base::RefCounted<ProtData> {
    103  public:
    104   ProtData(IInternetProtocol* protocol, InternetProtocol_Read_Fn read_fun,
    105            const wchar_t* url);
    106   ~ProtData();
    107   HRESULT Read(void* buffer, ULONG size, ULONG* size_read);
    108   HRESULT ReportProgress(IInternetProtocolSink* delegate,
    109                          ULONG status_code,
    110                          LPCWSTR status_text);
    111   HRESULT ReportData(IInternetProtocolSink* delegate,
    112                      DWORD flags, ULONG progress, ULONG max_progress);
    113   HRESULT ReportResult(IInternetProtocolSink* delegate, HRESULT result,
    114                        DWORD error, LPCWSTR result_text);
    115   void UpdateUrl(const wchar_t* url);
    116   static scoped_refptr<ProtData> DataFromProtocol(IInternetProtocol* protocol);
    117 
    118   RendererType renderer_type() {
    119     return renderer_type_;
    120   }
    121 
    122   // Valid only if renderer_type_ is CHROME.
    123   const std::string& referrer() const {
    124     return referrer_;
    125   }
    126 
    127   bool is_attach_external_tab_request() const {
    128     return read_fun_ == NULL;
    129   }
    130 
    131   // Removes the mapping between the protocol and the ProtData.
    132   void Invalidate();
    133 
    134   const std::wstring& url() const {
    135     return url_;
    136   }
    137 
    138  private:
    139   typedef std::map<IInternetProtocol*, ProtData*> ProtocolDataMap;
    140   static ProtocolDataMap datamap_;
    141   static base::Lock datamap_lock_;
    142 
    143   // Url we are retrieving. Used for RendererTypeForUrl() only.
    144   std::wstring url_;
    145   // HTTP "Referrer" header if we detect are going to switch.
    146   // We have to save and pass it to Chrome, so scripts can read it via DOM.
    147   std::string referrer_;
    148 
    149   // Our gate to IInternetProtocol::Read()
    150   IInternetProtocol* protocol_;
    151   InternetProtocol_Read_Fn read_fun_;
    152 
    153   // What BINDSTATUS_MIMETYPEAVAILABLE and Co. tells us.
    154   base::win::ScopedBstr suggested_mime_type_;
    155   // At least one of the following has been received:
    156   // BINDSTATUS_MIMETYPEAVAILABLE,
    157   // MIMESTATUS_VERIFIEDMIMETYPEAVAILABLE
    158   // BINDSTATUS_SERVER_MIMETYPEAVAILABLE
    159   bool has_suggested_mime_type_;
    160   // BINDSTATUS_SERVER_MIMETYPEAVAILABLE received, so we shall fire one.
    161   bool has_server_mime_type_;
    162 
    163   RendererType renderer_type_;
    164 
    165   // Buffer for accumulated data including 1 extra for NULL-terminator
    166   static const size_t kMaxContentSniffLength = 2 * 1024;
    167   char buffer_[kMaxContentSniffLength + 1];
    168   unsigned long buffer_size_;  // NOLINT
    169   unsigned long buffer_pos_;  // NOLINT
    170 
    171   HRESULT FillBuffer();
    172   void SaveSuggestedMimeType(LPCWSTR status_text);
    173   void FireSuggestedMimeType(IInternetProtocolSink* delegate);
    174   void SaveReferrer(IInternetProtocolSink* delegate);
    175 };
    176 
    177 struct TransactionHooks {
    178   void InstallHooks();
    179   void RevertHooks();
    180 };
    181 
    182 DECLSPEC_SELECTANY struct TransactionHooks g_trans_hooks;
    183 
    184 #endif  // CHROME_FRAME_PROTOCOL_SINK_WRAP_H_
    185