| // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROME_FRAME_PROTOCOL_SINK_WRAP_H_ |
| #define CHROME_FRAME_PROTOCOL_SINK_WRAP_H_ |
| |
| #include <exdisp.h> |
| #include <urlmon.h> |
| #include <atlbase.h> |
| #include <atlcom.h> |
| |
| #include <map> |
| #include <string> |
| |
| #include "base/basictypes.h" |
| #include "base/ref_counted.h" |
| #include "base/scoped_comptr_win.h" |
| #include "googleurl/src/gurl.h" |
| #include "chrome_frame/chrome_frame_delegate.h" |
| #include "chrome_frame/ie8_types.h" |
| #include "chrome_frame/utils.h" |
| #include "chrome_frame/vtable_patch_manager.h" |
| |
| // Typedefs for IInternetProtocol and related methods that we patch. |
| typedef HRESULT (STDMETHODCALLTYPE* InternetProtocol_Start_Fn)( |
| IInternetProtocol* this_object, LPCWSTR url, |
| IInternetProtocolSink* prot_sink, IInternetBindInfo* bind_info, |
| DWORD flags, HANDLE_PTR reserved); |
| typedef HRESULT (STDMETHODCALLTYPE* InternetProtocol_Read_Fn)( |
| IInternetProtocol* this_object, void* buffer, ULONG size, |
| ULONG* size_read); |
| typedef HRESULT (STDMETHODCALLTYPE* InternetProtocol_StartEx_Fn)( |
| IInternetProtocolEx* this_object, IUri* uri, |
| IInternetProtocolSink* prot_sink, IInternetBindInfo* bind_info, |
| DWORD flags, HANDLE_PTR reserved); |
| typedef HRESULT (STDMETHODCALLTYPE* InternetProtocolRoot_Continue_Fn)( |
| IInternetProtocolRoot* me, PROTOCOLDATA* data); |
| |
| // A class to wrap protocol sink in IInternetProtocol::Start[Ex] for |
| // HTTP and HTTPS protocols. |
| // |
| // This is an alternative to a mime filter and we have to do this in order |
| // to inspect initial portion of HTML for 'chrome' meta tag and report |
| // a different mime type in that case. |
| // |
| // We implement several documented interfaces |
| // supported by the original sink provided by urlmon. There are a few |
| // undocumented interfaces that we have chosen not to implement |
| // but delegate simply the QI. |
| class ProtocolSinkWrap |
| : public CComObjectRootEx<CComMultiThreadModel>, |
| public IInternetProtocolSink, |
| public IInternetBindInfoEx, |
| public IServiceProvider, |
| public IAuthenticate, |
| public IInternetProtocolEx, |
| public IInternetPriority, |
| public IWrappedProtocol, |
| // public IPreBindingSupport, // undocumented |
| // public ITransProtocolSink, // Undocumented |
| // public ITransactionInternal, // undocumented |
| public IUriContainer { |
| public: |
| |
| BEGIN_COM_MAP(ProtocolSinkWrap) |
| COM_INTERFACE_ENTRY(IInternetProtocolSink) |
| COM_INTERFACE_ENTRY(IInternetBindInfo) |
| COM_INTERFACE_ENTRY(IInternetBindInfoEx) |
| COM_INTERFACE_ENTRY(IServiceProvider) |
| COM_INTERFACE_ENTRY(IAuthenticate) |
| COM_INTERFACE_ENTRY(IInternetProtocolRoot) |
| COM_INTERFACE_ENTRY(IInternetProtocol) |
| COM_INTERFACE_ENTRY(IInternetProtocolEx) |
| COM_INTERFACE_ENTRY(IInternetPriority) |
| COM_INTERFACE_ENTRY(IWrappedProtocol) |
| COM_INTERFACE_ENTRY_IF_DELEGATE_SUPPORTS(IUriContainer) |
| COM_INTERFACE_BLIND_DELEGATE() |
| END_COM_MAP() |
| |
| ProtocolSinkWrap(); |
| virtual ~ProtocolSinkWrap(); |
| |
| bool Initialize(IInternetProtocol* protocol, |
| IInternetProtocolSink* original_sink, const wchar_t* url); |
| |
| // VTable patches the IInternetProtocol and IIntenetProtocolEx interface. |
| // Returns true on success. |
| static bool PatchProtocolHandlers(); |
| |
| // Unpatches the IInternetProtocol and IInternetProtocolEx interfaces. |
| static void UnpatchProtocolHandlers(); |
| |
| // IInternetProtocol/Ex patches. |
| static STDMETHODIMP OnStart(InternetProtocol_Start_Fn orig_start, |
| IInternetProtocol* protocol, LPCWSTR url, |
| IInternetProtocolSink* prot_sink, IInternetBindInfo* bind_info, |
| DWORD flags, HANDLE_PTR reserved); |
| |
| static STDMETHODIMP OnStartEx( |
| InternetProtocol_StartEx_Fn orig_start_ex, IInternetProtocolEx* protocol, |
| IUri* uri, IInternetProtocolSink* prot_sink, |
| IInternetBindInfo* bind_info, DWORD flags, HANDLE_PTR reserved); |
| |
| static STDMETHODIMP OnRead(InternetProtocol_Read_Fn orig_read, |
| IInternetProtocol* protocol, void* buffer, ULONG size, ULONG* size_read); |
| |
| // IInternetProtocolSink methods |
| STDMETHOD(Switch)(PROTOCOLDATA* protocol_data); |
| STDMETHOD(ReportProgress)(ULONG status_code, LPCWSTR status_text); |
| STDMETHOD(ReportData)(DWORD flags, ULONG progress, ULONG max_progress); |
| STDMETHOD(ReportResult)(HRESULT result, DWORD error, LPCWSTR result_text); |
| |
| // IInternetBindInfoEx |
| STDMETHOD(GetBindInfo)(DWORD* flags, BINDINFO* bind_info); |
| STDMETHOD(GetBindString)(ULONG string_type, LPOLESTR* string_array, |
| ULONG array_size, ULONG* size_returned); |
| STDMETHOD(GetBindInfoEx)(DWORD *flags, BINDINFO* bind_info, |
| DWORD* bindf2, DWORD *reserved); |
| |
| // IServiceProvider |
| STDMETHOD(QueryService)(REFGUID service_guid, REFIID riid, void** service); |
| |
| // IAuthenticate |
| STDMETHOD(Authenticate)(HWND* window, LPWSTR* user_name, LPWSTR* password); |
| |
| // IInternetProtocolEx |
| STDMETHOD(Start)(LPCWSTR url, IInternetProtocolSink *protocol_sink, |
| IInternetBindInfo* bind_info, DWORD flags, HANDLE_PTR reserved); |
| STDMETHOD(Continue)(PROTOCOLDATA* protocol_data); |
| STDMETHOD(Abort)(HRESULT reason, DWORD options); |
| STDMETHOD(Terminate)(DWORD options); |
| STDMETHOD(Suspend)(); |
| STDMETHOD(Resume)(); |
| STDMETHOD(Read)(void *buffer, ULONG size, ULONG* size_read); |
| STDMETHOD(Seek)(LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER* new_pos); |
| STDMETHOD(LockRequest)(DWORD options); |
| STDMETHOD(UnlockRequest)(); |
| STDMETHOD(StartEx)(IUri* uri, IInternetProtocolSink* protocol_sink, |
| IInternetBindInfo* bind_info, DWORD flags, HANDLE_PTR reserved); |
| |
| // IInternetPriority |
| STDMETHOD(SetPriority)(LONG priority); |
| STDMETHOD(GetPriority)(LONG* priority); |
| |
| // IWrappedProtocol |
| STDMETHOD(GetWrapperCode)(LONG *code, DWORD_PTR reserved); |
| |
| // public IUriContainer |
| STDMETHOD(GetIUri)(IUri** uri); |
| |
| // IPreBindingSupport, // undocumented |
| // ITransProtocolSink, // Undocumented |
| // ITransactionInternal, // undocumented |
| |
| IInternetProtocolSink* delegate() const { |
| return delegate_; |
| } |
| |
| protected: |
| enum RendererType { |
| UNDETERMINED, |
| CHROME, |
| OTHER |
| }; |
| |
| typedef std::map<IInternetProtocol*, ProtocolSinkWrap*> ProtocolSinkMap; |
| static const int kMaxContentSniffLength = 1024; |
| |
| static scoped_refptr<ProtocolSinkWrap> InstanceFromProtocol( |
| IInternetProtocol* protocol); |
| static ScopedComPtr<IInternetProtocolSink> MaybeWrapSink( |
| IInternetProtocol* protocol, IInternetProtocolSink* prot_sink, |
| const wchar_t* url); |
| |
| void DetermineRendererType(); |
| |
| HRESULT OnReadImpl(void* buffer, ULONG size, ULONG* size_read, |
| InternetProtocol_Read_Fn orig_read); |
| |
| // This function determines whether the current request should be handled |
| // by Chrome. If yes it reports the mime type as application/chromepage, |
| // which ensures that the ChromeFrame is instantiated for handling this |
| // request. |
| // Returns S_OK on success. |
| HRESULT CheckAndReportChromeMimeTypeForRequest(); |
| |
| bool is_undetermined() const { |
| return (UNDETERMINED == renderer_type_); |
| } |
| RendererType renderer_type() const { |
| return renderer_type_; |
| } |
| |
| // Creates an instance of the specified protocol handler and returns the |
| // IInternetProtocol interface pointer. |
| // Returns S_OK on success. |
| static HRESULT CreateProtocolHandlerInstance(const CLSID& clsid, |
| IInternetProtocol** protocol); |
| |
| // Helper function for patching the VTable of the IInternetProtocol |
| // interface. It instantiates the object identified by the protocol_clsid |
| // parameter and patches its VTable. |
| // Returns S_OK on success. |
| static HRESULT PatchProtocolMethods( |
| const CLSID& protocol_clsid, |
| vtable_patch::MethodPatchInfo* protocol_patch_info, |
| vtable_patch::MethodPatchInfo* protocol_ex_patch_info); |
| |
| // WARNING: Don't use GURL variables here. Please see |
| // http://b/issue?id=2102171 for details. |
| |
| // Remember original sink |
| ScopedComPtr<IInternetProtocolSink> delegate_; |
| |
| // Cannot take a reference on the protocol. |
| IInternetProtocol* protocol_; |
| RendererType renderer_type_; |
| |
| // Buffer for accumulated data including 1 extra for NULL-terminator |
| char buffer_[kMaxContentSniffLength + 1]; |
| unsigned long buffer_size_; // NOLINT |
| unsigned long buffer_pos_; // NOLINT |
| |
| // Accumulated result |
| bool is_saved_result_; |
| HRESULT result_code_; |
| DWORD result_error_; |
| std::wstring result_text_; |
| // For tracking re-entrency and preventing duplicate Read()s from |
| // distorting the outcome of ReportData. |
| int report_data_recursiveness_; |
| |
| static ProtocolSinkMap sink_map_; |
| // TODO(joshia): Replace with Lock |
| static CComAutoCriticalSection sink_map_lock_; |
| |
| std::wstring url_; |
| |
| // Set to true if we are in the context of determining the desired renderer |
| // type. |
| bool determining_renderer_type_; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(ProtocolSinkWrap); |
| }; |
| |
| #endif // CHROME_FRAME_PROTOCOL_SINK_WRAP_H_ |