Skip to content

Instantly share code, notes, and snippets.

@eoghain
Created January 22, 2014 22:41
Show Gist options
  • Save eoghain/8568881 to your computer and use it in GitHub Desktop.
Save eoghain/8568881 to your computer and use it in GitHub Desktop.
NSMutableURLRequest category for sending multipart/mixed (i.e.batch) request to servers that can handle them (i.e. Google Cloud Storage, .NET Web API, UCWA, OData). To use, just create your request to the batch endpoint and add your batched requests to it using the addPart: method.
//
// NSMutableURLRequest+MultipartBatch.h
//
// Created by Rob Booth on 1/17/14.
//
#import <Foundation/Foundation.h>
@interface NSMutableURLRequest (MultipartBatch)
- (NSString *)multipartRequestBody;
- (void)addPart:(NSURLRequest *)request;
@end
//
// NSMutableURLRequest+MultipartBatch.m
//
// Created by Rob Booth on 1/17/14.
//
#import "NSMutableURLRequest+MultipartBatch.h"
static NSString * prefix = @"X-MultipartBatch-";
@implementation NSMutableURLRequest (MultipartBatch)
- (NSString *)boundary
{
if ([[self.allHTTPHeaderFields allKeys] containsObject:@"Content-Type"] == NO)
return nil;
NSString * contentType = (NSString *)[self.allHTTPHeaderFields objectForKey:@"Content-Type"];
NSArray * contentTypeArray = [contentType componentsSeparatedByString:@"boundary="];
if (contentTypeArray.count != 2)
return nil;
NSString * boundary = contentTypeArray[1];
return [boundary stringByReplacingOccurrencesOfString:@"\"" withString:@""];
}
- (void)addPart:(NSURLRequest *)request
{
NSString * boundary = self.boundary;
NSString * mimeType = @"multipart/mixed";
NSString * contentType = @"application/http; msgtype=request";
if (boundary == nil)
{
CFUUIDRef uuid = CFUUIDCreate(nil);
boundary = CFBridgingRelease(CFUUIDCreateString(nil, uuid));
boundary = boundary.lowercaseString;
CFRelease(uuid);
[self addValue:[NSString stringWithFormat:@"%@; type=\"%@\"; boundary=\"%@\"", mimeType, contentType, boundary] forHTTPHeaderField:@"Content-Type"];
}
NSMutableURLRequest * mutableRequest = [request mutableCopy];
[mutableRequest addValue:contentType forHTTPHeaderField:[prefix stringByAppendingString:@"Content-Type"]];
[mutableRequest addValue:[NSString stringWithFormat:@"<%p>", mutableRequest] forHTTPHeaderField:[prefix stringByAppendingString:@"Content-ID"]];
NSString * finalBoundary = [NSString stringWithFormat:@"--%@--\r\n", boundary];
NSString * body = [[NSString alloc] initWithData:self.HTTPBody encoding:NSUTF8StringEncoding];
// Strip final boundary
body = [body stringByReplacingOccurrencesOfString:finalBoundary withString:@""];
body = [body stringByAppendingString:[NSString stringWithFormat:@"--%@\r\n%@", boundary, mutableRequest.multipartRequestBody]];
// Add final boundary
body = [body stringByAppendingString:finalBoundary];
self.HTTPBody = [body dataUsingEncoding:NSUTF8StringEncoding];
}
- (NSString *)multipartRequestBody
{
NSString * multipartHeader = @"";
NSString * requestHeaders = @"";
NSString * requestBody = [[NSString alloc] initWithData:self.HTTPBody encoding:NSUTF8StringEncoding];
for (NSString * key in [self.allHTTPHeaderFields allKeys])
{
if ([key hasPrefix:prefix])
{
multipartHeader = [multipartHeader stringByAppendingString:[NSString stringWithFormat:@"%@: %@\r\n", [key stringByReplacingOccurrencesOfString:prefix withString:@""], [self.allHTTPHeaderFields objectForKey:key]]];
continue;
}
requestHeaders = [requestHeaders stringByAppendingString:[NSString stringWithFormat:@"%@: %@\r\n", key, [self.allHTTPHeaderFields objectForKey:key]]];
}
NSString * queryString = @"";
if (self.URL.query.length > 0)
queryString = [NSString stringWithFormat:@"?%@", self.URL.query];
/*
multipartHeader
method path(?queryString) HTTP/1.1
Host: hostname
headers
body
*/
return [NSString stringWithFormat:@"%@\r\n%@ %@%@ HTTP/1.1\r\nHost: %@\r\n%@\r\n%@\r\n", multipartHeader, self.HTTPMethod, self.URL.path, queryString, self.URL.host, requestHeaders, requestBody];
}
@end
@sstadelman
Copy link

Lifesaver... can this be used under MIT or Apache2 terms?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment