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