Files
AVPlayer-HTTP-Headers-Example/AVPlayerHTTPHeaders/AVPlayerReverseProxy.m
T
2017-01-18 23:20:00 -05:00

115 lines
4.9 KiB
Objective-C

//
// AVPlayerProxy.m
// AVPlayerHTTPHeaders
//
// Created by Kevin Hunt on 2017-01-16.
// Copyright © 2017 Prophet Studios. All rights reserved.
//
#import "AVPlayerReverseProxy.h"
#import "GCDWebServer.h"
#import "GCDWebServerDataResponse.h"
NSString * __nonnull const AVPlayerProxyLocalHost = @"localhost:8080";
NSString *const AVPlayerReverseProxyDidReceiveHeadersNotification = @"AVPlayerReverseProxyDidReceiveHeadersNotification";
NSString *const AVPlayerReverseProxyNotificationRequestURLKey = @"AVPlayerReverseProxyNotificationRequestURLKey";
NSString *const AVPlayerReverseProxyNotificationHeadersKey = @"AVPlayerReverseProxyNotificationHeadersKey";
@implementation AVPlayerReverseProxy {
NSDictionary *_httpHeaders;
GCDWebServer *_webServer;
}
- (instancetype)init {
if (self = [super init]) {
_httpHeaders = [[NSDictionary alloc] init];
}
return self;
}
- (void)startPlayerProxyWithReverseProxyHost:(nonnull NSString *)reverseProxyHost {
dispatch_async(dispatch_get_main_queue(), ^{
_webServer = [[GCDWebServer alloc] init];
__weak NSDictionary *weakHeaders = _httpHeaders;
__weak typeof(self) weakSelf = self;
// Add a handler to respond to GET requests on any local URL
[_webServer addDefaultHandlerForMethod:@"GET"
requestClass:[GCDWebServerRequest class]
processBlock:^GCDWebServerResponse *(GCDWebServerRequest* request) {
// Process the request by sending it using the reverse proxy URL
GCDWebServerResponse *response = [weakSelf sendRequest:request toHost:reverseProxyHost withHeaders:weakHeaders];
return response;
}];
// Start server on port 8080
[_webServer startWithPort:8080 bonjourName:nil];
});
}
- (void)stopPlayerProxy {
dispatch_async(dispatch_get_main_queue(), ^{
[_webServer stop];
});
}
- (void)addHttpHeaders:(NSDictionary*)httpHeaders {
if (httpHeaders && [httpHeaders count] > 0) {
NSMutableDictionary *mergeDict = [NSMutableDictionary dictionaryWithDictionary:_httpHeaders];
[mergeDict addEntriesFromDictionary:httpHeaders];
_httpHeaders = [NSDictionary dictionaryWithDictionary:mergeDict];
}
}
- (void)removeHttpHeaders:(NSDictionary*)httpHeaders {
if (httpHeaders && [httpHeaders count] > 0) {
NSMutableDictionary *removeDict = [NSMutableDictionary dictionaryWithDictionary:_httpHeaders];
[removeDict removeObjectsForKeys:[httpHeaders allKeys]];
_httpHeaders = [NSDictionary dictionaryWithDictionary:removeDict];
}
}
- (GCDWebServerResponse *)sendRequest:(GCDWebServerRequest *)request toHost:(NSString *)reverseProxyHost withHeaders:(NSDictionary *)headers {
NSError *error = nil;
NSHTTPURLResponse *urlResponse = nil;
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// Replace the local url with the reverse host to recreate the original url
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
NSString *customUrl = [request.URL.absoluteString stringByReplacingOccurrencesOfString:AVPlayerProxyLocalHost withString:reverseProxyHost];
NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:customUrl]];
// Set the additional HTTP headers in the new request
for (NSString *key in [headers allKeys]) {
NSString *value = [headers valueForKey:key];
[urlRequest setValue:value forHTTPHeaderField:key];
}
// Synchronously make the request
NSData *responseData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&urlResponse error:&error];
// Capture the header info
NSDictionary *responseHeaders = urlResponse.allHeaderFields;
NSString *contentType = [responseHeaders valueForKey:@"Content-Type"];
// Post notification containing headers an corresponding URL
NSDictionary *userInfoDict = [NSDictionary dictionaryWithObjectsAndKeys:
customUrl, AVPlayerReverseProxyNotificationRequestURLKey,
responseHeaders, AVPlayerReverseProxyNotificationHeadersKey,
nil];
[[NSNotificationCenter defaultCenter] postNotificationName:AVPlayerReverseProxyDidReceiveHeadersNotification
object:nil
userInfo:userInfoDict];
// Create the response to return back to the player
GCDWebServerDataResponse *response = [GCDWebServerDataResponse responseWithData:responseData contentType:contentType];
return response;
}
@end