Bug 238159 - [Cocoa] Ensure correct isAppInitiated state when creating URLRequests from URL
Summary: [Cocoa] Ensure correct isAppInitiated state when creating URLRequests from URL
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebKit Misc. (show other bugs)
Version: WebKit Local Build
Hardware: Unspecified Unspecified
: P2 Normal
Assignee: Brent Fulgham
URL:
Keywords: InRadar
Depends on: 236111 236167
Blocks:
  Show dependency treegraph
 
Reported: 2022-03-21 15:53 PDT by Brent Fulgham
Modified: 2022-03-31 09:19 PDT (History)
7 users (show)

See Also:


Attachments
Patch (11.89 KB, patch)
2022-03-21 16:24 PDT, Brent Fulgham
no flags Details | Formatted Diff | Diff
Patch (4.81 KB, patch)
2022-03-24 10:52 PDT, Brent Fulgham
no flags Details | Formatted Diff | Diff
Patch (5.81 KB, patch)
2022-03-29 14:29 PDT, Brent Fulgham
no flags Details | Formatted Diff | Diff
Patch (5.85 KB, patch)
2022-03-30 10:37 PDT, Brent Fulgham
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Brent Fulgham 2022-03-21 15:53:34 PDT
This patch follows on the work from Bug 236167. It corrects a few more load paths are getting incorrect state for 'isAppInitiated'.
Comment 1 Brent Fulgham 2022-03-21 15:53:49 PDT
<rdar://problem/88490742>
Comment 2 Brent Fulgham 2022-03-21 16:24:45 PDT
Created attachment 455296 [details]
Patch
Comment 3 Kate Cheney 2022-03-21 16:37:56 PDT
Comment on attachment 455296 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=455296&action=review

Have you seen these code paths be hit with incorrect app initiated values? For all of the NavigationScheduler functions we eventually call frame.changeLocation() which will set the app initiated value on the request in FrameLoader::updateRequestAndAddExtraFields based on the main frame document loader's value. Ditto for FrameLoader::loadFrameRequest() in the contextMenuItem case.

> Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp:831
> +    preconnectTo(WTFMove(resourceRequest), *webPage, webFrame, storedCredentialsPolicy, shouldPreconnectAsFirstParty, WTFMove(completionHandler));

I think we already do this, see the preconnectTo function below.
Comment 4 Brent Fulgham 2022-03-22 11:11:17 PDT
Comment on attachment 455296 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=455296&action=review

>> Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp:831
>> +    preconnectTo(WTFMove(resourceRequest), *webPage, webFrame, storedCredentialsPolicy, shouldPreconnectAsFirstParty, WTFMove(completionHandler));
> 
> I think we already do this, see the preconnectTo function below.

You are right -- this isn't needed.
Comment 5 Brent Fulgham 2022-03-22 11:13:56 PDT
(In reply to Kate Cheney from comment #3)
> Comment on attachment 455296 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=455296&action=review
> 
> Have you seen these code paths be hit with incorrect app initiated values?
> For all of the NavigationScheduler functions we eventually call
> frame.changeLocation() which will set the app initiated value on the request
> in FrameLoader::updateRequestAndAddExtraFields based on the main frame
> document loader's value. Ditto for FrameLoader::loadFrameRequest() in the
> contextMenuItem case.

Ah, okay. I can remove those.

> 
> > Source/WebKit/WebProcess/Network/WebLoaderStrategy.cpp:831
> > +    preconnectTo(WTFMove(resourceRequest), *webPage, webFrame, storedCredentialsPolicy, shouldPreconnectAsFirstParty, WTFMove(completionHandler));
> 
> I think we already do this, see the preconnectTo function below.

I'm suspicious of this code path because the hits we've been getting seem to be related to code like this:

<link rel="preconnect" href="https://something.example.com">
Comment 6 Brent Fulgham 2022-03-22 11:58:50 PDT
(In reply to Kate Cheney from comment #3)
> Comment on attachment 455296 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=455296&action=review
> 
> Have you seen these code paths be hit with incorrect app initiated values?
> For all of the NavigationScheduler functions we eventually call
> frame.changeLocation() which will set the app initiated value on the request
> in FrameLoader::updateRequestAndAddExtraFields based on the main frame
> document loader's value. Ditto for FrameLoader::loadFrameRequest() in the
> contextMenuItem case.
> 

I believe that NavigationScheduler does have one case that uses:

    frame.loader().load(WTFMove(frameLoadRequest));

It looks like FrameLoader::load(FrameLoadRequest&& request) can bypass 'updateRequestAndAddExtraFields' in the case where request.shouldCheckNewWindowPolicy() is true, which I think can get through the load without setting AppInitiated state.
Comment 7 Brent Fulgham 2022-03-24 10:52:00 PDT
Created attachment 455653 [details]
Patch
Comment 8 Kate Cheney 2022-03-24 11:00:14 PDT
(In reply to Brent Fulgham from comment #6)
> (In reply to Kate Cheney from comment #3)
> > Comment on attachment 455296 [details]
> > Patch
> > 
> > View in context:
> > https://bugs.webkit.org/attachment.cgi?id=455296&action=review
> > 
> > Have you seen these code paths be hit with incorrect app initiated values?
> > For all of the NavigationScheduler functions we eventually call
> > frame.changeLocation() which will set the app initiated value on the request
> > in FrameLoader::updateRequestAndAddExtraFields based on the main frame
> > document loader's value. Ditto for FrameLoader::loadFrameRequest() in the
> > contextMenuItem case.
> > 
> 
> I believe that NavigationScheduler does have one case that uses:
> 
>     frame.loader().load(WTFMove(frameLoadRequest));
> 
> It looks like FrameLoader::load(FrameLoadRequest&& request) can bypass
> 'updateRequestAndAddExtraFields' in the case where
> request.shouldCheckNewWindowPolicy() is true, which I think can get through
> the load without setting AppInitiated state.

Oh, good catch.

Weird about the <link> preconnect case causing issues. Does it repro in a reduced test case?
Comment 9 Kate Cheney 2022-03-24 11:03:41 PDT
Comment on attachment 455653 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=455653&action=review

> Source/WebCore/loader/ThreadableLoader.cpp:117
> +    if (auto* documentLoader = document ? document->loader() : nullptr)

Was this a place you were catching errors? A test case would be nice. Or if it is speculative maybe we should add this to WorkerThreadableLoader as well?
Comment 10 Brent Fulgham 2022-03-24 16:05:31 PDT
(In reply to Kate Cheney from comment #8)
> (In reply to Brent Fulgham from comment #6)
> > (In reply to Kate Cheney from comment #3)
> > > Comment on attachment 455296 [details]
> > > Patch
> > > 
> > > View in context:
> > > https://bugs.webkit.org/attachment.cgi?id=455296&action=review
> > > 
> > > Have you seen these code paths be hit with incorrect app initiated values?
> > > For all of the NavigationScheduler functions we eventually call
> > > frame.changeLocation() which will set the app initiated value on the request
> > > in FrameLoader::updateRequestAndAddExtraFields based on the main frame
> > > document loader's value. Ditto for FrameLoader::loadFrameRequest() in the
> > > contextMenuItem case.
> > > 
> > 
> > I believe that NavigationScheduler does have one case that uses:
> > 
> >     frame.loader().load(WTFMove(frameLoadRequest));
> > 
> > It looks like FrameLoader::load(FrameLoadRequest&& request) can bypass
> > 'updateRequestAndAddExtraFields' in the case where
> > request.shouldCheckNewWindowPolicy() is true, which I think can get through
> > the load without setting AppInitiated state.
> 
> Oh, good catch.
> 
> Weird about the <link> preconnect case causing issues. Does it repro in a
> reduced test case?

I need to try to build one. I've been testing with an iOS Simulator build, and I can't get those two cases to trigger a mismatch, so perhaps something else is going on.

Another possibility is that the Cache loader doesn't handle AppInitiated state, and so the first load that goes to Cache gets flagged as App-Initiated?
Comment 11 Brent Fulgham 2022-03-24 16:07:24 PDT
Comment on attachment 455653 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=455653&action=review

>> Source/WebCore/loader/ThreadableLoader.cpp:117
>> +    if (auto* documentLoader = document ? document->loader() : nullptr)
> 
> Was this a place you were catching errors? A test case would be nice. Or if it is speculative maybe we should add this to WorkerThreadableLoader as well?

Yes, this was a case that I encountered mismatches, but I'm not sure if lower-level loading code might correct it. At a minimum, I should probably move this above the WorkerThreadableLoader::create so that if the context has a document we can properly reflect it's AppInitiated state.
Comment 12 Brent Fulgham 2022-03-29 14:29:13 PDT
Created attachment 456058 [details]
Patch
Comment 13 Brent Fulgham 2022-03-30 10:37:11 PDT
Created attachment 456144 [details]
Patch
Comment 14 Kate Cheney 2022-03-30 11:38:47 PDT
Comment on attachment 456144 [details]
Patch

r=me
Comment 15 Darin Adler 2022-03-30 20:33:26 PDT
Comment on attachment 456144 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=456144&action=review

> Source/WebCore/loader/NavigationScheduler.cpp:385
> +        if (auto* documentLoader = m_originDocument.loader())
> +            resourceRequest.setIsAppInitiated(documentLoader->lastNavigationWasAppInitiated());

Is it really OK to leave this set to the default if there is no document loader associated? Does that mean it gets set to true or false? Which is the correct value for that case?

> Source/WebCore/loader/ThreadableLoader.cpp:115
> +    if (auto* documentLoader = document ? document->loader() : nullptr)
> +        request.setIsAppInitiated(documentLoader->lastNavigationWasAppInitiated());

Is it really OK to leave this set to the default if there is no document loader associated? Does that mean it gets set to true or false? Which is the correct value for that case?

> Source/WebCore/page/DragController.cpp:298
> +    resourceRequest.setIsAppInitiated(false);

Why is this needed? Isn’t false the default?
Comment 16 EWS 2022-03-30 20:46:31 PDT
Committed r292139 (249046@main): <https://commits.webkit.org/249046@main>

All reviewed patches have been landed. Closing bug and clearing flags on attachment 456144 [details].
Comment 17 Kate Cheney 2022-03-31 08:58:45 PDT
(In reply to Darin Adler from comment #15)
> Comment on attachment 456144 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=456144&action=review
> 
> > Source/WebCore/loader/NavigationScheduler.cpp:385
> > +        if (auto* documentLoader = m_originDocument.loader())
> > +            resourceRequest.setIsAppInitiated(documentLoader->lastNavigationWasAppInitiated());
> 
> Is it really OK to leave this set to the default if there is no document
> loader associated? Does that mean it gets set to true or false? Which is the
> correct value for that case?
> 
> > Source/WebCore/loader/ThreadableLoader.cpp:115
> > +    if (auto* documentLoader = document ? document->loader() : nullptr)
> > +        request.setIsAppInitiated(documentLoader->lastNavigationWasAppInitiated());
> 
> Is it really OK to leave this set to the default if there is no document
> loader associated? Does that mean it gets set to true or false? Which is the
> correct value for that case?
> 
> > Source/WebCore/page/DragController.cpp:298
> > +    resourceRequest.setIsAppInitiated(false);
> 
> Why is this needed? Isn’t false the default?

The default for a request's attribution value is to attribute to the app/developer (https://developer.apple.com/documentation/foundation/nsurlrequest/attribution) which equates to app-initiated being "true".

I am not sure of the full extent of cases where we create a request without a document loader, which is where we store the attribution value from the initial request. Maybe an investigation into that would be useful. For now, in the case where we are unsure of the attribution value because the document loader is null, I think it makes sense to keep the default value.
Comment 18 Brent Fulgham 2022-03-31 09:19:45 PDT
Comment on attachment 456144 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=456144&action=review

>> Source/WebCore/page/DragController.cpp:298
>> +    resourceRequest.setIsAppInitiated(false);
> 
> Why is this needed? Isn’t false the default?

The default value is app initiated; we have to set to non-app-initiated if we have reason to believe a user triggered the load. In this case, since the request is happening because of a user drag operation, we can set to "non-app-initiated".