Skip to content
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

feat: on license request errors, return response body as cause #137

Merged
merged 11 commits into from
Jul 27, 2021

Conversation

gkatsev
Copy link
Member

@gkatsev gkatsev commented Jul 20, 2021

This adds a new cause property to the error object returned by player.error() when a license request fails with a 4xx or 5xx status code. It's a string representation, so, if it's JSON a consumer would need to call JSON.parse manually as we can't know whether it's JSON or not.

One way of using it is by listening to the error event and then re-setting the message to be the cause

// notice the .one here, otherwise we'd get caught in an infinite loop
player.one('error', () => {
  var e = player.error();
  player.error(null);
  player.error({code: 5, message: e.cause})
});

Copy link
Member Author

@gkatsev gkatsev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In addition to the comments below, are there any other places where we may need to bubble the cause through?

src/eme.js Outdated Show resolved Hide resolved
src/fairplay.js Outdated
Comment on lines 121 to 126
if (response.statusCode >= 400 && response.statusCode <= 599) {
const cause = String.fromCharCode.apply(null, new Uint8Array(responseBody));

callback({cause});
return;
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fairplay certificate 4xx and 5xx were never counted as errors apparently.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we wrap this in a checkForError function and re-use it?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or perhaps emeErrorHandler should take the response and trigger an error on error, and return true so that we can return.

Copy link
Member Author

@gkatsev gkatsev Jul 20, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, maybe we can push it into emeErrorHandler, though, I'd need to figure out whether the custom getLicense/getCertificate method's callback get to emeErrorHandler or how that piece is wired up.

Also, is it possible that treating 4xx/5xx for these as errors now going to cause an issue compared to previously? My guess is likely no, since if we didn't actually get the cert, it means that playback didn't work.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pushing it all into emeErrorHandler might make things more complicated because of existing and custom getLicenses, which expect it to be just err, and license. Though, we could use the function arity to disambiguate between the two, where if we only get 2 arguments, it's the existing stuff, and if it gets 3 items, it's the new thing since we can just pass through the err, res, resBody. I'll take a look to see whether it's worth it.

src/plugin.js Outdated
Comment on lines 193 to 202
if (typeof objOrErr === 'string') {
error.message = objOrErr;
} else if (objOrErr) {
if (objOrErr.message) {
error.message = objOrErr.message;
}
if (objOrErr.cause && objOrErr.cause.length) {
error.cause = objOrErr.cause;
}
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it makes it a bit clearer what's happening, plus allows us to set both the cause and the message based on the potential inputs to this function.

videojs.xhr = (params, callback) => {
return callback(null, {statusCode: 400}, {body: 'some-body'});
return callback(null, {statusCode: 400}, toArrayBuffer({body: 'some-body'}));
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These were incorrect. As we specify that the response type should be an arraybuffer, we need to convert these to array buffer.

@brandonocasey
Copy link
Contributor

brandonocasey commented Jul 20, 2021

I do wonder wether we should trigger a beforeerror event that can modify the error object before we trigger it.

@gkatsev
Copy link
Member Author

gkatsev commented Jul 20, 2021

Re: beforeerror, I think that adding a beforeerror hook might nice, but that's out of scope for right now.

@gkatsev
Copy link
Member Author

gkatsev commented Jul 20, 2021

Thinking about things some more, I don't think that for custom getLicense requests we can properly provide helpers, particularly, since fetch exists. I think the current err and license arguments make sense. Instead, we should update our documentation to mention that you should pass an error object when the HTTP Status Code is 4xx or 5xx and that you can provide the response body in the cause field for downstream consumers of this error. Right now, our sample documentation only shows providing an error if the XHR errored itself, which rarely happens.

@gkatsev
Copy link
Member Author

gkatsev commented Jul 20, 2021

However, internally, I think we can use a helper so that all this error stuff is handled the same across all our usage instead of trying to remember to copy-pasta it all over the place.

if (response.statusCode >= 400 && response.statusCode <= 599) {
let cause;

if (window.TextDecoder) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does any of this throw if responseBody is empty?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth adding some tests for these two functions.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yup, definitely need a bunch of tests before this is ready.
Looks like decoding nothing doesn't throw.

> var td = new TextDecoder('utf-8')
> td.decode()
< ""

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moving to videojs/xhr#7, I did end up wrapping this in a try catch just in case.

@gkatsev gkatsev changed the title feat: on license reque errors, return response body as cause feat: on license request errors, return response body as cause Jul 21, 2021
Copy link
Contributor

@brandonocasey brandonocasey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once we switch this code to use videojs.xhr I think this is good to go.

@gkatsev
Copy link
Member Author

gkatsev commented Jul 27, 2021

This will require a Video.js release with videojs/video.js#7348 which includes videojs/xhr#7.

@gkatsev gkatsev merged commit a9a5b82 into main Jul 27, 2021
@gkatsev gkatsev deleted the license-cause branch July 27, 2021 21:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants