| 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_URLMON_URL_REQUEST_H_ | 5 #ifndef CHROME_FRAME_URLMON_URL_REQUEST_H_ |
| 6 #define CHROME_FRAME_URLMON_URL_REQUEST_H_ | 6 #define CHROME_FRAME_URLMON_URL_REQUEST_H_ |
| 7 | 7 |
| 8 #include <urlmon.h> | 8 #include <urlmon.h> |
| 9 #include <atlbase.h> | 9 #include <atlbase.h> |
| 10 #include <atlcom.h> | 10 #include <atlcom.h> |
| 11 #include <atlwin.h> | |
| 12 #include <algorithm> | |
| 13 #include <string> | 11 #include <string> |
| 14 | 12 |
| 15 #include "base/lock.h" | 13 #include "base/scoped_comptr_win.h" |
| 16 #include "base/platform_thread.h" | |
| 17 #include "base/thread.h" | 14 #include "base/thread.h" |
| 18 #include "base/scoped_comptr_win.h" | 15 #include "base/waitable_event.h" |
| 19 #include "chrome_frame/plugin_url_request.h" | 16 #include "chrome_frame/plugin_url_request.h" |
| 20 #include "chrome_frame/chrome_frame_delegate.h" | 17 #include "chrome_frame/utils.h" |
| 21 | 18 |
| 22 #include "net/base/net_errors.h" | 19 class UrlmonUrlRequest; |
| 23 #include "net/base/upload_data.h" | |
| 24 | 20 |
| 25 class UrlmonUrlRequest | 21 class UrlmonUrlRequestManager : |
| 26 : public CComObjectRootEx<CComMultiThreadModel>, | 22 public PluginUrlRequestManager, |
| 27 public PluginUrlRequest, | 23 public PluginUrlRequestDelegate { |
| 28 public IServiceProviderImpl<UrlmonUrlRequest>, | |
| 29 public IBindStatusCallback, | |
| 30 public IHttpNegotiate, | |
| 31 public IAuthenticate, | |
| 32 public IHttpSecurity, | |
| 33 public CWindowImpl<UrlmonUrlRequest>, | |
| 34 public TaskMarshallerThroughWindowsMessages<UrlmonUrlRequest> { | |
| 35 public: | 24 public: |
| 36 typedef TaskMarshallerThroughWindowsMessages<UrlmonUrlRequest> | 25 UrlmonUrlRequestManager(); |
| 37 TaskMarshaller; | 26 ~UrlmonUrlRequestManager(); |
| 38 | 27 |
| 39 UrlmonUrlRequest(); | 28 // Use specific moniker and bind context when Chrome request this url. |
| 40 ~UrlmonUrlRequest(); | 29 // Used from ChromeActiveDocument's implementation of IPersistMoniker::Load(). |
| 41 | 30 void UseMonikerForUrl(IMoniker* moniker, IBindCtx* bind_ctx, |
| 42 BEGIN_COM_MAP(UrlmonUrlRequest) | 31 const std::wstring& url); |
| 43 COM_INTERFACE_ENTRY(IHttpNegotiate) | 32 void StealMonikerFromRequest(int request_id, IMoniker** moniker); |
| 44 COM_INTERFACE_ENTRY(IServiceProvider) | |
| 45 COM_INTERFACE_ENTRY(IBindStatusCallback) | |
| 46 COM_INTERFACE_ENTRY(IWindowForBindingUI) | |
| 47 COM_INTERFACE_ENTRY(IAuthenticate) | |
| 48 COM_INTERFACE_ENTRY(IHttpSecurity) | |
| 49 END_COM_MAP() | |
| 50 | |
| 51 BEGIN_SERVICE_MAP(UrlmonUrlRequest) | |
| 52 SERVICE_ENTRY(IID_IHttpNegotiate); | |
| 53 END_SERVICE_MAP() | |
| 54 | |
| 55 BEGIN_MSG_MAP(UrlmonUrlRequest) | |
| 56 CHAIN_MSG_MAP(TaskMarshaller) | |
| 57 END_MSG_MAP() | |
| 58 | |
| 59 // PluginUrlRequest implementation | |
| 60 virtual bool Start(); | |
| 61 virtual void Stop(); | |
| 62 virtual bool Read(int bytes_to_read); | |
| 63 | |
| 64 void TransferToHost(IUnknown* host); | |
| 65 | |
| 66 // IBindStatusCallback implementation | |
| 67 STDMETHOD(OnStartBinding)(DWORD reserved, IBinding* binding); | |
| 68 STDMETHOD(GetPriority)(LONG* priority); | |
| 69 STDMETHOD(OnLowResource)(DWORD reserved); | |
| 70 STDMETHOD(OnProgress)(ULONG progress, ULONG max_progress, | |
| 71 ULONG status_code, LPCWSTR status_text); | |
| 72 STDMETHOD(OnStopBinding)(HRESULT result, LPCWSTR error); | |
| 73 STDMETHOD(GetBindInfo)(DWORD* bind_flags, BINDINFO* bind_info); | |
| 74 STDMETHOD(OnDataAvailable)(DWORD flags, DWORD size, FORMATETC* formatetc, | |
| 75 STGMEDIUM* storage); | |
| 76 STDMETHOD(OnObjectAvailable)(REFIID iid, IUnknown* object); | |
| 77 | |
| 78 // IHttpNegotiate implementation | |
| 79 STDMETHOD(BeginningTransaction)(const wchar_t* url, | |
| 80 const wchar_t* current_headers, DWORD reserved, | |
| 81 wchar_t** additional_headers); | |
| 82 STDMETHOD(OnResponse)(DWORD dwResponseCode, const wchar_t* response_headers, | |
| 83 const wchar_t* request_headers, wchar_t** additional_headers); | |
| 84 | |
| 85 // IWindowForBindingUI implementation. This interface is used typically to | |
| 86 // query the window handle which URLMON uses as the parent of error dialogs. | |
| 87 STDMETHOD(GetWindow)(REFGUID guid_reason, HWND* parent_window); | |
| 88 | |
| 89 // IAuthenticate implementation. Used to return the parent window for the | |
| 90 // dialog displayed by IE for authenticating with a proxy. | |
| 91 STDMETHOD(Authenticate)(HWND* parent_window, LPWSTR* user_name, | |
| 92 LPWSTR* password); | |
| 93 | |
| 94 // IHttpSecurity implementation. | |
| 95 STDMETHOD(OnSecurityProblem)(DWORD problem); | |
| 96 | |
| 97 HRESULT ConnectToExistingMoniker(IMoniker* moniker, IBindCtx* context, | |
| 98 const std::wstring& url); | |
| 99 | |
| 100 void set_parent_window(HWND parent_window) { | |
| 101 parent_window_ = parent_window; | |
| 102 } | |
| 103 | |
| 104 // Needed to support PostTask. | |
| 105 static bool ImplementsThreadSafeReferenceCounting() { | |
| 106 return true; | |
| 107 } | |
| 108 | |
| 109 // URL requests are handled on this thread. | |
| 110 void set_worker_thread(base::Thread* worker_thread) { | |
| 111 worker_thread_ = worker_thread; | |
| 112 } | |
| 113 | |
| 114 virtual void OnFinalMessage(HWND window); | |
| 115 | |
| 116 protected: | |
| 117 // The following functions issue and handle Urlmon requests on the dedicated | |
| 118 // Urlmon thread. | |
| 119 void StartAsync(); | |
| 120 void StopAsync(); | |
| 121 void ReadAsync(int bytes_to_read); | |
| 122 void ReleaseBindings(); | |
| 123 | |
| 124 static const size_t kCopyChunkSize = 32 * 1024; | |
| 125 // URL requests are handled on this thread. | |
| 126 base::Thread* worker_thread_; | |
| 127 | |
| 128 // A fake stream class to make it easier to copy received data using | |
| 129 // IStream::CopyTo instead of allocating temporary buffers and keeping | |
| 130 // track of data copied so far. | |
| 131 class SendStream | |
| 132 : public CComObjectRoot, | |
| 133 public IStream { | |
| 134 public: | |
| 135 SendStream() { | |
| 136 } | |
| 137 | |
| 138 BEGIN_COM_MAP(SendStream) | |
| 139 COM_INTERFACE_ENTRY(IStream) | |
| 140 COM_INTERFACE_ENTRY(ISequentialStream) | |
| 141 END_COM_MAP() | |
| 142 | |
| 143 void Initialize(UrlmonUrlRequest* request) { | |
| 144 request_ = request; | |
| 145 } | |
| 146 | |
| 147 STDMETHOD(Read)(void* pv, ULONG cb, ULONG* read) { | |
| 148 DCHECK(false) << __FUNCTION__; | |
| 149 return E_NOTIMPL; | |
| 150 } | |
| 151 | |
| 152 STDMETHOD(Write)(const void * buffer, ULONG size, ULONG* size_written) { | |
| 153 DCHECK(request_); | |
| 154 int size_to_write = static_cast<int>( | |
| 155 std::min(static_cast<ULONG>(MAXINT), size)); | |
| 156 request_->OnReadComplete(buffer, size_to_write); | |
| 157 if (size_written) | |
| 158 *size_written = size_to_write; | |
| 159 return S_OK; | |
| 160 } | |
| 161 | |
| 162 STDMETHOD(Seek)(LARGE_INTEGER move, DWORD origin, ULARGE_INTEGER* new_pos) { | |
| 163 DCHECK(false) << __FUNCTION__; | |
| 164 return E_NOTIMPL; | |
| 165 } | |
| 166 | |
| 167 STDMETHOD(SetSize)(ULARGE_INTEGER new_size) { | |
| 168 DCHECK(false) << __FUNCTION__; | |
| 169 return E_NOTIMPL; | |
| 170 } | |
| 171 | |
| 172 STDMETHOD(CopyTo)(IStream* stream, ULARGE_INTEGER cb, ULARGE_INTEGER* read, | |
| 173 ULARGE_INTEGER* written) { | |
| 174 DCHECK(false) << __FUNCTION__; | |
| 175 return E_NOTIMPL; | |
| 176 } | |
| 177 | |
| 178 STDMETHOD(Commit)(DWORD flags) { | |
| 179 DCHECK(false) << __FUNCTION__; | |
| 180 return E_NOTIMPL; | |
| 181 } | |
| 182 | |
| 183 STDMETHOD(Revert)() { | |
| 184 DCHECK(false) << __FUNCTION__; | |
| 185 return E_NOTIMPL; | |
| 186 } | |
| 187 | |
| 188 STDMETHOD(LockRegion)(ULARGE_INTEGER offset, ULARGE_INTEGER cb, | |
| 189 DWORD type) { | |
| 190 DCHECK(false) << __FUNCTION__; | |
| 191 return E_NOTIMPL; | |
| 192 } | |
| 193 | |
| 194 STDMETHOD(UnlockRegion)(ULARGE_INTEGER offset, ULARGE_INTEGER cb, | |
| 195 DWORD type) { | |
| 196 DCHECK(false) << __FUNCTION__; | |
| 197 return E_NOTIMPL; | |
| 198 } | |
| 199 | |
| 200 STDMETHOD(Stat)(STATSTG *pstatstg, DWORD grfStatFlag) { | |
| 201 return E_NOTIMPL; | |
| 202 } | |
| 203 | |
| 204 STDMETHOD(Clone)(IStream** stream) { | |
| 205 DCHECK(false) << __FUNCTION__; | |
| 206 return E_NOTIMPL; | |
| 207 } | |
| 208 | |
| 209 protected: | |
| 210 scoped_refptr<UrlmonUrlRequest> request_; | |
| 211 DISALLOW_COPY_AND_ASSIGN(SendStream); | |
| 212 }; | |
| 213 | |
| 214 // Manage data caching. Note: this class supports cache | |
| 215 // size less than 2GB | |
| 216 class Cache { | |
| 217 public: | |
| 218 // Adds data to the end of the cache. | |
| 219 bool Append(IStream* source, size_t* bytes_copied); | |
| 220 | |
| 221 // Reads from the cache. | |
| 222 bool Read(IStream* dest, size_t size, size_t* bytes_copied); | |
| 223 | |
| 224 // Returns the size of the cache. | |
| 225 size_t Size() const; | |
| 226 | |
| 227 // Returns true if the cache has valid data. | |
| 228 bool is_valid() const { | |
| 229 return Size() != 0; | |
| 230 } | |
| 231 | |
| 232 protected: | |
| 233 std::vector<byte> cache_; | |
| 234 char read_buffer_[kCopyChunkSize]; | |
| 235 }; | |
| 236 | |
| 237 HRESULT StartAsyncDownload(); | |
| 238 // Sends over the response end notification to chrome, releases the bindings | |
| 239 // and releases the initial reference on the UrlmonUrlRequest object. | |
| 240 // After this function is called we should not attempt to access any members | |
| 241 // as the object could become invalid at any point. | |
| 242 void EndRequest(); | |
| 243 // Executes in the context of the UI thread and releases the outstanding | |
| 244 // reference to us. It also deletes the request mapping for this instance. | |
| 245 void EndRequestInternal(); | |
| 246 int GetHttpResponseStatus() const; | |
| 247 std::string GetHttpHeaders() const; | |
| 248 | |
| 249 static net::Error HresultToNetError(HRESULT hr); | |
| 250 | 33 |
| 251 private: | 34 private: |
| 252 std::wstring redirect_url_; | 35 struct MonikerForUrl { |
| 253 int redirect_status_; | 36 ScopedComPtr<IMoniker> moniker; |
| 254 ScopedComPtr<IBinding> binding_; | 37 ScopedComPtr<IBindCtx> bind_ctx; |
| 255 ScopedComPtr<IMoniker> moniker_; | 38 std::wstring url; |
| 256 ScopedComPtr<IBindCtx> bind_context_; | 39 }; |
| 257 Cache cached_data_; | |
| 258 size_t pending_read_size_; | |
| 259 URLRequestStatus status_; | |
| 260 | 40 |
| 261 PlatformThreadId thread_; | 41 friend class MessageLoop; |
| 262 static int instance_count_; | 42 friend struct RunnableMethodTraits<UrlmonUrlRequestManager>; |
| 263 HWND parent_window_; | 43 static bool ImplementsThreadSafeReferenceCounting() { return true; } |
| 264 // Set to true if a redirect notification was aborted. | 44 void AddRef() {} |
| 265 bool ignore_redirect_stop_binding_error_; | 45 void Release() {} |
| 266 | 46 |
| 267 DISALLOW_COPY_AND_ASSIGN(UrlmonUrlRequest); | 47 // PluginUrlRequestManager implementation. |
| 48 virtual bool IsThreadSafe(); |
| 49 virtual void StartRequest(int request_id, |
| 50 const IPC::AutomationURLRequest& request_info); |
| 51 virtual void ReadRequest(int request_id, int bytes_to_read); |
| 52 virtual void EndRequest(int request_id); |
| 53 virtual void StopAll(); |
| 54 |
| 55 // PluginUrlRequestDelegate implementation |
| 56 virtual void OnResponseStarted(int request_id, const char* mime_type, |
| 57 const char* headers, int size, base::Time last_modified, |
| 58 const std::string& peristent_cookies, const std::string& redirect_url, |
| 59 int redirect_status); |
| 60 virtual void OnReadComplete(int request_id, const void* buffer, int len); |
| 61 virtual void OnResponseEnd(int request_id, const URLRequestStatus& status); |
| 62 |
| 63 // Methods executed in worker thread. |
| 64 void StartRequestWorker(int request_id, |
| 65 const IPC::AutomationURLRequest& request_info, |
| 66 MonikerForUrl* moniker_for_url); |
| 67 void ReadRequestWorker(int request_id, int bytes_to_read); |
| 68 void EndRequestWorker(int request_id); |
| 69 void StopAllWorker(); |
| 70 void StealMonikerFromRequestWorker(int request_id, IMoniker** moniker, |
| 71 base::WaitableEvent* done); |
| 72 |
| 73 // Map for (request_id <-> UrlmonUrlRequest) |
| 74 typedef std::map<int, scoped_refptr<UrlmonUrlRequest> > RequestMap; |
| 75 RequestMap request_map_; |
| 76 scoped_refptr<UrlmonUrlRequest> LookupRequest(int request_id); |
| 77 |
| 78 scoped_ptr<MonikerForUrl> moniker_for_url_; |
| 79 STAThread worker_thread_; |
| 80 base::WaitableEvent map_empty_; |
| 81 bool stopping_; |
| 268 }; | 82 }; |
| 269 | 83 |
| 270 #endif // CHROME_FRAME_URLMON_URL_REQUEST_H_ | 84 #endif // CHROME_FRAME_URLMON_URL_REQUEST_H_ |
| 271 | 85 |
| OLD | NEW |