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