Last active
November 25, 2022 01:31
-
-
Save pbakondy/f89f44913ff57d36d8d72f455da40e40 to your computer and use it in GitHub Desktop.
HTTP Request Objective-C implementations
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Foundation/Foundation.h> | |
@interface MyNetwork : NSObject | |
- (NSData* )httpRequestWithURL:(NSURL *)url httpMethod:(NSString *)httpMethod body:(NSData *)body contentType:(NSString *)contentType error:(NSError **)error; | |
@end | |
@implementation MyNetwork | |
// Simple HTTP Request implementation | |
- (NSData* )httpRequestWithURL:(NSURL *)url httpMethod:(NSString *)httpMethod body:(NSData *)body contentType:(NSString *)contentType error:(NSError **)error { | |
NSLog(@"Request URL: %@", url); | |
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:30]; | |
if (request == nil) { | |
return nil; | |
} | |
[request setHTTPMethod:httpMethod]; | |
if ([@"POST" isEqualToString:httpMethod]) { | |
// can be "application/json" or "multipart/form-data" | |
[request setValue:contentType forHTTPHeaderField:@"Content-Type"]; | |
[request setHTTPBody:body]; | |
} | |
NSURLResponse *urlResponse = nil; | |
NSData *response = [self sendSynchronousRequest:request returningResponse:&urlResponse error:error]; | |
if (*error != nil) { | |
return nil; | |
} | |
NSInteger statusCode = [(NSHTTPURLResponse *)urlResponse statusCode]; | |
if (statusCode >= 200 && statusCode < 300) { | |
return response; | |
} | |
return nil; | |
} | |
- (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error { | |
NSError __block *err = NULL; | |
NSData __block *data; | |
BOOL __block reqProcessed = false; | |
NSURLResponse __block *resp; | |
[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable _data, NSURLResponse * _Nullable _response, NSError * _Nullable _error) { | |
resp = _response; | |
err = _error; | |
data = _data; | |
reqProcessed = true; | |
}] resume]; | |
while (!reqProcessed) { | |
[NSThread sleepForTimeInterval:0]; | |
} | |
*response = resp; | |
*error = err; | |
return data; | |
} | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Foundation/Foundation.h> | |
#define CONTENT_TYPE_HEADER @"Content-Type" | |
#define SESSION_HEADER @"Set-Cookie" | |
#define SESSION_KEY @"JSESSIONID" | |
@interface MyNetwork : NSObject | |
- (NSData* )httpRequestWithURL:(NSURL *)url httpMethod:(NSString *)httpMethod body:(NSData *)body contentType:(NSString *)contentType error:(NSError **)error; | |
@end | |
@implementation MyNetwork { | |
NSString *sessionId; | |
} | |
- (id) init { | |
self = [super init]; | |
if (self) { | |
sessionId = nil; | |
} | |
return self; | |
} | |
// HTTP Request implementation with Apache session handling | |
- (NSData* )httpRequestWithURL:(NSURL *)url httpMethod:(NSString *)httpMethod body:(NSData *)body contentType:(NSString *)contentType error:(NSError **)error { | |
NSLog(@"Request URL: %@", url); | |
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:30]; | |
if (request == nil) { | |
return nil; | |
} | |
[request setHTTPMethod:httpMethod]; | |
if ([@"POST" isEqualToString:httpMethod]) { | |
// can be "application/json" or "multipart/form-data" | |
[request setValue:contentType forHTTPHeaderField:CONTENT_TYPE_HEADER]; | |
[request setHTTPBody:body]; | |
} | |
if (sessionId != nil) { | |
// This command makes the following changes: | |
// - adds a new cookie to the Cookie Storage with name JSESSIONID=sessionId | |
// - this cookie will be sent with this request and every following requests too | |
// - adds new HTTP request header: JSESSIONID=sessionId | |
// - adds new HTTP request header: Cookie="JSESSIONID=sessionId" | |
[request addValue:sessionId forHTTPHeaderField:SESSION_KEY]; | |
} | |
NSURLResponse *urlResponse = nil; | |
NSData *response = [self sendSynchronousRequest:request returningResponse:&urlResponse error:error]; | |
if (*error != nil) { | |
return nil; | |
} | |
NSInteger statusCode = [(NSHTTPURLResponse *)urlResponse statusCode]; | |
// If Apache Tomcat recognizes this request as a new session ( request.getSession().isNew() ) | |
// then it sends a new HTTP response header "Set-Cookie" | |
// To maintain this session Tomcat expects this sessionId with the future requests. | |
sessionId = [self getSessionId:urlResponse]; | |
if (statusCode >= 200 && statusCode < 300) { | |
return response; | |
} | |
return nil; | |
} | |
- (NSString *)getSessionId:(NSURLResponse *)urlResponse { | |
NSDictionary *headers = [(NSHTTPURLResponse *)urlResponse allHeaderFields]; | |
NSString *setCookieHeader = [headers objectForKey:SESSION_HEADER]; | |
if (setCookieHeader == nil) { | |
return nil; | |
} | |
NSRange range = [setCookieHeader rangeOfString:SESSION_KEY options:NSCaseInsensitiveSearch]; | |
if (range.location == NSNotFound) { | |
return nil; | |
} | |
NSUInteger startPos = range.location + SESSION_KEY.length + 1; | |
NSRange rangeEnd = [setCookieHeader rangeOfString:@";"]; | |
if (rangeEnd.location == NSNotFound) { | |
return nil; | |
} | |
NSUInteger rangeLength = rangeEnd.location - startPos; | |
NSString *sessionId = [setCookieHeader substringWithRange:NSMakeRange(startPos, rangeLength)]; | |
return sessionId; | |
} | |
- (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error { | |
NSError __block *err = NULL; | |
NSData __block *data; | |
BOOL __block reqProcessed = false; | |
NSURLResponse __block *resp; | |
[[[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable _data, NSURLResponse * _Nullable _response, NSError * _Nullable _error) { | |
resp = _response; | |
err = _error; | |
data = _data; | |
reqProcessed = true; | |
}] resume]; | |
while (!reqProcessed) { | |
[NSThread sleepForTimeInterval:0]; | |
} | |
*response = resp; | |
*error = err; | |
return data; | |
} | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#import <Foundation/Foundation.h> | |
#define CONTENT_TYPE_HEADER @"Content-Type" | |
#define SESSION_HEADER @"Set-Cookie" | |
#define SESSION_KEY @"JSESSIONID" | |
@interface NSHTTPCookieStorage (applePrivateHeader) | |
- (id)_initWithIdentifier:(id)arg1 private:(BOOL)arg2; | |
@end | |
@interface MyNetwork : NSObject | |
- (NSData* )httpRequestWithURL:(NSURL *)url httpMethod:(NSString *)httpMethod body:(NSData *)body contentType:(NSString *)contentType error:(NSError **)error; | |
@end | |
// Every new instance of this class will store its cookies in a separated Cookie Storage | |
@implementation MyNetwork { | |
NSString *sessionId; | |
NSURLSessionConfiguration *urlSessionConfiguration; | |
} | |
- (id) init { | |
self = [super init]; | |
if (self) { | |
sessionId = nil; | |
NSString *uuid = [[NSUUID UUID] UUIDString]; | |
NSHTTPCookieStorage *cookieStorage = [[NSHTTPCookieStorage alloc] _initWithIdentifier:uuid private:0]; | |
cookieStorage.cookieAcceptPolicy = NSHTTPCookieAcceptPolicyAlways; | |
urlSessionConfiguration = [NSURLSessionConfiguration ephemeralSessionConfiguration]; | |
urlSessionConfiguration.HTTPCookieStorage = cookieStorage; | |
} | |
return self; | |
} | |
// HTTP Request implementation with Apache session handling supporing multiple sessions | |
- (NSData* )httpRequestWithURL:(NSURL *)url httpMethod:(NSString *)httpMethod body:(NSData *)body contentType:(NSString *)contentType error:(NSError **)error { | |
NSLog(@"Request URL: %@", url); | |
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:30]; | |
if (request == nil) { | |
return nil; | |
} | |
[request setHTTPMethod:httpMethod]; | |
if ([@"POST" isEqualToString:httpMethod]) { | |
// can be "application/json" or "multipart/form-data" | |
[request setValue:contentType forHTTPHeaderField:CONTENT_TYPE_HEADER]; | |
[request setHTTPBody:body]; | |
} | |
if (sessionId != nil) { | |
// This command makes the following changes: | |
// - adds a new cookie to the Cookie Storage with name JSESSIONID=sessionId | |
// - this cookie will be sent with this request and every following requests too | |
// - adds new HTTP request header: JSESSIONID=sessionId | |
// - adds new HTTP request header: Cookie="JSESSIONID=sessionId" | |
[request addValue:sessionId forHTTPHeaderField:SESSION_KEY]; | |
} | |
NSURLResponse *urlResponse = nil; | |
NSData *response = [self sendSynchronousRequest:request returningResponse:&urlResponse error:error]; | |
if (*error != nil) { | |
return nil; | |
} | |
NSInteger statusCode = [(NSHTTPURLResponse *)urlResponse statusCode]; | |
// If Apache Tomcat recognizes this request as a new session ( request.getSession().isNew() ) | |
// then it sends a new HTTP response header "Set-Cookie" | |
// To maintain this session Tomcat expects this sessionId with the future requests. | |
sessionId = [self getSessionId:urlResponse]; | |
if (statusCode >= 200 && statusCode < 300) { | |
return response; | |
} | |
return nil; | |
} | |
- (NSString *)getSessionId:(NSURLResponse *)urlResponse { | |
NSDictionary *headers = [(NSHTTPURLResponse *)urlResponse allHeaderFields]; | |
NSString *setCookieHeader = [headers objectForKey:SESSION_HEADER]; | |
if (setCookieHeader == nil) { | |
return nil; | |
} | |
NSRange range = [setCookieHeader rangeOfString:SESSION_KEY options:NSCaseInsensitiveSearch]; | |
if (range.location == NSNotFound) { | |
return nil; | |
} | |
NSUInteger startPos = range.location + SESSION_KEY.length + 1; | |
NSRange rangeEnd = [setCookieHeader rangeOfString:@";"]; | |
if (rangeEnd.location == NSNotFound) { | |
return nil; | |
} | |
NSUInteger rangeLength = rangeEnd.location - startPos; | |
NSString *sessionId = [setCookieHeader substringWithRange:NSMakeRange(startPos, rangeLength)]; | |
return sessionId; | |
} | |
// [NSURLSession sharedSession] uses a common shared Cookie Storage therefore it does not allow maintaining multiple sessions | |
// [NSURLSession sessionWithConfiguration:urlSessionConfiguration] uses a custom separated Cookie Storage | |
- (NSData *)sendSynchronousRequest:(NSURLRequest *)request returningResponse:(NSURLResponse **)response error:(NSError **)error { | |
NSError __block *err = NULL; | |
NSData __block *data; | |
BOOL __block reqProcessed = false; | |
NSURLResponse __block *resp; | |
[[[NSURLSession sessionWithConfiguration:urlSessionConfiguration] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable _data, NSURLResponse * _Nullable _response, NSError * _Nullable _error) { | |
resp = _response; | |
err = _error; | |
data = _data; | |
reqProcessed = true; | |
}] resume]; | |
while (!reqProcessed) { | |
[NSThread sleepForTimeInterval:0]; | |
} | |
*response = resp; | |
*error = err; | |
return data; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment