New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.

Issue 651107 link

Starred by 1 user

Issue metadata

Status: Duplicate
Merged: issue 659307
Owner: ----
Closed: Oct 2016
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: ----
Pri: 3
Type: Bug



Sign in to add a comment

Cancellation in ResourceHandler/ResourceThrottle stack is broken

Project Member Reported by mmenke@chromium.org, Sep 28 2016

Issue description

ResourceHandlers / ResourceThrottles are supposed to cancel requests by either:

1)  Synchronously returning false.
2)  Calling ResourceController asynchronously.

ResourceLoader is not designed for ResourceController::Cancel / CancelWithError to be invoked synchronously and either true or false to be returned, or URLRequest::Cancel to be called (Synchronously or asynchronously), yet we have ResourceHandlers and ResourceThrottles that do both of these...And things *seem* to work when this is done, but there's no code to explicitly support either of these cases.

We should fix this.  Seems like we a couple options:

1) Make ResourceController::Cancel the only way to cancel requests, allowing synchronous invocation, and get rid of the return value.
2) Enforce that ResourceController::Cancel isn't called synchronously.  We could try and get fancy, and make it nullptr when it can't be called, but given how we create stacks of ResourceHandlers that share a ResourceController, that probably won't work too well.  Note that unless we change the return value to a net::Error instad of a bool, this path will preclude us from failing synchronously with custom error codes, which seems bad, unless we want to remove that ability completely - Looks like we only use 4 error codes with CAncelWithError:  ERR_TEMPORARILY_THROTTLED, ERR_INSUFFICIENT_RESOURCES, and ERR_BLOCKED_BY_CLIENT, and ERR_FAILED.
3) Make sending cancel signals sent via both paths at once work.  This just seems like a bad idea to me.

This issue is a bit related to  issue 472771 , which aims to reword URLRequest::Cancel semantics.  Getting rid of URLRequest::Cancel, for instance, would protect against subclasses incorrectly calling URLRequestCancel instead of ResourceController::Cancel or returning false.
 
(1) seems like the obvious choice to me. How can we enforce that's the only way to cancel requests?

Comment 2 by mmenke@chromium.org, Sep 29 2016

Getting rid of the bool should be trivial...URLRequest::Cancel is more complicated.  I'd really like to remove URLRequest::Cancel, but I'm not sure that's feasible (See  issue 472771  for more discussion).

Allowing sync invocation is a little weird - ResourceLoader then becomes a bit of a push/pull dongle, but shouldn't be too hard...Though we'd need to update MimeTypeResourceHandler in the same manner.

Comment 3 by mmenke@chromium.org, Sep 29 2016

Another issue is that classes should only be calling Cancel when it's their turn.  If they don't, it could be another class's turn with the request...and things devolve from there quickly.

Comment 4 by mmenke@chromium.org, Oct 12 2016

Another fun case:  Something cancels a request while one handler has it deferred.  The cancel is deferred before it reaches that handler, and then that handler tries to resume the request.  Reasoning about whether this case explodes, kinda works, mostly works, sorta works, or does in fact work is left as an exercise for the reader, but we don't have explicit handling of it.

Comment 5 by mmenke@chromium.org, Oct 24 2016

So one of the biggest problems seems to be:  ResourceHandler A calls Cancel() out of turn.  ResourceHandler B then calls Cancel()/Resume() in turn/out of turn.

We could either end up with two Cancels() making their way through the stack, or think the Resume() is for something deferring the OnRequestComplete call initiated by the cancel, or possibly run into a DCHECK in ResourceLoader::Resume (Which is actually probably safe, but doesn't seem great).  Individual ResourceHandler types that subclass ResourceHandler could also have a Cancel and Resume hanging out in their control flow as the same time as well, which could lead to similar issues.

Seems like the easiest two ways to fix this would be to either:
1)  Forbid cancelling/failing a request out of turn.  This doesn't work, since the AsyncResourceHandler can cancel at any point.
2)  Forbid delaying cancellation.  RedirectToFileResourceHandler really wants to do that, unclear if we'd break anything if we changed that.  On error, it would mean the renderer may not get all of a partially retrieved body.

Other options:
3)  Defer cancellation if it comes out of turn, until it's the cancellee's turn.  We don't know when it's the cancellee's turn, which makes this a little problematic.  I suppose we could give things a null ResourceController until it's their turn, but doesn't seem great.
4)  Have things able to peek at the ResourceLoader's real status (Cancelled or not).  This...works, but really doesn't scale, since everything would then be responsible for its own safety.

I'm kinda low on ideas here, I'm just concerned that the entire ResourceHandler stack is a mess, and has a number of hard edges around cancellation.

Comment 6 by mmenke@chromium.org, Oct 25 2016

Mergedinto: 659307
Status: Duplicate (was: Available)
Merging into new issues with simpler description of problem.

Sign in to add a comment