Skip to content

Instantly share code, notes, and snippets.

@pbakondy
Last active November 25, 2022 01:31
Show Gist options
  • Save pbakondy/f89f44913ff57d36d8d72f455da40e40 to your computer and use it in GitHub Desktop.
Save pbakondy/f89f44913ff57d36d8d72f455da40e40 to your computer and use it in GitHub Desktop.
HTTP Request Objective-C implementations
#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
#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
#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