|
| 1 | +# Background |
| 2 | +The WebView2 team has been asked for an API to get the response for a web |
| 3 | +resource as it was received and to provide request headers not available when |
| 4 | +`WebResourceRequested` event fires (such as Authentication headers). The |
| 5 | +`WebResourceResponseReceived` event provides such HTTP response representation |
| 6 | +and exposes the request as sent over the wire. |
| 7 | + |
| 8 | +In this document we describe the new API. We'd appreciate your feedback. |
| 9 | + |
| 10 | +# Description |
| 11 | +The `WebResourceResponseReceived` event fires when the WebView receives the |
| 12 | +response for a request for a web resource. It provides access to both the |
| 13 | +response as it was received and the request as it was sent over the wire, |
| 14 | +including modifications made by the network stack (such as adding of |
| 15 | +Authorization headers). The app can use this event to view the actual request |
| 16 | +and response for a web resource, but modifications made to these objects are |
| 17 | +ignored. |
| 18 | + |
| 19 | +The host app registers for this event by providing a |
| 20 | +`WebResourceResponseReceivedEventHandler` (or delegate) to WebView's |
| 21 | +`add_WebResourceResponseReceived`/`WebResourceResponseReceived`. When invoking |
| 22 | +the handler, the WebView will pass a `WebResourceResponseReceivedEventArgs`, |
| 23 | +which lets the app view the request and response. The additional |
| 24 | +`PopulateResponseContent` API is exposed from the event arguments so the app |
| 25 | +can get the response's body (if it has one). |
| 26 | + |
| 27 | +# Examples |
| 28 | +The following code snippets demonstrates how the `WebResourceResponseReceived` |
| 29 | +event can be used: |
| 30 | + |
| 31 | +## COM |
| 32 | +```cpp |
| 33 | +EventRegistrationToken m_webResourceResponseReceivedToken = {}; |
| 34 | + |
| 35 | +m_webview->add_WebResourceResponseReceived( |
| 36 | + Callback<ICoreWebView2WebResourceResponseReceivedEventHandler>( |
| 37 | + [this](ICoreWebView2* webview, ICoreWebView2WebResourceResponseReceivedEventArgs* args) |
| 38 | + -> HRESULT { |
| 39 | + // The request object as sent by the wire |
| 40 | + wil::com_ptr<ICoreWebView2WebResourceRequest> webResourceRequest; |
| 41 | + CHECK_FAILURE(args->get_Request(&webResourceRequest)); |
| 42 | + // The response object as received |
| 43 | + wil::com_ptr<ICoreWebView2WebResourceResponse> webResourceResponse; |
| 44 | + CHECK_FAILURE(args->get_Response(&webResourceResponse)); |
| 45 | + |
| 46 | + // Get body content for the response. Redirect responses will |
| 47 | + // return an error HRESULT as their body (if any) is ignored. |
| 48 | + HRESULT populateCallResult = args->PopulateResponseContent( |
| 49 | + Callback< |
| 50 | + ICoreWebView2WebResourceResponseReceivedEventArgsPopulateResponseContentCompletedHandler>( |
| 51 | + [this, webResourceRequest, webResourceResponse](HRESULT result) { |
| 52 | + // The response might not have a body. |
| 53 | + bool populatedBody = SUCCEEDED(result); |
| 54 | + |
| 55 | + std::wstring message = |
| 56 | + L"{ \"kind\": \"event\", \"name\": " |
| 57 | + L"\"WebResourceResponseReceived\", \"args\": {" |
| 58 | + L"\"request\": " + |
| 59 | + RequestToJsonString(webResourceRequest.get()) + |
| 60 | + L", " |
| 61 | + L"\"response\": " + |
| 62 | + ResponseToJsonString(webResourceResponse.get()) + L"}"; |
| 63 | + |
| 64 | + message += |
| 65 | + WebViewPropertiesToJsonString(m_webview.get()); |
| 66 | + message += L"}"; |
| 67 | + PostEventMessage(message); |
| 68 | + return S_OK; |
| 69 | + }) |
| 70 | + .Get()); |
| 71 | + |
| 72 | + return S_OK; |
| 73 | + }) |
| 74 | + .Get(), |
| 75 | + &m_webResourceResponseReceivedToken); |
| 76 | +``` |
| 77 | +
|
| 78 | +## C# |
| 79 | +```c# |
| 80 | +WebView.WebResourceResponseReceived += WebView_WebResourceResponseReceived; |
| 81 | +
|
| 82 | +// Note: modifications made to request and response are ignored |
| 83 | +private async void WebView_WebResourceResponseReceived(object sender, CoreWebView2WebResourceResponseReceivedEventArgs e) |
| 84 | +{ |
| 85 | + // Actual headers sent with request |
| 86 | + foreach (var current in e.Request.Headers) |
| 87 | + Console.WriteLine(current); |
| 88 | +
|
| 89 | + // Headers in response received |
| 90 | + foreach (var current in e.Response.Headers) |
| 91 | + Console.WriteLine(current); |
| 92 | +
|
| 93 | + // Status code from response received |
| 94 | + int status = e.Response.StatusCode; |
| 95 | + if (status == 200) |
| 96 | + { |
| 97 | + // Handle |
| 98 | + Console.WriteLine("Request succeeded!"); |
| 99 | +
|
| 100 | + // Get response body |
| 101 | + try |
| 102 | + { |
| 103 | + await e.PopulateResponseContentAsync(); |
| 104 | + DoSomethingWithResponseBody(e.Response.Content); |
| 105 | + } catch (Exception ex) |
| 106 | + { |
| 107 | + // An exception will be thrown if the request has no body. |
| 108 | + } |
| 109 | + } |
| 110 | +} |
| 111 | +``` |
| 112 | + |
| 113 | + |
| 114 | +# Remarks |
| 115 | +Calling `PopulateResponseContent` will fail/throw an exception if the response |
| 116 | +has no body. An exception will also be thrown for redirect responses, for which |
| 117 | +the body (if any) is ignored. |
| 118 | + |
| 119 | + |
| 120 | +# API Notes |
| 121 | +See [API Details](#api-details) section below for API reference. |
| 122 | + |
| 123 | + |
| 124 | +# API Details |
| 125 | +## COM |
| 126 | +```cpp |
| 127 | +library WebView2 |
| 128 | +{ |
| 129 | + interface ICoreWebView2 : IUnknown |
| 130 | + { |
| 131 | + // ... |
| 132 | + |
| 133 | + /// Add an event handler for the WebResourceResponseReceived event. |
| 134 | + /// WebResourceResponseReceived event fires after the WebView has received |
| 135 | + /// and processed the response for a WebResource request. The event args |
| 136 | + /// include the WebResourceRequest as sent by the wire and WebResourceResponse |
| 137 | + /// received, including any additional headers added by the network stack that |
| 138 | + /// were not be included as part of the associated WebResourceRequested event, |
| 139 | + /// such as Authentication headers. |
| 140 | + HRESULT add_WebResourceResponseReceived( |
| 141 | + [in] ICoreWebView2WebResourceResponseReceivedEventHandler* eventHandler, |
| 142 | + [out] EventRegistrationToken* token); |
| 143 | + /// Removes the WebResourceResponseReceived event handler previously added |
| 144 | + /// with add_WebResourceResponseReceived |
| 145 | + HRESULT remove_WebResourceResponseReceived( |
| 146 | + [in] EventRegistrationToken token); |
| 147 | + } |
| 148 | + |
| 149 | + /// Fires when a response for a request is received for a Web resource in the webview. |
| 150 | + /// Host can use this event to view the actual request and response for a Web resource. |
| 151 | + /// This includes any request or response modifications made by the network stack (such as |
| 152 | + /// adding of Authorization headers) after the WebResourceRequested event for |
| 153 | + /// the associated request has fired. Modifications made to the request or response |
| 154 | + /// objects are ignored. |
| 155 | + interface ICoreWebView2WebResourceResponseReceivedEventHandler : IUnknown |
| 156 | + { |
| 157 | + /// Called to provide the implementer with the event args for the |
| 158 | + /// corresponding event. |
| 159 | + HRESULT Invoke( |
| 160 | + [in] ICoreWebView2* sender, |
| 161 | + [in] ICoreWebView2WebResourceResponseReceivedEventArgs* args); |
| 162 | + } |
| 163 | + |
| 164 | + /// Completion handler for PopulateResponseContent async method. It's invoked |
| 165 | + /// when the Content stream of the Response of a WebResourceResponseReceieved |
| 166 | + /// event is available. |
| 167 | + interface ICoreWebView2WebResourceResponseReceivedEventArgsPopulateResponseContentCompletedHandler : IUnknown |
| 168 | + { |
| 169 | + /// Called to provide the implementer with the completion status |
| 170 | + /// of the corresponding asynchronous method call. |
| 171 | + HRESULT Invoke([in] HRESULT errorCode); |
| 172 | + } |
| 173 | + |
| 174 | + /// Event args for the WebResourceResponseReceived event. Will contain the |
| 175 | + /// request as it was sent and the response as it was received. |
| 176 | + /// Note: To get the response content stream, first call PopulateResponseContent |
| 177 | + /// and wait for the async call to complete, otherwise the content stream object |
| 178 | + /// returned will be null. |
| 179 | + interface ICoreWebView2WebResourceResponseReceivedEventArgs : IUnknown |
| 180 | + { |
| 181 | + /// Web resource request object. Any modifications to this object will be ignored. |
| 182 | + [propget] HRESULT Request([out, retval] ICoreWebView2WebResourceRequest** request); |
| 183 | + /// Web resource response object. Any modifications to this object |
| 184 | + /// will be ignored. |
| 185 | + [propget] HRESULT Response([out, retval] ICoreWebView2WebResourceResponse** response); |
| 186 | + |
| 187 | + /// Async method to request the Content stream of the response. |
| 188 | + HRESULT PopulateResponseContent(ICoreWebView2WebResourceResponseReceivedEventArgsPopulateResponseContentCompletedHandler* handler); |
| 189 | + } |
| 190 | +} |
| 191 | +``` |
| 192 | + |
| 193 | +## WinRT |
| 194 | +```c# |
| 195 | +namespace Microsoft.Web.WebView2.Core |
| 196 | +{ |
| 197 | + runtimeclass CoreWebView2 |
| 198 | + { |
| 199 | + // ... |
| 200 | +
|
| 201 | + /// WebResourceResponseReceived event fires after the WebView has received and processed the response for a WebResource request. |
| 202 | + event Windows.Foundation.TypedEventHandler<CoreWebView2, CoreWebView2WebResourceResponseReceivedEventArgs> WebResourceResponseReceived; |
| 203 | + } |
| 204 | + |
| 205 | + /// Event args for the WebResourceResponseReceived event. |
| 206 | + runtimeclass CoreWebView2WebResourceResponseReceivedEventArgs |
| 207 | + { |
| 208 | + /// Web resource request object. |
| 209 | + /// Any modifications to this object will be ignored. |
| 210 | + CoreWebView2WebResourceRequest Request { get; }; |
| 211 | + /// Web resource response object. |
| 212 | + /// Any modifications to this object will be ignored. |
| 213 | + CoreWebView2WebResourceResponse Response { get; }; |
| 214 | + |
| 215 | + /// Async method to request the Content stream of the response. |
| 216 | + Windows.Foundation.IAsyncAction PopulateResponseContentAsync(); |
| 217 | + } |
| 218 | +} |
| 219 | +``` |
0 commit comments