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

added optional request headers for remote assests (android & ios) #805

Merged
merged 15 commits into from
Jun 25, 2018

Conversation

emrahdk
Copy link
Contributor

@emrahdk emrahdk commented Oct 2, 2017

This pull request adds support for setting arbitrary Request Headers for resolving remote media. A use case could be to add an Authorization header for media that needs authentication. Therefore this PR should be able to close #475.

It can be used as demonstrated in the snippet below, by adding a headers object in the source property of the Video component.

<Video
  source={{
    uri: videoUrl,                        .
      headers: {
        Authorization: 'bearer some-token-value',
        'X-Custom-Header': 'some value'
      }
  }}
</Video>

It has been tested on iOS and Android.

Note: It was currently not possible to add the same functionality for Windows. System.Windows.Media.MediaPlayer only supports a single Uri class for remote/local media.

@wja123
Copy link

wja123 commented Oct 7, 2017

This would be great, I can't wait till this is implemented.

@ArtisanalPickle
Copy link

Great stuff. Any update on this? Would love to see this merged.

Video.js Outdated
const strObj = {};

Object.keys(obj).forEach(x => {
strObj[x] = obj[x].toString();

Choose a reason for hiding this comment

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

This will set objects to [object Object] - do we want a check here for typeof obj[x] and to use JSON.stringify in those cases?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes you're correct - I was kinda of unsure whether to leave it or do a "smarter" string conversion. After your review, I choose the latter. 👍

Conversion is as follows:

  • Booleans, numbers, strings => prototype.toString
  • Objects and nulls => JSON.stringify'
  • Date => prototype.toISOString
  • undefined => returns empty string

@@ -190,6 +200,7 @@ export default class Video extends Component {
type: source.type || '',
mainVer: source.mainVer || 0,
patchVer: source.patchVer || 0,
requestHeaders: source.headers ? this.stringsOnlyObject(source.headers) : {}

Choose a reason for hiding this comment

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

I believe the key here should be headers and not requestHeaders. That or VideoViewManager.PROP_SRC_HEADERS needs to be changed to requestHeaders. Without these changes, this line in VideoViewManager:

src.getMap(PROP_SRC_HEADERS)

throws a runtime error due to the fact that 'headers' is not a key on 'src'.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Nice catch! 🙏 I've just pushed updates. I can't test it out on Android right now - it would be nice if you could verify it works. 🙌

Thanks for the reviews btw! 👍

@ptfly
Copy link

ptfly commented Dec 24, 2017

Thank you very much for this! Hope it gets merged asap 🥇

@JohnGalt1717
Copy link

Yes please! I hope this gets merged ASAP. This is required for any AES Encrypted video playback.

Windows UWP should be possible as well because this is supported. There are samples from the Azure Media Services team.

WPF is the only one that should have issues.

@emrahdk
Copy link
Contributor Author

emrahdk commented Jan 13, 2018

@JohnGalt1717 could you point me in the direction of these samples? I'd love to add support for UWP too

@kyle-ssg
Copy link

+1

@gouxlord
Copy link

Awesome !

@JohnGalt1717
Copy link

JohnGalt1717 commented Feb 27, 2018

@emrah88 I believe it's here: https://github.com/Microsoft/Windows-universal-samples/tree/master/Samples/AdaptiveStreaming

I also have UWP code that works for AES.

You can use the Azure Media Player samples library to test the various types as well using that code. That will get you PlayReady, Fairplay, AES and that other one that I can never remember that Google uses.

@gouxlord
Copy link

@emrah88 I tested your fork on android and got this error, i tried some fixes but my android knowledge is low:

Error while updating property 'src' of a view managed by: RCTVideo

null

couldn't find key requestHeaders in dynamic object

Hope this help :)

@cedbale
Copy link

cedbale commented Feb 27, 2018

👍 should be great to have this feature merged soon :)

@vwmoose
Copy link

vwmoose commented Apr 17, 2018

Any news on this being merged anytime soon?

@davidsneal
Copy link

Also in need of this!

@sanchesking9
Copy link

@sampurcell93 sorry, when can you merge it? it's really needed feature

@rterysen
Copy link

Really need this!!! can I get a merge or a alternative?

@kyle-ssg
Copy link

kyle-ssg commented Apr 27, 2018

You can of course can fork the pr in the meantime and point to that in your package.json, but yeah definitely needs merging

@sanchesking9
Copy link

It has an error on android

Error while updating property 'src' of a view managed by: RCTVideo

null

couldn't find key requestHeaders in dynamic object

so fork couldn't help in this case

@emrah88, sorry, when can you fix it?

@sampurcell93
Copy link

@sanchesking9 I do not have write permissions.

@sanchesking9
Copy link

@isaiahgrey93 sorry, maybe you have write permissions??

@emrahdk
Copy link
Contributor Author

emrahdk commented May 4, 2018

Thanks for your feedback!! 🙏 🙏

I don't have that much Android experience. Sadly, this PR can't be merged as it is now since the Android player throws errors. No problems in iOS though, I am currently using it production.

I've tried to fix it, but I only get the first video playing. As soon as I try to load another video I get exceptions. I'll keep working on it though.

For you that are willing to try it out add the following to dependencies in package.json:
react-native-video: emrah88/react-native-video

@emrahdk
Copy link
Contributor Author

emrahdk commented May 4, 2018

@JohnGalt1717 cool, I'll look in to the AdaptiveStreaming samples

ios/RCTVideo.m Outdated
NSURL *url = (isNetwork || isAsset) ?
[NSURL URLWithString:uri] :
[[NSURL alloc] initFileURLWithPath:[[NSBundle mainBundle] pathForResource:uri ofType:type]];

if (isNetwork) {
if ([headers count] > 0) {
Copy link
Contributor

Choose a reason for hiding this comment

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

This will ignore cookies if you opt to use headers. You should build up the options object so both are supported.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ahh, good point! 🙌 I see it now 👏

@cobarx
Copy link
Contributor

cobarx commented May 29, 2018

@emrah88 I can get this merged once the remaining issues get resolved. What sort of problems are you running into on Android, I should be able to help you get them sorted out. I left a note on the iOS code.

@sampurcell93 Thanks for helping review this. We could use more maintainers, if you'd like to help out lmk and I can get you added.

@emrahdk
Copy link
Contributor Author

emrahdk commented Jun 9, 2018

Hey @cobarx that sounds great! I should be able to give you some logcat output at Monday. The gist is: first video plays fine first time around, when selecting other video nothing happens.

@@ -254,7 +254,7 @@ public void setSrc(final String uriString, final String type, final boolean isNe
headers.putAll(toStringMap(mRequestHeaders));
}

setDataSource(uriString);
setDataSource(mThemedReactContext, parsedUrl, headers);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

In master (of the main repo) no headers are being passed to setDataSource. Even though the headers HashMap is being created (lines 247-251) and the cookies are added to it.

Is it me or was the headers never used?

Luckily setDataSource had an overload that accepted headers which I could pass them to.

@emrahdk
Copy link
Contributor Author

emrahdk commented Jun 9, 2018

I managed to get it working on Android now 🎉
... but I'm unsure about it's the right approach.

@cobarx could you have a look at my comment in the latest commit? (49cd5b6)

@sanchesking9
Copy link

hi @emrah88
something happened with ios version, check it please

/Users/user/www/GetAlertReact/node_modules/react-native-video/ios/RCTVideo.m:55:22: warning: designated initializer invoked a non-designated initializer [-Wobjc-designated-initializers]
if ((self = [super init])) {
^
In file included from /Users/user/www/GetAlertReact/node_modules/react-native-video/ios/RCTVideo.m:2:
/Users/user/www/GetAlertReact/node_modules/react-native-video/ios/RCTVideo.h:29:1: note: method marked as designated initializer of the class here

  • (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER;
    ^
    /Users/user/www/GetAlertReact/node_modules/react-native-video/ios/RCTVideo.m:53:1: warning: designated initializer missing a 'super' call to a designated initializer of the super class [-Wobjc-designated-initializers]
  • (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher
    ^
    In file included from /Users/user/www/GetAlertReact/node_modules/react-native-video/ios/RCTVideo.m:2:
    /Users/user/www/GetAlertReact/node_modules/react-native-video/ios/RCTVideo.h:29:1: note: method marked as designated initializer of the class here
  • (instancetype)initWithEventDispatcher:(RCTEventDispatcher *)eventDispatcher NS_DESIGNATED_INITIALIZER;
    ^
    /Users/user/www/GetAlertReact/node_modules/react-native-video/ios/RCTVideo.m:333:31: error: unexpected '@' in program
    [assetOptions setObject:@headers forKey:@"AVURLAssetHTTPHeaderFieldsKey"]
    ^
    /Users/user/www/GetAlertReact/node_modules/react-native-video/ios/RCTVideo.m:336:29: error: unexpected '@' in program
    [assetOptions setObject:@cookies forKey:@AVURLAssetHTTPCookiesKey]
    ^
    /Users/user/www/GetAlertReact/node_modules/react-native-video/ios/RCTVideo.m:339:46: error: use of undeclared identifier 'asset'
    return [AVPlayerItem playerItemWithAsset:asset];
    ^
    /Users/user/www/GetAlertReact/node_modules/react-native-video/ios/RCTVideo.m:364:27: warning: initializing 'NSString *__strong' with an expression of incompatible type 'id<NSObject,NSCopying> _Nullable'
    NSString *value = item.value;
    ^ ~~~~~~~~~~
    /Users/user/www/GetAlertReact/node_modules/react-native-video/ios/RCTVideo.m:858:1: warning: method possibly missing a [super insertReactSubview:atIndex:] call [-Wobjc-missing-super-calls]
    }
    ^
    /Users/user/www/GetAlertReact/node_modules/react-native-video/ios/RCTVideo.m:871:1: warning: method possibly missing a [super removeReactSubview:] call [-Wobjc-missing-super-calls]
    }
    ^
    /Users/user/www/GetAlertReact/node_modules/react-native-video/ios/RCTVideo.m:14:17: warning: method override for the designated initializer of the superclass '-initWithFrame:' not found [-Wobjc-designated-initializers]
    @implementation RCTVideo
    ^
    In module 'UIKit' imported from /Users/user/www/GetAlertReact/ios/build/Build/Products/Debug-iphonesimulator/include/React/RCTConvert.h:9:
    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator11.4.sdk/System/Library/Frameworks/UIKit.framework/Headers/UIView.h:150:1: note: method marked as designated initializer of the class here
  • (instancetype)initWithFrame:(CGRect)frame NS_DESIGNATED_INITIALIZER;
    ^
    /Users/user/www/GetAlertReact/node_modules/react-native-video/ios/RCTVideo.m:14:17: warning: method override for the designated initializer of the superclass '-initWithCoder:' not found [-Wobjc-designated-initializers]
    @implementation RCTVideo
    ^
    In module 'UIKit' imported from /Users/user/www/GetAlertReact/ios/build/Build/Products/Debug-iphonesimulator/include/React/RCTConvert.h:9:
    /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator11.4.sdk/System/Library/Frameworks/UIKit.framework/Headers/UIView.h:151:1: note: method marked as designated initializer of the class here
  • (nullable instancetype)initWithCoder:(NSCoder *)aDecoder NS_DESIGNATED_INITIALIZER;
    ^
    7 warnings and 3 errors generated.

@emrahdk
Copy link
Contributor Author

emrahdk commented Jun 11, 2018

@sanchesking9 thanks for the heads up!
I've had some syntax erros - which is fixed now.

@cobarx
Copy link
Contributor

cobarx commented Jun 23, 2018

Ok I've tested this on all 3 platforms, made a few small fixes, and it's working great!

There are only 2 things I noticed that were worth mentioning. All the data is showing up in the Apache logs URL encoded. For example:

headers: {
  'X-HTTP-Object': { key: 'value' },
  'X-HTTP-Date': new Date()
}

becomes:

X-HTTP-Object:{"key"%3a"value"}|X-HTTP-Date:2018-06-23T02%3a27%3a58.302Z

I don't know if this is an issue or not as I don't have a web app setup for testing headers. I suppose I can throw something together pretty quick in PHP and check it.

Also, as a general coding convention I tend to like keeping the variable names the same throughout. Is there any reason we need to switch back and forth between headers and requestHeaders in the native code rather than picking one? It's pretty minor and I would be ok merging without changing working code.

I went ahead and added a note about changing the Android MediaPlayer setDataSource call so we can know what's up if someone reports an issue.

This thing is pretty much ready to merge. I also need to go through and document it, which I'll probably do in another PR.

@JohnGalt1717 If you have time to add UWP support that would be fantastic.

@cobarx cobarx merged commit 5f1ce1a into TheWidlarzGroup:master Jun 25, 2018
@JohnGalt1717
Copy link

I'm burried at the moment but will see if I can get some bandwidth soon to take a look.

@edersiebert
Copy link

I need to pass a header with a video access authorization token, since I want to block the external access in .htaccess and open access only by the mobile phone through a token.

I'm using Android
but this is not working ...

source={ { uri: 'http://10.0.0.5:5000/50045454', headers: { Authorization: 'my token' } } }
in the logs I get only this

User-Agent: ReactNativeVideo/1.0 (Linux;Android 7.0) ExoPlayerLib/2.7.3 Connection: Keep-Alive Range: bytes=124042930- Host: 10.0.0.5:5000 Accept-Encoding: identity

@cobarx
Copy link
Contributor

cobarx commented Jun 29, 2018

This feature isn't in 2.3.1, it's only available on the master branch. I'll be releasing 3.0 with it later today.

@edersiebert
Copy link

thank, very much
this update will help me a lot (:

@emrahdk
Copy link
Contributor Author

emrahdk commented Jul 7, 2018

@cobarx thanks for the awesome job and putting this together!

I'll look out for any mentions regarding the changes to setDataSource.

Regarding the Apache Logs, did you figure out something? I'll try do some request to my IIS server too see if I get the same encoding.

Regarding the naming of headers and requestHeaders, I agree completely with keeping the same names. But there was a reason for it which I can't remember. I'll do a PR soon to get them aligned again.

@YoranRoels
Copy link

Is there any sort of documentation for this? I can't seem to pass my Authorization header successfully.

@cobarx
Copy link
Contributor

cobarx commented Sep 28, 2018

@YoranRoels I've added docs to the README. It only works out of the box on ExoPlayer, it's disabled by default on iOS because the code uses a private API that could get the app rejected from the App Store. The README has instructions for enabling it.

To troubleshoot, you can set breakpoints in the native code. Also, enable logging on your server to make sure the headers are arriving.

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.

Support for Authorization header for remote videos