RESOLVED FIXED 155995
WebKit should dispatchDidFailProvisionalLoad while loading invalid URLs
https://bugs.webkit.org/show_bug.cgi?id=155995
Summary WebKit should dispatchDidFailProvisionalLoad while loading invalid URLs
Jiewen Tan
Reported 2016-03-29 16:24:18 PDT
* SUMMARY Handling of invalid URLs should be investigated * STEPS TO REPRODUCE URLs that have certain invalid characters result in an about:blank page instead of a Safari error page. The following URLs can be used to demonstrate this. Try them out from href links. file://www.apple.com<>/ https://www.apple.com<>/
Attachments
Patch (13.39 KB, patch)
2016-03-29 16:35 PDT, Jiewen Tan
no flags
Patch (17.44 KB, patch)
2016-03-30 19:02 PDT, Jiewen Tan
aestes: review+
Patch for landing (23.96 KB, patch)
2016-04-01 13:51 PDT, Jiewen Tan
no flags
Jiewen Tan
Comment 1 2016-03-29 16:25:25 PDT
Jiewen Tan
Comment 2 2016-03-29 16:35:42 PDT
Brent Fulgham
Comment 3 2016-03-29 17:50:47 PDT
Comment on attachment 275148 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=275148&action=review This looks great! I think the test cases need a little work. (1) I'd like to see a WK1 test case, since the 'cancelMainResourceLoad' is invoked for WK1 and WK2. (2) I'd like to see a "success" case for WK2 (and WK1) that confirms that normal loads work properly with this change. For those reasons, r- to add some additional test cases. > Source/WebCore/ChangeLog:9 > + Added API Tests. It looks like you added a WK2 test, but this code change is in WebCore. It seems like you should also have a WK1 test, following something like the code in BackForwardList.mm as an example. > Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LoadInvalidURLRequest.mm:77 > +} Please add another test for the "success" case where you navigate to a valid URL just to make sure we didn't break anything.
Sam Weinig
Comment 4 2016-03-29 18:04:50 PDT
What security vulnerability is this bug in regards to? While it is not necessary to explain in detail in the bug the issue is (and you shouldn't) this bug should out line the concern.
Jiewen Tan
Comment 5 2016-03-29 18:25:19 PDT
(In reply to comment #4) > What security vulnerability is this bug in regards to? While it is not > necessary to explain in detail in the bug the issue is (and you shouldn't) > this bug should out line the concern. The original concern is: Window objects that are scriptable from other windows such as the opener could potentially use this bug to mislead users about what page they are at However, I don't think it is valid now as the bug is not quite the same as it is originally reported.
Jiewen Tan
Comment 6 2016-03-29 18:39:35 PDT
Comment on attachment 275148 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=275148&action=review >> Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LoadInvalidURLRequest.mm:77 >> +} > > Please add another test for the "success" case where you navigate to a valid URL just to make sure we didn't break anything. I think existing layout tests/api tests should already cover the "success" case.
Andy Estes
Comment 7 2016-03-29 18:48:04 PDT
Comment on attachment 275148 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=275148&action=review > Source/WebCore/loader/DocumentLoader.cpp:1516 > + if (!m_request.url().isValid()) > + cancelMainResourceLoad(frameLoader()->client().cannotShowURLError(m_request)); > + else { You should just return early after calling cancelMainResourceLoad(). > Source/WebCore/loader/FrameLoader.cpp:2213 > + if (!m_provisionalLoadErrorBeingHandledURL.isEmpty() && !error.isCancellation()) > + return; > + You don't explain why you moved this or why added a check for cancellation errors. You also don't test this new behavior. I think you need to do both of these things.
Andy Estes
Comment 8 2016-03-29 18:51:13 PDT
Comment on attachment 275148 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=275148&action=review > Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LoadInvalidURLRequest.mm:69 > + [webView loadRequest:[NSURLRequest requestWithURL:contentURL]]; Is it actually necessary to load an HTML file that clicks a link to "https://www.apple.com&lt;&gt;/"? Would it not be sufficient to just call loadRequest: directly with that URL?
Sam Weinig
Comment 9 2016-03-29 22:12:27 PDT
(In reply to comment #5) > (In reply to comment #4) > > What security vulnerability is this bug in regards to? While it is not > > necessary to explain in detail in the bug the issue is (and you shouldn't) > > this bug should out line the concern. > > The original concern is: > Window objects that are scriptable from other windows such as the opener > could potentially use this bug to mislead users about what page they are at > > However, I don't think it is valid now as the bug is not quite the same as > it is originally reported. Ok, then what is the issue now?
Jiewen Tan
Comment 10 2016-03-29 23:36:21 PDT
Comment on attachment 275148 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=275148&action=review >> Source/WebCore/loader/DocumentLoader.cpp:1516 >> + else { > > You should just return early after calling cancelMainResourceLoad(). I have a return statement after the if else control. >> Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LoadInvalidURLRequest.mm:69 >> + [webView loadRequest:[NSURLRequest requestWithURL:contentURL]]; > > Is it actually necessary to load an HTML file that clicks a link to "https://www.apple.com&lt;&gt;/"? Would it not be sufficient to just call loadRequest: directly with that URL? I cannot create a NSURL object by passing a string containing an invalid URL. There is a complicated way we use in WebCoreNSURLExtras.mm to create a NSURL that accepts invalid URL strings. I choose the current way as it is easier and more understandable.
Jiewen Tan
Comment 11 2016-03-29 23:39:17 PDT
(In reply to comment #9) > (In reply to comment #5) > > (In reply to comment #4) > > > What security vulnerability is this bug in regards to? While it is not > > > necessary to explain in detail in the bug the issue is (and you shouldn't) > > > this bug should out line the concern. > > > > The original concern is: > > Window objects that are scriptable from other windows such as the opener > > could potentially use this bug to mislead users about what page they are at > > > > However, I don't think it is valid now as the bug is not quite the same as > > it is originally reported. > > Ok, then what is the issue now? I am not capable of reassessing the security vulnerability of this bug. From my understanding, it is that we should show a Safari error page by
Jiewen Tan
Comment 12 2016-03-29 23:40:32 PDT
(In reply to comment #11) > (In reply to comment #9) > > (In reply to comment #5) > > > (In reply to comment #4) > > > > What security vulnerability is this bug in regards to? While it is not > > > > necessary to explain in detail in the bug the issue is (and you shouldn't) > > > > this bug should out line the concern. > > > > > > The original concern is: > > > Window objects that are scriptable from other windows such as the opener > > > could potentially use this bug to mislead users about what page they are at > > > > > > However, I don't think it is valid now as the bug is not quite the same as > > > it is originally reported. > > > > Ok, then what is the issue now? > > I am not capable of reassessing the security vulnerability of this bug. From > my understanding, it is that we should show a Safari error page by dispatchDidFailProvisionalLoad with proper error msg when users navigate to invalid URLs.
Andy Estes
Comment 13 2016-03-30 09:01:38 PDT
(In reply to comment #10) > Comment on attachment 275148 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=275148&action=review > > >> Source/WebCore/loader/DocumentLoader.cpp:1516 > >> + else { > > > > You should just return early after calling cancelMainResourceLoad(). > > I have a return statement after the if else control. Right. I'm suggesting you don't add the else block and instead just return after calling cancelMainResourceLoad(). > > >> Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LoadInvalidURLRequest.mm:69 > >> + [webView loadRequest:[NSURLRequest requestWithURL:contentURL]]; > > > > Is it actually necessary to load an HTML file that clicks a link to "https://www.apple.com&lt;&gt;/"? Would it not be sufficient to just call loadRequest: directly with that URL? > > I cannot create a NSURL object by passing a string containing an invalid > URL. There is a complicated way we use in WebCoreNSURLExtras.mm to create a > NSURL that accepts invalid URL strings. I choose the current way as it is > easier and more understandable. Ok, thank makes sense.
Jiewen Tan
Comment 14 2016-03-30 19:02:17 PDT
Brent Fulgham
Comment 15 2016-03-31 16:34:40 PDT
Comment on attachment 275254 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=275254&action=review > Source/WebKit2/UIProcess/WebPageProxy.cpp:1007 > + // the page load state will not transit in a desired order. // When the UIProcess is in the process of handling a failing provisional load, do not attempt to // start a second alternative HTML load as this will prevent the page load state from being // handled properly. > Source/WebKit2/UIProcess/WebPageProxy.h:1514 > + bool m_isDealingFailingProvisionalLoad; I think this should be "bool m_isDealingFailingProvisionalLoad { false };"
Andy Estes
Comment 16 2016-03-31 17:24:08 PDT
Comment on attachment 275254 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=275254&action=review From your conversation with Sam, I'm somewhat unclear if this still needs to be a security bug. r=me. > Source/WebKit2/UIProcess/WebPageProxy.cpp:1008 > + if (m_isClosed || m_isDealingFailingProvisionalLoad) Wouldn't any new load started in response to a provisional load failure cause this problem? For instance, if the client called loadRequest: instead of _loadAlternateHTMLString:baseURL:forUnreachableURL:, would you see the same assertion? If so, seems like we need a fix that won't involve adding checks like this to every loading entry point in the UI process. I'm ok with this for now, since you are handling what Safari does, but we might need to come up with a better long-term solution. >> Source/WebKit2/UIProcess/WebPageProxy.h:1514 >> + bool m_isDealingFailingProvisionalLoad; > > I think this should be "bool m_isDealingFailingProvisionalLoad { false };" Not a fan of this name. Let's be specific: m_isLoadingAlternateHTMLStringForFailingProvisionalLoad. > Tools/ChangeLog:10 > + * TestWebKitAPI/Tests/WebKit2Cocoa/LoadAlternateHTMLString.mm: It doesn't make sense to have a test with WebKit1 code inside Tests/WebKit2Cocoa/. Either add two files, or just put this in Tests/Cocoa/. > Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LoadAlternateHTMLString.mm:38 > +static int provisionalLoadCount = 0; You don't need to initialize this to 0. > Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LoadAlternateHTMLString.mm:48 > +static NSData *literalAsData(const char* literal) > +{ > + return [NSData dataWithBytes:literal length:strlen(literal)]; > +} > + > +static NSURL *literalURL(const char* literal) > +{ > + return WebCore::URLWithData(literalAsData(literal), nil); > +} Not sure you really need these functions. > Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LoadAlternateHTMLString.mm:58 > + [webView _loadAlternateHTMLString:@"error page" baseURL:nil forUnreachableURL:[NSURL URLWithString:@"data:"]]; The unreachable URL shouldn't be "data:", it should be the invalid URL you passed to loadRequest:. > Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LoadAlternateHTMLString.mm:122 > + [webView loadRequest:[NSURLRequest requestWithURL:literalURL("https://www.example.com<>/")]]; > + [webView loadRequest:[NSURLRequest requestWithURL:literalURL("https://www.example.com<>/")]]; Why create two of the same URLs when you could just have one local NSURL? > Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LoadInvalidURLRequest.mm:59 > +- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error Can you check that the NSError has the domain/code/userInfo you'd expect for a cannotShowURLError? > Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LoadInvalidURLRequest.mm:80 > +- (void)webView:(WebView *)sender didFailProvisionalLoadWithError:(NSError *)error forFrame:(WebFrame *)frame Ditto.
Jiewen Tan
Comment 17 2016-03-31 17:52:12 PDT
Comment on attachment 275254 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=275254&action=review Thanks Andy and Brent for giving comments! >> Source/WebKit2/UIProcess/WebPageProxy.cpp:1008 >> + if (m_isClosed || m_isDealingFailingProvisionalLoad) > > Wouldn't any new load started in response to a provisional load failure cause this problem? For instance, if the client called loadRequest: instead of _loadAlternateHTMLString:baseURL:forUnreachableURL:, would you see the same assertion? If so, seems like we need a fix that won't involve adding checks like this to every loading entry point in the UI process. I'm ok with this for now, since you are handling what Safari does, but we might need to come up with a better long-term solution. I don't think other APIs have the same problem. It should be only specific to loadAlternateHTMLString as the way we tell if we are in the process of responding to a provisional load failure in WebProcess is to check whether FrameLoader ::m_provisionalLoadErrorBeingHandledURL is empty. This member is only set/clear at WebPage::loadAlternateHTMLString. >> Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LoadAlternateHTMLString.mm:48 >> +} > > Not sure you really need these functions. I can't initiate a NSURL object easily by passing a string containing invalid URLs. However, with the help of WebCore::URLWithData, it can be done.
Andy Estes
Comment 18 2016-03-31 18:22:25 PDT
(In reply to comment #17) > Comment on attachment 275254 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=275254&action=review > > Thanks Andy and Brent for giving comments! > > >> Source/WebKit2/UIProcess/WebPageProxy.cpp:1008 > >> + if (m_isClosed || m_isDealingFailingProvisionalLoad) > > > > Wouldn't any new load started in response to a provisional load failure cause this problem? For instance, if the client called loadRequest: instead of _loadAlternateHTMLString:baseURL:forUnreachableURL:, would you see the same assertion? If so, seems like we need a fix that won't involve adding checks like this to every loading entry point in the UI process. I'm ok with this for now, since you are handling what Safari does, but we might need to come up with a better long-term solution. > > I don't think other APIs have the same problem. It should be only specific > to loadAlternateHTMLString as the way we tell if we are in the process of > responding to a provisional load failure in WebProcess is to check whether > FrameLoader ::m_provisionalLoadErrorBeingHandledURL is empty. This member is > only set/clear at WebPage::loadAlternateHTMLString. No, that's not true. m_provisionalLoadErrorBeingHandledURL is set in FrameLoader whenever there's a provisional load failure. It's also set in WebPage::loadAlternateHTMLString(), but that's just to account for the fact that WebKit2 clients do not load alternate HTML synchronously. My question was whether the assertion failure you saw would also occur in the presence of two sequential provisionally failing loads when the client responded to the second one with something other than _loadAlternateHTMLString:... > > >> Tools/TestWebKitAPI/Tests/WebKit2Cocoa/LoadAlternateHTMLString.mm:48 > >> +} > > > > Not sure you really need these functions. > > I can't initiate a NSURL object easily by passing a string containing > invalid URLs. However, with the help of WebCore::URLWithData, it can be done. I get that part. I was just suggesting that you didn't need to create new functions to do this; just call URLWithData() directly.
Jiewen Tan
Comment 19 2016-03-31 18:59:20 PDT
Comment on attachment 275254 [details] Patch View in context: https://bugs.webkit.org/attachment.cgi?id=275254&action=review >>>> Source/WebKit2/UIProcess/WebPageProxy.cpp:1008 >>>> + if (m_isClosed || m_isDealingFailingProvisionalLoad) >>> >>> Wouldn't any new load started in response to a provisional load failure cause this problem? For instance, if the client called loadRequest: instead of _loadAlternateHTMLString:baseURL:forUnreachableURL:, would you see the same assertion? If so, seems like we need a fix that won't involve adding checks like this to every loading entry point in the UI process. I'm ok with this for now, since you are handling what Safari does, but we might need to come up with a better long-term solution. >> >> I don't think other APIs have the same problem. It should be only specific to loadAlternateHTMLString as the way we tell if we are in the process of responding to a provisional load failure in WebProcess is to check whether FrameLoader ::m_provisionalLoadErrorBeingHandledURL is empty. This member is only set/clear at WebPage::loadAlternateHTMLString. > > No, that's not true. m_provisionalLoadErrorBeingHandledURL is set in FrameLoader whenever there's a provisional load failure. It's also set in WebPage::loadAlternateHTMLString(), but that's just to account for the fact that WebKit2 clients do not load alternate HTML synchronously. > > My question was whether the assertion failure you saw would also occur in the presence of two sequential provisionally failing loads when the client responded to the second one with something other than _loadAlternateHTMLString:... I think the situation you mentioned is fine, but what will cause problems is replacing the first one with some other load APIs. Once WebProcess enter the state of loadAlternateHTMLString, it will lose the ability to send DidFailProvisionalLoad error through checkLoadCompleteForThisFrame to the clients, and therefore any back to back load before loadAlternateHTMLString will cause the assertion to hit. The way how loadAlternateHTMLString lock things down is too heavy. I don't have any idea to fix this for long term so far.
Andy Estes
Comment 20 2016-03-31 19:01:46 PDT
(In reply to comment #19) > Comment on attachment 275254 [details] > Patch > > View in context: > https://bugs.webkit.org/attachment.cgi?id=275254&action=review > > >>>> Source/WebKit2/UIProcess/WebPageProxy.cpp:1008 > >>>> + if (m_isClosed || m_isDealingFailingProvisionalLoad) > >>> > >>> Wouldn't any new load started in response to a provisional load failure cause this problem? For instance, if the client called loadRequest: instead of _loadAlternateHTMLString:baseURL:forUnreachableURL:, would you see the same assertion? If so, seems like we need a fix that won't involve adding checks like this to every loading entry point in the UI process. I'm ok with this for now, since you are handling what Safari does, but we might need to come up with a better long-term solution. > >> > >> I don't think other APIs have the same problem. It should be only specific to loadAlternateHTMLString as the way we tell if we are in the process of responding to a provisional load failure in WebProcess is to check whether FrameLoader ::m_provisionalLoadErrorBeingHandledURL is empty. This member is only set/clear at WebPage::loadAlternateHTMLString. > > > > No, that's not true. m_provisionalLoadErrorBeingHandledURL is set in FrameLoader whenever there's a provisional load failure. It's also set in WebPage::loadAlternateHTMLString(), but that's just to account for the fact that WebKit2 clients do not load alternate HTML synchronously. > > > > My question was whether the assertion failure you saw would also occur in the presence of two sequential provisionally failing loads when the client responded to the second one with something other than _loadAlternateHTMLString:... > > I think the situation you mentioned is fine, but what will cause problems is > replacing the first one with some other load APIs. > > Once WebProcess enter the state of loadAlternateHTMLString, it will lose the > ability to send DidFailProvisionalLoad error through > checkLoadCompleteForThisFrame to the clients, and therefore any back to back > load before loadAlternateHTMLString will cause the assertion to hit. > > The way how loadAlternateHTMLString lock things down is too heavy. I don't > have any idea to fix this for long term so far. It isn't urgent since we don't know if any clients actually do this, but filing a bug and writing some test cases is a good place to start. Thanks!
Jiewen Tan
Comment 21 2016-04-01 13:51:33 PDT
Created attachment 275426 [details] Patch for landing
WebKit Commit Bot
Comment 22 2016-04-01 14:40:16 PDT
Comment on attachment 275426 [details] Patch for landing Clearing flags on attachment: 275426 Committed r198956: <http://trac.webkit.org/changeset/198956>
Jiewen Tan
Comment 23 2016-04-01 14:46:29 PDT
Bug 156117 is filed to address the issue of SPI: _LoadAlternateHTMLString.
Jiewen Tan
Comment 24 2016-04-01 18:49:13 PDT
A build fix for adopting existing API tests to the new change has been landed: Committed r198964: <http://trac.webkit.org/changeset/198964>
Andy Estes
Comment 25 2016-04-03 06:55:59 PDT
(In reply to comment #22) > Comment on attachment 275426 [details] > Patch for landing > > Clearing flags on attachment: 275426 > > Committed r198956: <http://trac.webkit.org/changeset/198956> > > +- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error > +{ > + if ([error.domain isEqual:@"WebKitErrorDomain"] > + && error.code == WebKitErrorCannotShowURL > + && [error.userInfo[@"NSErrorFailingURLKey"] isEqual:literalURL(literal)]) > + didFailProvisionalLoad = true; > + didFinishTest = true; > +} This wasn't what I meant when I suggested that you "check that the NSError has the domain/code/userInfo you'd expect". I was suggesting that you use EXPECT macros to verify the error is of the form we expect. Sorry if I wasn't clear.
Jiewen Tan
Comment 26 2016-04-04 13:17:57 PDT
(In reply to comment #25) > (In reply to comment #22) > > Comment on attachment 275426 [details] > > Patch for landing > > > > Clearing flags on attachment: 275426 > > > > Committed r198956: <http://trac.webkit.org/changeset/198956> > > > > +- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error > > +{ > > + if ([error.domain isEqual:@"WebKitErrorDomain"] > > + && error.code == WebKitErrorCannotShowURL > > + && [error.userInfo[@"NSErrorFailingURLKey"] isEqual:literalURL(literal)]) > > + didFailProvisionalLoad = true; > > + didFinishTest = true; > > +} > > This wasn't what I meant when I suggested that you "check that the NSError > has the domain/code/userInfo you'd expect". I was suggesting that you use > EXPECT macros to verify the error is of the form we expect. Sorry if I > wasn't clear. Committed r199018: <http://trac.webkit.org/changeset/199018> to address Andy's comments.
Note You need to log in before you can comment on or make changes to this bug.