[email protected] | 27a112c | 2011-01-06 04:19:30 | [diff] [blame^] | 1 | // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
[email protected] | 3eb07da | 2010-02-01 19:48:36 | [diff] [blame] | 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_URLMON_URL_REQUEST_PRIVATE_H_ |
| 6 | #define CHROME_FRAME_URLMON_URL_REQUEST_PRIVATE_H_ |
| 7 | |
| 8 | #include <atlbase.h> |
| 9 | #include <atlcom.h> |
| 10 | #include <string> |
[email protected] | 3eb07da | 2010-02-01 19:48:36 | [diff] [blame] | 11 | |
[email protected] | 7e4468d5 | 2010-09-22 19:42:00 | [diff] [blame] | 12 | #include "base/callback.h" |
[email protected] | ce072a7 | 2010-12-31 20:02:16 | [diff] [blame] | 13 | #include "base/threading/platform_thread.h" |
[email protected] | 3eb07da | 2010-02-01 19:48:36 | [diff] [blame] | 14 | #include "net/base/net_errors.h" |
| 15 | #include "net/http/http_response_headers.h" |
| 16 | #include "net/url_request/url_request_status.h" |
[email protected] | 4cb6dca5 | 2010-04-08 22:11:31 | [diff] [blame] | 17 | #include "testing/gtest/include/gtest/gtest_prod.h" |
[email protected] | 3eb07da | 2010-02-01 19:48:36 | [diff] [blame] | 18 | |
[email protected] | 051236f | 2010-03-12 22:06:14 | [diff] [blame] | 19 | class RequestData; |
| 20 | |
[email protected] | 3eb07da | 2010-02-01 19:48:36 | [diff] [blame] | 21 | class UrlmonUrlRequest |
| 22 | : public CComObjectRootEx<CComMultiThreadModel>, |
| 23 | public PluginUrlRequest, |
| 24 | public IServiceProviderImpl<UrlmonUrlRequest>, |
| 25 | public IBindStatusCallback, |
| 26 | public IHttpNegotiate, |
| 27 | public IAuthenticate, |
| 28 | public IHttpSecurity { |
| 29 | public: |
[email protected] | 3eb07da | 2010-02-01 19:48:36 | [diff] [blame] | 30 | virtual bool Start(); |
| 31 | virtual void Stop(); |
| 32 | virtual bool Read(int bytes_to_read); |
| 33 | |
| 34 | // Special function needed by ActiveDocument::Load() |
[email protected] | 3ee6112 | 2010-04-14 00:35:52 | [diff] [blame] | 35 | HRESULT InitPending(const GURL& url, IMoniker* moniker, IBindCtx* bind_ctx, |
| 36 | bool enable_frame_busting, bool privileged_mode, |
[email protected] | 70277f6 | 2010-04-15 01:39:26 | [diff] [blame] | 37 | HWND notification_window, IStream* cache); |
[email protected] | 3eb07da | 2010-02-01 19:48:36 | [diff] [blame] | 38 | |
[email protected] | 7ae8074 | 2010-03-25 22:02:27 | [diff] [blame] | 39 | // Used from "DownloadRequestInHost". |
[email protected] | 5cec0eb3 | 2010-04-28 21:00:54 | [diff] [blame] | 40 | // Callback will be invoked either right away (if operation is finished) or |
| 41 | // from inside ::OnStopBinding() when it is safe to reuse the bind_context. |
| 42 | typedef Callback2<IMoniker*, IBindCtx*>::Type TerminateBindCallback; |
| 43 | void TerminateBind(TerminateBindCallback* callback); |
[email protected] | 3eb07da | 2010-02-01 19:48:36 | [diff] [blame] | 44 | |
| 45 | // Parent Window for UrlMon error dialogs |
| 46 | void set_parent_window(HWND parent_window) { |
| 47 | parent_window_ = parent_window; |
| 48 | } |
| 49 | |
[email protected] | 7403d38f | 2010-03-22 22:50:49 | [diff] [blame] | 50 | // This function passes information on whether ChromeFrame is running in |
| 51 | // privileged mode. |
| 52 | void set_privileged_mode(bool privileged_mode) { |
| 53 | privileged_mode_ = privileged_mode; |
| 54 | } |
| 55 | |
[email protected] | 1a5b2c242 | 2010-05-08 15:36:17 | [diff] [blame] | 56 | // Returns a string in the form " id: %i Obj: %X URL: %s" which is useful |
| 57 | // to identify request objects in the log. |
| 58 | std::string me() const; |
[email protected] | 3ee6112 | 2010-04-14 00:35:52 | [diff] [blame] | 59 | |
[email protected] | 3eb07da | 2010-02-01 19:48:36 | [diff] [blame] | 60 | protected: |
| 61 | UrlmonUrlRequest(); |
| 62 | ~UrlmonUrlRequest(); |
| 63 | |
| 64 | BEGIN_COM_MAP(UrlmonUrlRequest) |
| 65 | COM_INTERFACE_ENTRY(IHttpNegotiate) |
| 66 | COM_INTERFACE_ENTRY(IServiceProvider) |
| 67 | COM_INTERFACE_ENTRY(IBindStatusCallback) |
| 68 | COM_INTERFACE_ENTRY(IWindowForBindingUI) |
| 69 | COM_INTERFACE_ENTRY(IAuthenticate) |
| 70 | COM_INTERFACE_ENTRY(IHttpSecurity) |
| 71 | END_COM_MAP() |
| 72 | |
| 73 | BEGIN_SERVICE_MAP(UrlmonUrlRequest) |
| 74 | SERVICE_ENTRY(IID_IHttpNegotiate); |
| 75 | END_SERVICE_MAP() |
| 76 | |
[email protected] | 3eb07da | 2010-02-01 19:48:36 | [diff] [blame] | 77 | // IBindStatusCallback implementation |
| 78 | STDMETHOD(OnStartBinding)(DWORD reserved, IBinding* binding); |
| 79 | STDMETHOD(GetPriority)(LONG* priority); |
| 80 | STDMETHOD(OnLowResource)(DWORD reserved); |
| 81 | STDMETHOD(OnProgress)(ULONG progress, ULONG max_progress, |
[email protected] | 1a5b2c242 | 2010-05-08 15:36:17 | [diff] [blame] | 82 | ULONG status_code, LPCWSTR status_text); |
[email protected] | 3eb07da | 2010-02-01 19:48:36 | [diff] [blame] | 83 | STDMETHOD(OnStopBinding)(HRESULT result, LPCWSTR error); |
| 84 | STDMETHOD(GetBindInfo)(DWORD* bind_flags, BINDINFO* bind_info); |
| 85 | STDMETHOD(OnDataAvailable)(DWORD flags, DWORD size, FORMATETC* formatetc, |
[email protected] | 1a5b2c242 | 2010-05-08 15:36:17 | [diff] [blame] | 86 | STGMEDIUM* storage); |
[email protected] | 3eb07da | 2010-02-01 19:48:36 | [diff] [blame] | 87 | STDMETHOD(OnObjectAvailable)(REFIID iid, IUnknown* object); |
| 88 | |
| 89 | // IHttpNegotiate implementation |
| 90 | STDMETHOD(BeginningTransaction)(const wchar_t* url, |
[email protected] | 1a5b2c242 | 2010-05-08 15:36:17 | [diff] [blame] | 91 | const wchar_t* current_headers, DWORD reserved, |
| 92 | wchar_t** additional_headers); |
[email protected] | 3eb07da | 2010-02-01 19:48:36 | [diff] [blame] | 93 | STDMETHOD(OnResponse)(DWORD dwResponseCode, const wchar_t* response_headers, |
[email protected] | 1a5b2c242 | 2010-05-08 15:36:17 | [diff] [blame] | 94 | const wchar_t* request_headers, wchar_t** additional_headers); |
[email protected] | 3eb07da | 2010-02-01 19:48:36 | [diff] [blame] | 95 | |
| 96 | // IWindowForBindingUI implementation. This interface is used typically to |
| 97 | // query the window handle which URLMON uses as the parent of error dialogs. |
| 98 | STDMETHOD(GetWindow)(REFGUID guid_reason, HWND* parent_window); |
| 99 | |
| 100 | // IAuthenticate implementation. Used to return the parent window for the |
| 101 | // dialog displayed by IE for authenticating with a proxy. |
| 102 | STDMETHOD(Authenticate)(HWND* parent_window, LPWSTR* user_name, |
[email protected] | 1a5b2c242 | 2010-05-08 15:36:17 | [diff] [blame] | 103 | LPWSTR* password); |
[email protected] | 3eb07da | 2010-02-01 19:48:36 | [diff] [blame] | 104 | |
| 105 | // IHttpSecurity implementation. |
| 106 | STDMETHOD(OnSecurityProblem)(DWORD problem); |
| 107 | |
[email protected] | 70277f6 | 2010-04-15 01:39:26 | [diff] [blame] | 108 | void set_pending(bool pending) { |
| 109 | pending_ = pending; |
| 110 | } |
| 111 | |
| 112 | bool pending() const { |
| 113 | return pending_; |
| 114 | } |
| 115 | |
[email protected] | 5cec0eb3 | 2010-04-28 21:00:54 | [diff] [blame] | 116 | bool terminate_requested() const { |
| 117 | return terminate_bind_callback_.get() != NULL; |
| 118 | } |
| 119 | |
[email protected] | 70277f6 | 2010-04-15 01:39:26 | [diff] [blame] | 120 | std::string response_headers() { |
| 121 | return response_headers_; |
| 122 | } |
| 123 | |
[email protected] | 3eb07da | 2010-02-01 19:48:36 | [diff] [blame] | 124 | protected: |
| 125 | void ReleaseBindings(); |
| 126 | |
[email protected] | 3eb07da | 2010-02-01 19:48:36 | [diff] [blame] | 127 | HRESULT StartAsyncDownload(); |
| 128 | void NotifyDelegateAndDie(); |
[email protected] | 233469df | 2010-10-08 22:18:53 | [diff] [blame] | 129 | void TerminateTransaction(); |
[email protected] | 3eb07da | 2010-02-01 19:48:36 | [diff] [blame] | 130 | static net::Error HresultToNetError(HRESULT hr); |
| 131 | |
| 132 | private: |
[email protected] | 0ce4640 | 2010-04-08 16:53:57 | [diff] [blame] | 133 | size_t SendDataToDelegate(size_t bytes); |
[email protected] | 1a5b2c242 | 2010-05-08 15:36:17 | [diff] [blame] | 134 | |
[email protected] | 3eb07da | 2010-02-01 19:48:36 | [diff] [blame] | 135 | // This class simplifies tracking the progress of operation. We have 3 main |
| 136 | // states: DONE, WORKING and ABORTING. |
| 137 | // When in [DONE] or [ABORTING] state, there is additional information |
| 138 | // about the result of operation. |
| 139 | // Start(), SetRedirected(), Cancel() and Done() methods trigger the state |
| 140 | // change. See comments bellow. |
| 141 | class Status { |
| 142 | public: |
| 143 | enum State {DONE, ABORTING, WORKING}; |
| 144 | struct Redirection { |
| 145 | Redirection() : http_code(0) { } |
| 146 | int http_code; |
| 147 | std::string utf8_url; |
| 148 | }; |
| 149 | |
| 150 | Status() : state_(Status::DONE) { |
| 151 | } |
| 152 | |
| 153 | State get_state() const { |
| 154 | return state_; |
| 155 | } |
| 156 | |
| 157 | // Switch from [DONE] to [WORKING]. |
| 158 | void Start() { |
| 159 | DCHECK_EQ(state_, DONE); |
| 160 | state_ = WORKING; |
| 161 | } |
| 162 | |
| 163 | // Save redirection information and switch to [ABORTING] state. |
| 164 | // Assumes binding_->Abort() will be called! |
| 165 | void SetRedirected(int http_code, const std::string& utf8_url) { |
| 166 | DCHECK_EQ(state_, WORKING); |
[email protected] | 27a112c | 2011-01-06 04:19:30 | [diff] [blame^] | 167 | DCHECK_EQ(result_.status(), net::URLRequestStatus::SUCCESS); |
[email protected] | 3eb07da | 2010-02-01 19:48:36 | [diff] [blame] | 168 | redirect_.utf8_url = utf8_url; |
| 169 | |
| 170 | // At times we receive invalid redirect codes like 0, 200, etc. We |
| 171 | // default to 302 in this case. |
| 172 | redirect_.http_code = http_code; |
| 173 | if (!net::HttpResponseHeaders::IsRedirectResponseCode(http_code)) |
| 174 | redirect_.http_code = 302; |
| 175 | |
| 176 | state_ = ABORTING; |
| 177 | } |
| 178 | |
[email protected] | 27a112c | 2011-01-06 04:19:30 | [diff] [blame^] | 179 | // Set the result as net::URLRequestStatus::CANCELED. |
[email protected] | 3eb07da | 2010-02-01 19:48:36 | [diff] [blame] | 180 | // Switch to [ABORTING] state (if not already in that state). |
| 181 | void Cancel() { |
| 182 | if (state_ == DONE) |
| 183 | return; |
| 184 | |
| 185 | if (state_ == WORKING) { |
| 186 | state_ = ABORTING; |
| 187 | } else { |
| 188 | // state_ == ABORTING |
| 189 | redirect_.http_code = 0; |
| 190 | redirect_.utf8_url.clear(); |
| 191 | } |
| 192 | |
[email protected] | 27a112c | 2011-01-06 04:19:30 | [diff] [blame^] | 193 | set_result(net::URLRequestStatus::CANCELED, 0); |
[email protected] | 3eb07da | 2010-02-01 19:48:36 | [diff] [blame] | 194 | } |
| 195 | |
| 196 | void Done() { |
| 197 | state_ = DONE; |
| 198 | } |
| 199 | |
| 200 | bool was_redirected() const { |
| 201 | return redirect_.http_code != 0; |
| 202 | } |
| 203 | |
| 204 | const Redirection& get_redirection() const { |
| 205 | return redirect_; |
| 206 | } |
| 207 | |
[email protected] | 27a112c | 2011-01-06 04:19:30 | [diff] [blame^] | 208 | const net::URLRequestStatus& get_result() const { |
[email protected] | 3eb07da | 2010-02-01 19:48:36 | [diff] [blame] | 209 | return result_; |
| 210 | } |
| 211 | |
[email protected] | 27a112c | 2011-01-06 04:19:30 | [diff] [blame^] | 212 | void set_result(net::URLRequestStatus::Status status, int os_error) { |
[email protected] | 3eb07da | 2010-02-01 19:48:36 | [diff] [blame] | 213 | result_.set_status(status); |
| 214 | result_.set_os_error(os_error); |
| 215 | } |
| 216 | |
| 217 | void set_result(HRESULT hr) { |
[email protected] | 27a112c | 2011-01-06 04:19:30 | [diff] [blame^] | 218 | result_.set_status(FAILED(hr)? net::URLRequestStatus::FAILED: |
| 219 | net::URLRequestStatus::SUCCESS); |
[email protected] | 3eb07da | 2010-02-01 19:48:36 | [diff] [blame] | 220 | result_.set_os_error(HresultToNetError(hr)); |
| 221 | } |
| 222 | |
| 223 | private: |
| 224 | Redirection redirect_; |
| 225 | State state_; |
[email protected] | 27a112c | 2011-01-06 04:19:30 | [diff] [blame^] | 226 | net::URLRequestStatus result_; |
[email protected] | 3eb07da | 2010-02-01 19:48:36 | [diff] [blame] | 227 | }; |
| 228 | |
| 229 | Status status_; |
| 230 | ScopedComPtr<IBinding> binding_; |
| 231 | ScopedComPtr<IMoniker> moniker_; |
| 232 | ScopedComPtr<IBindCtx> bind_context_; |
[email protected] | 1a5b2c242 | 2010-05-08 15:36:17 | [diff] [blame] | 233 | ScopedComPtr<IStream> cache_; |
| 234 | ScopedComPtr<IStream> pending_data_; |
| 235 | |
[email protected] | 3eb07da | 2010-02-01 19:48:36 | [diff] [blame] | 236 | size_t pending_read_size_; |
[email protected] | ce072a7 | 2010-12-31 20:02:16 | [diff] [blame] | 237 | base::PlatformThreadId thread_; |
[email protected] | 3eb07da | 2010-02-01 19:48:36 | [diff] [blame] | 238 | HWND parent_window_; |
[email protected] | 290c537 | 2010-02-12 17:02:09 | [diff] [blame] | 239 | bool headers_received_; |
[email protected] | 0ce4640 | 2010-04-08 16:53:57 | [diff] [blame] | 240 | int calling_delegate_; // re-entrancy protection. |
[email protected] | 7403d38f | 2010-03-22 22:50:49 | [diff] [blame] | 241 | // Set to true if the ChromeFrame instance is running in privileged mode. |
| 242 | bool privileged_mode_; |
[email protected] | 70277f6 | 2010-04-15 01:39:26 | [diff] [blame] | 243 | bool pending_; |
[email protected] | 5cec0eb3 | 2010-04-28 21:00:54 | [diff] [blame] | 244 | scoped_ptr<TerminateBindCallback> terminate_bind_callback_; |
[email protected] | 70277f6 | 2010-04-15 01:39:26 | [diff] [blame] | 245 | std::string response_headers_; |
[email protected] | 233469df | 2010-10-08 22:18:53 | [diff] [blame] | 246 | // Defaults to true and indicates whether we want to keep the original |
| 247 | // transaction alive when we receive the last data notification from |
| 248 | // urlmon. |
| 249 | bool is_expecting_download_; |
| 250 | // Set to true if the Urlmon transaction object needs to be cleaned up |
| 251 | // when this object is destroyed. Happens if we return |
| 252 | // INET_E_TERMINATE_BIND from OnDataAvailable in the last data notification. |
| 253 | bool cleanup_transaction_; |
| 254 | |
[email protected] | 3eb07da | 2010-02-01 19:48:36 | [diff] [blame] | 255 | DISALLOW_COPY_AND_ASSIGN(UrlmonUrlRequest); |
| 256 | }; |
| 257 | |
| 258 | #endif // CHROME_FRAME_URLMON_URL_REQUEST_PRIVATE_H_ |