OLD | NEW |
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef CHROME_FRAME_PROTOCOL_SINK_WRAP_H_ | 5 #ifndef CHROME_FRAME_PROTOCOL_SINK_WRAP_H_ |
6 #define CHROME_FRAME_PROTOCOL_SINK_WRAP_H_ | 6 #define CHROME_FRAME_PROTOCOL_SINK_WRAP_H_ |
7 | 7 |
8 #include <exdisp.h> | 8 #include <exdisp.h> |
9 #include <urlmon.h> | 9 #include <urlmon.h> |
10 #include <atlbase.h> | 10 #include <atlbase.h> |
11 #include <atlcom.h> | 11 #include <atlcom.h> |
12 | 12 |
13 #include <map> | 13 #include <map> |
14 #include <string> | 14 #include <string> |
15 | 15 |
16 #include "base/basictypes.h" | 16 #include "base/basictypes.h" |
17 #include "base/ref_counted.h" | 17 #include "base/ref_counted.h" |
18 #include "base/scoped_comptr_win.h" | 18 #include "base/scoped_comptr_win.h" |
| 19 #include "base/scoped_bstr_win.h" |
19 #include "googleurl/src/gurl.h" | 20 #include "googleurl/src/gurl.h" |
20 #include "chrome_frame/chrome_frame_delegate.h" | 21 #include "chrome_frame/chrome_frame_delegate.h" |
21 #include "chrome_frame/ie8_types.h" | 22 #include "chrome_frame/ie8_types.h" |
22 #include "chrome_frame/utils.h" | 23 #include "chrome_frame/utils.h" |
23 #include "chrome_frame/vtable_patch_manager.h" | 24 #include "chrome_frame/vtable_patch_manager.h" |
24 | 25 |
25 // Typedefs for IInternetProtocol and related methods that we patch. | 26 // Typedefs for IInternetProtocol and related methods that we patch. |
26 typedef HRESULT (STDMETHODCALLTYPE* InternetProtocol_Start_Fn)( | 27 typedef HRESULT (STDMETHODCALLTYPE* InternetProtocol_Start_Fn)( |
27 IInternetProtocol* this_object, LPCWSTR url, | 28 IInternetProtocol* this_object, LPCWSTR url, |
28 IInternetProtocolSink* prot_sink, IInternetBindInfo* bind_info, | 29 IInternetProtocolSink* prot_sink, IInternetBindInfo* bind_info, |
29 DWORD flags, HANDLE_PTR reserved); | 30 DWORD flags, HANDLE_PTR reserved); |
30 typedef HRESULT (STDMETHODCALLTYPE* InternetProtocol_Read_Fn)( | 31 typedef HRESULT (STDMETHODCALLTYPE* InternetProtocol_Read_Fn)( |
31 IInternetProtocol* this_object, void* buffer, ULONG size, | 32 IInternetProtocol* this_object, void* buffer, ULONG size, |
32 ULONG* size_read); | 33 ULONG* size_read); |
33 typedef HRESULT (STDMETHODCALLTYPE* InternetProtocol_StartEx_Fn)( | 34 typedef HRESULT (STDMETHODCALLTYPE* InternetProtocol_StartEx_Fn)( |
34 IInternetProtocolEx* this_object, IUri* uri, | 35 IInternetProtocolEx* this_object, IUri* uri, |
35 IInternetProtocolSink* prot_sink, IInternetBindInfo* bind_info, | 36 IInternetProtocolSink* prot_sink, IInternetBindInfo* bind_info, |
36 DWORD flags, HANDLE_PTR reserved); | 37 DWORD flags, HANDLE_PTR reserved); |
37 typedef HRESULT (STDMETHODCALLTYPE* InternetProtocolRoot_Continue_Fn)( | 38 typedef HRESULT (STDMETHODCALLTYPE* InternetProtocolRoot_Continue_Fn)( |
38 IInternetProtocolRoot* me, PROTOCOLDATA* data); | 39 IInternetProtocolRoot* me, PROTOCOLDATA* data); |
39 | 40 |
| 41 |
| 42 enum RendererType { |
| 43 UNDETERMINED, |
| 44 CHROME, |
| 45 OTHER |
| 46 }; |
| 47 |
| 48 class ProtData; |
| 49 |
40 // A class to wrap protocol sink in IInternetProtocol::Start[Ex] for | 50 // A class to wrap protocol sink in IInternetProtocol::Start[Ex] for |
41 // HTTP and HTTPS protocols. | 51 // HTTP and HTTPS protocols. |
42 // | 52 // |
43 // This is an alternative to a mime filter and we have to do this in order | 53 // This is an alternative to a mime filter and we have to do this in order |
44 // to inspect initial portion of HTML for 'chrome' meta tag and report | 54 // to inspect initial portion of HTML for 'chrome' meta tag and report |
45 // a different mime type in that case. | 55 // a different mime type in that case. |
46 // | 56 // |
47 // We implement several documented interfaces | 57 // We implement several documented interfaces |
48 // supported by the original sink provided by urlmon. There are a few | 58 // supported by the original sink provided by urlmon. There are a few |
49 // undocumented interfaces that we have chosen not to implement | 59 // undocumented interfaces that we have chosen not to implement |
50 // but delegate simply the QI. | 60 // but delegate simply the QI. |
51 class ProtocolSinkWrap | 61 class ProtocolSinkWrap |
52 : public CComObjectRootEx<CComMultiThreadModel>, | 62 : public CComObjectRootEx<CComMultiThreadModel>, |
53 public IInternetProtocolSink, | 63 public IInternetProtocolSink { |
54 public IInternetBindInfoEx, | |
55 public IServiceProvider, | |
56 public IAuthenticate, | |
57 public IInternetProtocolEx, | |
58 public IInternetPriority, | |
59 public IWrappedProtocol, | |
60 // public IPreBindingSupport, // undocumented | |
61 // public ITransProtocolSink, // Undocumented | |
62 // public ITransactionInternal, // undocumented | |
63 public IUriContainer { | |
64 public: | 64 public: |
65 | 65 |
66 BEGIN_COM_MAP(ProtocolSinkWrap) | 66 BEGIN_COM_MAP(ProtocolSinkWrap) |
67 COM_INTERFACE_ENTRY(IInternetProtocolSink) | 67 COM_INTERFACE_ENTRY(IInternetProtocolSink) |
68 COM_INTERFACE_ENTRY(IInternetBindInfo) | |
69 COM_INTERFACE_ENTRY(IInternetBindInfoEx) | |
70 COM_INTERFACE_ENTRY(IServiceProvider) | |
71 COM_INTERFACE_ENTRY(IAuthenticate) | |
72 COM_INTERFACE_ENTRY(IInternetProtocolRoot) | |
73 COM_INTERFACE_ENTRY(IInternetProtocol) | |
74 COM_INTERFACE_ENTRY(IInternetProtocolEx) | |
75 COM_INTERFACE_ENTRY(IInternetPriority) | |
76 COM_INTERFACE_ENTRY(IWrappedProtocol) | |
77 COM_INTERFACE_ENTRY_IF_DELEGATE_SUPPORTS(IUriContainer) | |
78 COM_INTERFACE_BLIND_DELEGATE() | 68 COM_INTERFACE_BLIND_DELEGATE() |
79 END_COM_MAP() | 69 END_COM_MAP() |
80 | 70 |
| 71 static ScopedComPtr<IInternetProtocolSink> CreateNewSink( |
| 72 IInternetProtocolSink* sink, ProtData* prot_data); |
| 73 |
| 74 // Apparently this has to be public, to satisfy COM_INTERFACE_BLIND_DELEGATE |
| 75 IInternetProtocolSink* delegate() { |
| 76 return delegate_; |
| 77 } |
| 78 |
| 79 protected: |
81 ProtocolSinkWrap(); | 80 ProtocolSinkWrap(); |
82 virtual ~ProtocolSinkWrap(); | 81 ~ProtocolSinkWrap(); |
83 | 82 |
84 bool Initialize(IInternetProtocol* protocol, | 83 private: |
85 IInternetProtocolSink* original_sink, const wchar_t* url); | |
86 | |
87 // VTable patches the IInternetProtocol and IIntenetProtocolEx interface. | |
88 // Returns true on success. | |
89 static bool PatchProtocolHandlers(); | |
90 | |
91 // Unpatches the IInternetProtocol and IInternetProtocolEx interfaces. | |
92 static void UnpatchProtocolHandlers(); | |
93 | |
94 // IInternetProtocol/Ex patches. | |
95 static STDMETHODIMP OnStart(InternetProtocol_Start_Fn orig_start, | |
96 IInternetProtocol* protocol, LPCWSTR url, | |
97 IInternetProtocolSink* prot_sink, IInternetBindInfo* bind_info, | |
98 DWORD flags, HANDLE_PTR reserved); | |
99 | |
100 static STDMETHODIMP OnStartEx( | |
101 InternetProtocol_StartEx_Fn orig_start_ex, IInternetProtocolEx* protocol, | |
102 IUri* uri, IInternetProtocolSink* prot_sink, | |
103 IInternetBindInfo* bind_info, DWORD flags, HANDLE_PTR reserved); | |
104 | |
105 static STDMETHODIMP OnRead(InternetProtocol_Read_Fn orig_read, | |
106 IInternetProtocol* protocol, void* buffer, ULONG size, ULONG* size_read); | |
107 | |
108 // IInternetProtocolSink methods | 84 // IInternetProtocolSink methods |
109 STDMETHOD(Switch)(PROTOCOLDATA* protocol_data); | 85 STDMETHOD(Switch)(PROTOCOLDATA* protocol_data); |
110 STDMETHOD(ReportProgress)(ULONG status_code, LPCWSTR status_text); | 86 STDMETHOD(ReportProgress)(ULONG status_code, LPCWSTR status_text); |
111 STDMETHOD(ReportData)(DWORD flags, ULONG progress, ULONG max_progress); | 87 STDMETHOD(ReportData)(DWORD flags, ULONG progress, ULONG max_progress); |
112 STDMETHOD(ReportResult)(HRESULT result, DWORD error, LPCWSTR result_text); | 88 STDMETHOD(ReportResult)(HRESULT result, DWORD error, LPCWSTR result_text); |
113 | 89 |
114 // IInternetBindInfoEx | 90 // Remember original sink |
115 STDMETHOD(GetBindInfo)(DWORD* flags, BINDINFO* bind_info); | 91 ScopedComPtr<IInternetProtocolSink> delegate_; |
116 STDMETHOD(GetBindString)(ULONG string_type, LPOLESTR* string_array, | 92 scoped_refptr<ProtData> prot_data_; |
117 ULONG array_size, ULONG* size_returned); | 93 DISALLOW_COPY_AND_ASSIGN(ProtocolSinkWrap); |
118 STDMETHOD(GetBindInfoEx)(DWORD *flags, BINDINFO* bind_info, | 94 }; |
119 DWORD* bindf2, DWORD *reserved); | |
120 | 95 |
121 // IServiceProvider | 96 class ProtData : public base::RefCounted<ProtData> { |
122 STDMETHOD(QueryService)(REFGUID service_guid, REFIID riid, void** service); | 97 public: |
| 98 ProtData(IInternetProtocol* protocol, InternetProtocol_Read_Fn read_fun, |
| 99 const wchar_t* url); |
| 100 ~ProtData(); |
| 101 HRESULT Read(void* buffer, ULONG size, ULONG* size_read); |
| 102 HRESULT ReportProgress(IInternetProtocolSink* delegate, |
| 103 ULONG status_code, |
| 104 LPCWSTR status_text); |
| 105 HRESULT ReportData(IInternetProtocolSink* delegate, |
| 106 DWORD flags, ULONG progress, ULONG max_progress); |
| 107 HRESULT ReportResult(IInternetProtocolSink* delegate, HRESULT result, |
| 108 DWORD error, LPCWSTR result_text); |
| 109 void UpdateUrl(const wchar_t* url); |
| 110 static scoped_refptr<ProtData> DataFromProtocol(IInternetProtocol* protocol); |
123 | 111 |
124 // IAuthenticate | 112 RendererType renderer_type() { |
125 STDMETHOD(Authenticate)(HWND* window, LPWSTR* user_name, LPWSTR* password); | |
126 | |
127 // IInternetProtocolEx | |
128 STDMETHOD(Start)(LPCWSTR url, IInternetProtocolSink *protocol_sink, | |
129 IInternetBindInfo* bind_info, DWORD flags, HANDLE_PTR reserved); | |
130 STDMETHOD(Continue)(PROTOCOLDATA* protocol_data); | |
131 STDMETHOD(Abort)(HRESULT reason, DWORD options); | |
132 STDMETHOD(Terminate)(DWORD options); | |
133 STDMETHOD(Suspend)(); | |
134 STDMETHOD(Resume)(); | |
135 STDMETHOD(Read)(void *buffer, ULONG size, ULONG* size_read); | |
136 STDMETHOD(Seek)(LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER* new_pos); | |
137 STDMETHOD(LockRequest)(DWORD options); | |
138 STDMETHOD(UnlockRequest)(); | |
139 STDMETHOD(StartEx)(IUri* uri, IInternetProtocolSink* protocol_sink, | |
140 IInternetBindInfo* bind_info, DWORD flags, HANDLE_PTR reserved); | |
141 | |
142 // IInternetPriority | |
143 STDMETHOD(SetPriority)(LONG priority); | |
144 STDMETHOD(GetPriority)(LONG* priority); | |
145 | |
146 // IWrappedProtocol | |
147 STDMETHOD(GetWrapperCode)(LONG *code, DWORD_PTR reserved); | |
148 | |
149 // public IUriContainer | |
150 STDMETHOD(GetIUri)(IUri** uri); | |
151 | |
152 // IPreBindingSupport, // undocumented | |
153 // ITransProtocolSink, // Undocumented | |
154 // ITransactionInternal, // undocumented | |
155 | |
156 IInternetProtocolSink* delegate() const { | |
157 return delegate_; | |
158 } | |
159 | |
160 protected: | |
161 enum RendererType { | |
162 UNDETERMINED, | |
163 CHROME, | |
164 OTHER | |
165 }; | |
166 | |
167 typedef std::map<IInternetProtocol*, ProtocolSinkWrap*> ProtocolSinkMap; | |
168 static const int kMaxContentSniffLength = 1024; | |
169 | |
170 static scoped_refptr<ProtocolSinkWrap> InstanceFromProtocol( | |
171 IInternetProtocol* protocol); | |
172 static ScopedComPtr<IInternetProtocolSink> MaybeWrapSink( | |
173 IInternetProtocol* protocol, IInternetProtocolSink* prot_sink, | |
174 const wchar_t* url); | |
175 | |
176 void DetermineRendererType(); | |
177 | |
178 HRESULT OnReadImpl(void* buffer, ULONG size, ULONG* size_read, | |
179 InternetProtocol_Read_Fn orig_read); | |
180 | |
181 // This function determines whether the current request should be handled | |
182 // by Chrome. If yes it reports the mime type as application/chromepage, | |
183 // which ensures that the ChromeFrame is instantiated for handling this | |
184 // request. | |
185 // Returns S_OK on success. | |
186 HRESULT CheckAndReportChromeMimeTypeForRequest(); | |
187 | |
188 bool is_undetermined() const { | |
189 return (UNDETERMINED == renderer_type_); | |
190 } | |
191 RendererType renderer_type() const { | |
192 return renderer_type_; | 113 return renderer_type_; |
193 } | 114 } |
194 | 115 |
195 // Creates an instance of the specified protocol handler and returns the | 116 private: |
196 // IInternetProtocol interface pointer. | 117 typedef std::map<IInternetProtocol*, ProtData*> ProtocolDataMap; |
197 // Returns S_OK on success. | 118 static ProtocolDataMap datamap_; |
198 static HRESULT CreateProtocolHandlerInstance(const CLSID& clsid, | 119 static Lock datamap_lock_; |
199 IInternetProtocol** protocol); | |
200 | 120 |
201 // Helper function for patching the VTable of the IInternetProtocol | 121 // Url we are retrieving. Used for IsOptInUrl() only. |
202 // interface. It instantiates the object identified by the protocol_clsid | 122 std::wstring url_; |
203 // parameter and patches its VTable. | 123 // Our gate to IInternetProtocol::Read() |
204 // Returns S_OK on success. | 124 IInternetProtocol* protocol_; |
205 static HRESULT PatchProtocolMethods( | 125 InternetProtocol_Read_Fn read_fun_; |
206 const CLSID& protocol_clsid, | |
207 vtable_patch::MethodPatchInfo* protocol_patch_info, | |
208 vtable_patch::MethodPatchInfo* protocol_ex_patch_info); | |
209 | 126 |
210 // WARNING: Don't use GURL variables here. Please see | 127 // What BINDSTATUS_MIMETYPEAVAILABLE and Co. tells us. |
211 // http://b/issue?id=2102171 for details. | 128 ScopedBstr suggested_mime_type_; |
| 129 // At least one of the following has been received: |
| 130 // BINDSTATUS_MIMETYPEAVAILABLE, |
| 131 // MIMESTATUS_VERIFIEDMIMETYPEAVAILABLE |
| 132 // BINDSTATUS_SERVER_MIMETYPEAVAILABLE |
| 133 bool has_suggested_mime_type_; |
| 134 // BINDSTATUS_SERVER_MIMETYPEAVAILABLE received, so we shall fire one. |
| 135 bool has_server_mime_type_; |
212 | 136 |
213 // Remember original sink | 137 // Did we received ReportData() |
214 ScopedComPtr<IInternetProtocolSink> delegate_; | 138 bool report_data_received_; |
215 | |
216 // Cannot take a reference on the protocol. | |
217 IInternetProtocol* protocol_; | |
218 RendererType renderer_type_; | 139 RendererType renderer_type_; |
219 | 140 |
220 // Buffer for accumulated data including 1 extra for NULL-terminator | 141 // Buffer for accumulated data including 1 extra for NULL-terminator |
| 142 static const size_t kMaxContentSniffLength = 2 * 1024; |
221 char buffer_[kMaxContentSniffLength + 1]; | 143 char buffer_[kMaxContentSniffLength + 1]; |
222 unsigned long buffer_size_; // NOLINT | 144 unsigned long buffer_size_; // NOLINT |
223 unsigned long buffer_pos_; // NOLINT | 145 unsigned long buffer_pos_; // NOLINT |
224 | 146 |
225 // Accumulated result | 147 HRESULT FillBuffer(); |
226 bool is_saved_result_; | 148 void SaveSuggestedMimeType(LPCWSTR status_text); |
227 HRESULT result_code_; | 149 void FireSugestedMimeType(IInternetProtocolSink* delegate); |
228 DWORD result_error_; | |
229 std::wstring result_text_; | |
230 // For tracking re-entrency and preventing duplicate Read()s from | |
231 // distorting the outcome of ReportData. | |
232 int report_data_recursiveness_; | |
233 | |
234 static ProtocolSinkMap sink_map_; | |
235 // TODO(joshia): Replace with Lock | |
236 static CComAutoCriticalSection sink_map_lock_; | |
237 | |
238 std::wstring url_; | |
239 | |
240 // Set to true if we are in the context of determining the desired renderer | |
241 // type. | |
242 bool determining_renderer_type_; | |
243 | |
244 private: | |
245 DISALLOW_COPY_AND_ASSIGN(ProtocolSinkWrap); | |
246 }; | 150 }; |
247 | 151 |
| 152 struct TransactionHooks { |
| 153 void InstallHooks(); |
| 154 void RevertHooks(); |
| 155 }; |
| 156 |
| 157 DECLSPEC_SELECTANY struct TransactionHooks g_trans_hooks; |
| 158 |
248 #endif // CHROME_FRAME_PROTOCOL_SINK_WRAP_H_ | 159 #endif // CHROME_FRAME_PROTOCOL_SINK_WRAP_H_ |
| 160 |
OLD | NEW |