-
Notifications
You must be signed in to change notification settings - Fork 425
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: onRequest hooks called too late #1396
Conversation
Codecov Report
@@ Coverage Diff @@
## main #1396 +/- ##
==========================================
+ Coverage 85.46% 85.47% +0.01%
==========================================
Files 40 40
Lines 10017 10025 +8
Branches 2319 2320 +1
==========================================
+ Hits 8561 8569 +8
Misses 1456 1456
📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We've talked about this offline, but it's just now occurring to me... with this change to onRequest
, is there functionally any difference between the onRequest
hook and the beforeRequest
thing that already existed?
@misteroneill It's definitely a bit of hair splitting at this point, but there seems to be no real functional difference. Especially with the revelation that the |
The biggest reason for my decision to have |
if |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should beforeRequest
alias onRequest
?
Yeah I kind of figured this was headed toward the depreciation and/or aliasing of |
Added a deprecation warning to |
src/xhr.js
Outdated
} | ||
|
||
// Use the standard videojs.xhr() method unless `videojs.Vhs.xhr` has been overriden | ||
// TODO: switch back to videojs.Vhs.xhr.name === 'XhrFunction' when we drop IE11 | ||
const xhrMethod = videojs.Vhs.xhr.original === true ? videojsXHR : videojs.Vhs.xhr; | ||
|
||
// call all registered onRequest hooks | ||
callAllHooks(_requestCallbackSet, options); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like options
is passed here but no return value is used, which would be a change from the above removed behavior where beforeRequest
returned a new options object. It seems that this new expectation is that each request callback would reference the same options object - each potentially modifying the same object in sequence.
I don't think this is a bad implementation, but it could be a breaking change to beforeRequest
. Consider this would likely fail with this refactor:
videojs.Vhs.xhr.beforeRequest = (options) => {
// Ignores `options` and returns a totally new object.
return {...};
};
We probably don't want that to break, so perhaps the callAllHooks
should have special handling for the beforeRequest
/onRequest
hooks where it passes the return value of the previous hook through a chain and returns the last result?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great catch @misteroneill ! I added some logic to support both cases and a test for the use case you described. Let me know what you think.
Couple of open question I would appreciate some feedback on per the latest changes.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code looks solid to me. I think some documentation updates are all that's needed now.
Is it better to
merge
or||
(or) the options returned frombeforeRequest
and/or hooks?
I think ||
is better in this case. Since each onRequest
(including beforeRequest
) should return an options
object, my expectation as a developer would be that videojs.xhr
receives the options returned by the last hook function called.
Should we handle
onRequest
andonResponse
hooks separately, or still usecallAllHooks
for both?
I guess you asked this because of this:
hookOptions = hookCallback(hookOptions || request, error, response);
The only reservation I have about that is that if an onResponse
hook returns a new request
object, it could replace the original request
object on the next onResponse
hook.
It may be clearer and cleaner to create separate callAllHooks
functions since they would behave slightly differently.
README.md
Outdated
|
||
Example: | ||
```javascript | ||
const playerRequestHook = (request) => { | ||
const requestUrl = new URL(request.uri); | ||
const playerRequestHook = (options) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One thought on these samples, should they be wrapped in an xhr-hooks-ready
event callback to show the recommended approach?
player.on('xhr-hooks-ready', () => {
player.tech().vhs.xhr.onRequest((options) => options);
});
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good call, will add examples with the event.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the 'xhr-hooks-ready'
event listener to all the per-player examples.
README.md
Outdated
requestUrl.searchParams.set('foo', 'bar'); | ||
request.uri = requestUrl.href; | ||
options.uri = requestUrl.href; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will need to update these samples to return the options
object (or a new object) in the same pattern as beforeRequest
.
It would make sense to document the behavior here - each onRequest
hook should return an options object and each will receive the previous hook's options object.
Also, we should document that the onResponse
hooks do not behave this way - the request
object is passed to each by reference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I wasn't 100% sure that we wanted to document it that way as it wasn't clear whether we would remove the options
return/chaining after beforeRequest
is removed. I agree it makes sense if we keep it that way for onRequest
hooks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added options
return to the onRequest
examples. Documented onResponse
passing parameters by reference as well.
Ended up splitting |
Description
The xhr wrapper calls
open
andsend
when a request object is instantiated, this is causingonRequest
hooks to modify the xhr object too late, as they were already sent when the object was returned to the VHS xhr module. Additionally, setting xhr hooks in time for the initial manifest request whenpreload
is set toauto
ormetadata
is not possible with existing events orready
callbacks.Specific Changes proposed
Moving the request hooks callback and changing the callback parameter
By calling all the
onRequest
hooks before we create therequest
object and passing the callback theoptions
object instead, we can modify the request beforeopen
is called in the xhr wrapper. Thisoptions
object allows for modifying the url/headers/methods, as well as setting abeforeSend
callback, which gives theonRequest
callback direct access to thexhr
object via a nested callback.beforeSend
will be called immediately beforexhr.send
is called, which allows for full control of the xhr object prior to sending the request.For example, setting a request header.
See all supported options: https://github.com/videojs/xhr#options
Adding an xhr-hooks-ready event
This fixes a
preload
option issue in VHS, where if metadata is preloaded settingonRequest
hooks is not possible onplayer.ready
becauseplayer.tech().vhs
doesn't exist yet as it's created inhandleSources
. Also if the user tries to setonRequest
hooks on theloadstart
event, it's too late and the callback will not be set before the manifest is requested. Thus, a new event is needed to be fired immediately when the hooks are available, which allows the user to apply these hooks to all requests, including the main manifest.Deprecating xhr.beforeRequest
Since adding an
onRequest
hooks is functionally the same as setting axhr.beforeRequest
callback, a deprecation warning will log when setting abeforeRequest
function.beforeRequest
will also now alias to anonRequest
callback.Requirements Checklist