166 lines
4.5 KiB
Objective-C
166 lines
4.5 KiB
Objective-C
//
|
|
// MBIMHTTPConnection.m
|
|
// CocoaHTTPServer
|
|
//
|
|
// Created by James Magahern on 11/16/18.
|
|
// Copyright © 2018 James Magahern. All rights reserved.
|
|
//
|
|
|
|
#import "MBIMHTTPConnection.h"
|
|
|
|
#import "MBIMBridge.h"
|
|
#import "MBIMBridge_Private.h"
|
|
#import "MBIMBridgeOperation.h"
|
|
#import "MBIMAuthToken.h"
|
|
#import "MBIMUpdateQueue.h"
|
|
|
|
#import <Security/Security.h>
|
|
#import <CocoaHTTPServer/HTTPMessage.h>
|
|
|
|
@interface HTTPConnection (/* INTERNAL */)
|
|
- (BOOL)isAuthenticated;
|
|
@end
|
|
|
|
@implementation MBIMHTTPConnection {
|
|
NSMutableData *_bodyData;
|
|
MBIMBridgeOperation *_currentOperation;
|
|
}
|
|
|
|
- (BOOL)isSecureServer
|
|
{
|
|
return [[MBIMBridge sharedInstance] usesSSL];
|
|
}
|
|
|
|
- (NSArray *)sslIdentityAndCertificates
|
|
{
|
|
return [[MBIMBridge sharedInstance] sslCertificateAndIdentity];
|
|
}
|
|
|
|
- (BOOL)isPasswordProtected:(NSString *)path
|
|
{
|
|
if ([[MBIMBridge sharedInstance] usesAccessControl]) {
|
|
NSURL *url = [NSURL URLWithString:path];
|
|
NSString *endpointName = [url lastPathComponent];
|
|
|
|
Class operationClass = [MBIMBridgeOperation operationClassForEndpointName:endpointName];
|
|
return [operationClass requiresAuthentication];
|
|
}
|
|
|
|
return NO;
|
|
}
|
|
|
|
- (NSString *)passwordForUser:(NSString *)username
|
|
{
|
|
MBIMBridge *bridge = [MBIMBridge sharedInstance];
|
|
if ([username isEqualToString:bridge.authUsername]) {
|
|
return bridge.authPassword;
|
|
}
|
|
|
|
// nil means "user not in system"
|
|
return nil;
|
|
}
|
|
|
|
- (BOOL)isAuthenticated
|
|
{
|
|
NSString *authInfo = [request headerField:@"Authorization"];
|
|
if ([authInfo hasPrefix:@"Bearer"]) {
|
|
NSArray *bearerAuthTuple = [authInfo componentsSeparatedByString:@" "];
|
|
if ([bearerAuthTuple count] == 2) {
|
|
NSString *jwtToken = [bearerAuthTuple objectAtIndex:1];
|
|
MBIMAuthToken *authToken = [[MBIMAuthToken alloc] initWithTokenString:jwtToken];
|
|
return [authToken isValid];
|
|
}
|
|
}
|
|
|
|
return [super isAuthenticated];
|
|
}
|
|
|
|
- (BOOL)useDigestAccessAuthentication
|
|
{
|
|
// TODO: should use digest all the time, but it's a bit more complicated. Allow this to be NO if
|
|
// SSL is on, because then at least basic auth is encrypted
|
|
return ![[MBIMBridge sharedInstance] usesSSL];
|
|
}
|
|
|
|
- (BOOL)supportsMethod:(NSString *)method atPath:(NSString *)path
|
|
{
|
|
if ([method isEqualToString:@"GET"] || [method isEqualToString:@"POST"]) {
|
|
return YES;
|
|
}
|
|
|
|
return NO;
|
|
}
|
|
|
|
- (NSObject<HTTPResponse> *)httpResponseForMethod:(NSString *)method URI:(NSString *)path
|
|
{
|
|
__block NSObject<HTTPResponse> *response = nil;
|
|
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
|
|
MBIMBridgeOperationCompletionBlock completion = ^(NSObject<HTTPResponse> *incomingResponse) {
|
|
response = incomingResponse;
|
|
dispatch_semaphore_signal(sema);
|
|
};
|
|
|
|
NSURL *url = [NSURL URLWithString:path];
|
|
NSString *endpointName = [url lastPathComponent];
|
|
|
|
BOOL requestTimedOut = NO;
|
|
Class operationClass = [MBIMBridgeOperation operationClassForEndpointName:endpointName];
|
|
if (operationClass != nil) {
|
|
_currentOperation = [[operationClass alloc] initWithRequestURL:url completion:completion];
|
|
_currentOperation.requestBodyData = _bodyData;
|
|
_currentOperation.request = self->request;
|
|
|
|
[[[MBIMBridge sharedInstance] operationQueue] addOperation:_currentOperation];
|
|
long status = dispatch_semaphore_wait(sema, dispatch_time(DISPATCH_TIME_NOW, (int64_t)(60.0 * NSEC_PER_SEC)));
|
|
if (status != 0) {
|
|
requestTimedOut = YES;
|
|
}
|
|
} else {
|
|
response = [[HTTPErrorResponse alloc] initWithErrorCode:404];
|
|
}
|
|
|
|
if (requestTimedOut) {
|
|
response = [_currentOperation cancelAndReturnTimeoutResponse];
|
|
}
|
|
|
|
return response;
|
|
}
|
|
|
|
- (WebSocket *)webSocketForURI:(NSString *)path
|
|
{
|
|
NSURL *url = [NSURL URLWithString:path];
|
|
NSString *endpointName = [url lastPathComponent];
|
|
if ([endpointName isEqualToString:@"updates"]) {
|
|
return [[MBIMUpdateQueue sharedInstance] vendUpdateWebSocketConsumerForRequest:request socket:asyncSocket];
|
|
}
|
|
|
|
return [super webSocketForURI:path];
|
|
}
|
|
|
|
- (BOOL)expectsRequestBodyFromMethod:(NSString *)method atPath:(NSString *)path
|
|
{
|
|
if ([method isEqualToString:@"POST"]) {
|
|
return YES;
|
|
}
|
|
|
|
return NO;
|
|
}
|
|
|
|
- (void)prepareForBodyWithSize:(UInt64)contentLength
|
|
{
|
|
_bodyData = [[NSMutableData alloc] initWithCapacity:contentLength];
|
|
}
|
|
|
|
- (void)processBodyData:(NSData *)postDataChunk
|
|
{
|
|
[_bodyData appendData:postDataChunk];
|
|
}
|
|
|
|
- (void)die
|
|
{
|
|
[_currentOperation cancel];
|
|
[super die];
|
|
}
|
|
|
|
@end
|