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