Skip to content

Commit 718ab38

Browse files
authored
Merge pull request #481 from MicrosoftEdge/api-webresourceresponsereceived
WebResourceResponseReceived API Review
2 parents 4a0c576 + ae494c1 commit 718ab38

File tree

1 file changed

+296
-0
lines changed

1 file changed

+296
-0
lines changed

specs/WebResourceResponseReceived.md

Lines changed: 296 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,296 @@
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 is raised (such as HTTP Authentication headers).
5+
The `WebResourceResponseReceived` event provides such response representation
6+
and exposes the request as committed. A web request is any URI resolution the
7+
WebView performs. This includes declarative `<img src="...">` from HTML,
8+
implicit `favicon.ico` lookups, and JavaScript in the document calling the
9+
`fetch(...)` API.
10+
11+
In this document we describe the new API. We'd appreciate your feedback.
12+
13+
# Description
14+
The `WebResourceResponseReceived` event allows developers to inspect the
15+
response object from URL requests (such as HTTP/HTTPS, file and data). A key
16+
scenario is to allow developers to get Auth headers from an HTTP response to
17+
authenticate other tools they're using, since the Auth headers are not exposed
18+
in the `WebResourceRequested` event.
19+
20+
This event is raised when the WebView receives the response for a request for a
21+
web resource. It provides access to both the response as it was received and the
22+
request as it was committed, including modifications made by the network stack
23+
(such as the adding of HTTP Authorization headers). The app can use this event
24+
to view the actual request and response for a web resource. Modifications to the
25+
request object are set but have no effect on WebView processing it. There is no
26+
ordering guarantee between WebView processing the response and the host app's
27+
event handler running.
28+
29+
When the event is raised, the WebView will pass a
30+
`WebResourceResponseReceivedEventArgs`, which lets the app view the request and
31+
response. To get the response content, call `GetContent`/`GetContentAsync` on
32+
the `CoreWebView2WebResourceResponseView` object from the event args.
33+
34+
# Examples
35+
The following code snippets demonstrate how the `WebResourceResponseReceived`
36+
event can be used:
37+
38+
## COM
39+
```cpp
40+
EventRegistrationToken m_webResourceResponseReceivedToken = {};
41+
42+
m_webview->add_WebResourceResponseReceived(
43+
Callback<ICoreWebView2WebResourceResponseReceivedEventHandler>(
44+
[this](ICoreWebView2* webview, ICoreWebView2WebResourceResponseReceivedEventArgs* args)
45+
-> HRESULT {
46+
// The request object as committed
47+
wil::com_ptr<ICoreWebView2WebResourceRequest> webResourceRequest;
48+
CHECK_FAILURE(args->get_Request(&webResourceRequest));
49+
// The response object as received
50+
wil::com_ptr<ICoreWebView2WebResourceResponseView> webResourceResponse;
51+
CHECK_FAILURE(args->get_Response(&webResourceResponse));
52+
53+
// Get body content for the response
54+
webResourceResponse->GetContent(
55+
Callback<
56+
ICoreWebView2WebResourceResponseViewGetContentCompletedHandler>(
57+
[this, webResourceRequest, webResourceResponse](HRESULT result, IStream* content) {
58+
// The response content might have failed to load.
59+
bool getContentSucceeded = SUCCEEDED(result);
60+
61+
// The stream will be null if no content was found for the response.
62+
if (content) {
63+
DoSomethingWithContent(content);
64+
}
65+
66+
std::wstring message =
67+
L"{ \"kind\": \"event\", \"name\": "
68+
L"\"WebResourceResponseReceived\", \"args\": {"
69+
L"\"request\": " +
70+
RequestToJsonString(webResourceRequest.get()) +
71+
L", "
72+
L"\"response\": " +
73+
ResponseToJsonString(webResourceResponse.get(), content) + L"}";
74+
75+
message +=
76+
WebViewPropertiesToJsonString(m_webview.get());
77+
message += L"}";
78+
PostEventMessage(message);
79+
return S_OK;
80+
})
81+
.Get());
82+
83+
return S_OK;
84+
})
85+
.Get(),
86+
&m_webResourceResponseReceivedToken);
87+
```
88+
89+
## C#
90+
```c#
91+
WebView.WebResourceResponseReceived += WebView_WebResourceResponseReceived;
92+
93+
// Note: modifications made to request are set but have no effect on WebView processing it.
94+
private async void WebView_WebResourceResponseReceived(CoreWebView2 sender, CoreWebView2WebResourceResponseReceivedEventArgs e)
95+
{
96+
// Actual headers sent with request
97+
foreach (var current in e.Request.Headers)
98+
{
99+
Console.WriteLine(current);
100+
}
101+
102+
// Headers in response received
103+
foreach (var current in e.Response.Headers)
104+
{
105+
Console.WriteLine(current);
106+
}
107+
108+
// Status code from response received
109+
int status = e.Response.StatusCode;
110+
if (status == 200)
111+
{
112+
// Handle
113+
Console.WriteLine("Request succeeded!");
114+
115+
// Get response body
116+
try
117+
{
118+
System.IO.Stream content = await e.Response.GetContentAsync();
119+
// Null will be returned if no content was found for the response.
120+
if (content)
121+
{
122+
DoSomethingWithResponseContent(content);
123+
}
124+
}
125+
catch (COMException ex)
126+
{
127+
// A COMException will be thrown if the content failed to load.
128+
}
129+
}
130+
}
131+
```
132+
133+
134+
# Remarks
135+
`ICoreWebView2WebResourceResponseViewGetContentCompletedHandler` will be
136+
invoked with a failure errorCode if the content failed to load.
137+
Calling `CoreWebView2WebResourceResponseView.GetContentAsync` will throw a
138+
`COMException` if the content failed to load.
139+
140+
141+
# API Notes
142+
See [API Details](#api-details) section below for API reference.
143+
144+
145+
# API Details
146+
## COM
147+
```cpp
148+
library WebView2
149+
{
150+
// ...
151+
152+
interface ICoreWebView2 : IUnknown
153+
{
154+
// ...
155+
156+
/// Add an event handler for the WebResourceResponseReceived event.
157+
/// WebResourceResponseReceived is raised when the WebView receives the
158+
/// response for a request for a web resource (any URI resolution performed by
159+
/// the WebView; such as HTTP/HTTPS, file and data requests from redirects,
160+
/// navigations, declarations in HTML, implicit favicon lookups, and fetch API
161+
/// usage in the document). The host app can use this event to view the actual
162+
/// request and response for a web resource. There is no guarantee about the
163+
/// order in which the WebView processes the response and the host app's
164+
/// handler runs. The app's handler will not block the WebView from processing
165+
/// the response.
166+
HRESULT add_WebResourceResponseReceived(
167+
[in] ICoreWebView2WebResourceResponseReceivedEventHandler* eventHandler,
168+
[out] EventRegistrationToken* token);
169+
/// Remove an event handler previously added with
170+
/// add_WebResourceResponseReceived.
171+
HRESULT remove_WebResourceResponseReceived(
172+
[in] EventRegistrationToken token);
173+
}
174+
175+
/// The caller implements this interface to receive WebResourceResponseReceived
176+
/// events.
177+
interface ICoreWebView2WebResourceResponseReceivedEventHandler : IUnknown
178+
{
179+
/// Called to provide the implementer with the event args for the
180+
/// corresponding event.
181+
HRESULT Invoke(
182+
[in] ICoreWebView2* sender,
183+
[in] ICoreWebView2WebResourceResponseReceivedEventArgs* args);
184+
}
185+
186+
/// Event args for the WebResourceResponseReceived event.
187+
interface ICoreWebView2WebResourceResponseReceivedEventArgs : IUnknown
188+
{
189+
/// The request object for the web resource, as committed. This includes
190+
/// headers added by the network stack that were not be included during the
191+
/// associated WebResourceRequested event, such as Authentication headers.
192+
/// Modifications to this object have no effect on how the request is
193+
/// processed as it has already been sent.
194+
[propget] HRESULT Request(
195+
[out, retval] ICoreWebView2WebResourceRequest** request);
196+
/// View of the response object received for the web resource.
197+
[propget] HRESULT Response(
198+
[out, retval] ICoreWebView2WebResourceResponseView** response);
199+
}
200+
201+
/// View of the HTTP representation for a web resource response. The properties
202+
/// of this object are not mutable. This response view is used with the
203+
/// WebResourceResponseReceived event.
204+
interface ICoreWebView2WebResourceResponseView : IUnknown
205+
{
206+
/// The HTTP response headers as received.
207+
[propget] HRESULT Headers(
208+
[out, retval] ICoreWebView2HttpResponseHeaders** headers);
209+
/// The HTTP response status code.
210+
[propget] HRESULT StatusCode([out, retval] int* statusCode);
211+
/// The HTTP response reason phrase.
212+
[propget] HRESULT ReasonPhrase([out, retval] LPWSTR* reasonPhrase);
213+
214+
/// Get the response content asynchronously. The handler will receive the
215+
/// response content stream.
216+
/// If this method is being called again before a first call has completed,
217+
/// the handler will be invoked at the same time the handlers from prior calls
218+
/// are invoked.
219+
/// If this method is being called after a first call has completed, the
220+
/// handler will be invoked immediately.
221+
HRESULT GetContent(
222+
[in] ICoreWebView2WebResourceResponseViewGetContentCompletedHandler* handler);
223+
}
224+
225+
/// The caller implements this interface to receive the result of the
226+
/// ICoreWebView2WebResourceResponseView::GetContent method.
227+
interface ICoreWebView2WebResourceResponseViewGetContentCompletedHandler : IUnknown
228+
{
229+
/// Called to provide the implementer with the completion status and result of
230+
/// the corresponding asynchronous method call. A failure errorCode will be
231+
/// passed if the content failed to load. Null means no content was found.
232+
/// Note content (if any) for redirect responses is ignored.
233+
HRESULT Invoke([in] HRESULT errorCode, [in] IStream* content);
234+
}
235+
236+
}
237+
```
238+
239+
## WinRT
240+
```c#
241+
namespace Microsoft.Web.WebView2.Core
242+
{
243+
// ...
244+
245+
runtimeclass CoreWebView2
246+
{
247+
// ...
248+
249+
/// WebResourceResponseReceived is raised when the WebView receives the
250+
/// response for a request for a web resource (any URI resolution performed by
251+
/// the WebView; such as HTTP/HTTPS, file and data requests from redirects,
252+
/// navigations, declarations in HTML, implicit favicon lookups, and fetch API
253+
/// usage in the document). The host app can use this event to view the actual
254+
/// request and response for a web resource. There is no guarantee about the
255+
/// order in which the WebView processes the response and the host app's
256+
/// handler runs. The app's handler will not block the WebView from processing
257+
/// the response.
258+
event Windows.Foundation.TypedEventHandler<CoreWebView2, CoreWebView2WebResourceResponseReceivedEventArgs> WebResourceResponseReceived;
259+
}
260+
261+
/// Event args for the WebResourceResponseReceived event.
262+
runtimeclass CoreWebView2WebResourceResponseReceivedEventArgs
263+
{
264+
/// The request object for the web resource, as committed. This includes
265+
/// headers added by the network stack that were not be included during the
266+
/// associated WebResourceRequested event, such as Authentication headers.
267+
/// Modifications to this object have no effect on how the request is
268+
/// processed as it has already been sent.
269+
CoreWebView2WebResourceRequest Request { get; };
270+
/// View of the response object received for the web resource.
271+
CoreWebView2WebResourceResponseView Response { get; };
272+
}
273+
274+
/// View of the HTTP representation for a web resource response. The properties
275+
/// of this object are not mutable. This response view is used with the
276+
/// WebResourceResponseReceived event.
277+
runtimeclass CoreWebView2WebResourceResponseView
278+
{
279+
/// The HTTP response headers as received.
280+
CoreWebView2HttpResponseHeaders Headers { get; };
281+
/// The HTTP response status code.
282+
Int32 StatusCode { get; };
283+
/// The HTTP response reason phrase.
284+
String ReasonPhrase { get; };
285+
/// Get the response content stream asynchronously.
286+
/// This method will throw a COM exception if the content failed to load.
287+
/// A null stream means no content was found. Note content (if any) for
288+
/// redirect responses is ignored.
289+
/// If this method is being called again before a first call has completed,
290+
/// it will complete at the same time all prior calls do.
291+
/// If this method is being called after a first call has completed, it will
292+
/// return immediately (asynchronously).
293+
Windows.Foundation.IAsyncOperation<Windows.Storage.Streams.IRandomAccessStream> GetContentAsync();
294+
}
295+
}
296+
```

0 commit comments

Comments
 (0)