Permalink
Browse files

Adding new BS3Request

  • Loading branch information...
1 parent bc99922 commit e768da4725fcd15f1270ce9de1bf71cafb34fe58 @stevedekorte stevedekorte committed Oct 8, 2012
Showing with 232 additions and 0 deletions.
  1. BIN S3Kit/S3Kit/.DS_Store
  2. +46 −0 S3Kit/S3Kit/BS3Request.h
  3. +186 −0 S3Kit/S3Kit/BS3Request.m
View
Binary file not shown.
@@ -0,0 +1,46 @@
+//
+// BS3Request.h
+// BS3Request
+//
+// Created by Brandon Smith on 7/15/12.
+// Copyright (c) 2012 TokenGnome. All rights reserved.
+//
+// @param bucketName The name of the bucket to perform the request on or nil
+// @param resourcePath The path to the resouce targeted by the request.
+// @param params The dictionary of special request parameters to use
+// @see http://docs.amazonwebservices.com/AmazonS3/latest/API/RESTBucketGET.html#RESTBucketGET-requests-request-parameters
+// @param accessKey The Amazon AWS access key to be used to sign the request
+// @param secretKey The Amazon AWS secret key to be used to sign the request
+// @return a newly initialized NSURLRequest subclass with a signed URL
+
+
+#import <Foundation/Foundation.h>
+
+@interface BS3Request : NSMutableURLRequest
+{
+}
+
+@property (nonatomic, retain) NSDate *date;
+@property (nonatomic, retain) NSString *bucketName;
+@property (nonatomic, retain) NSString *resourcePath;
+@property (nonatomic, retain) NSString *accessKey;
+@property (nonatomic, retain) NSString *secretKey;
+
+@property (nonatomic, retain) NSMutableDictionary *parameters;
+@property (assign) Class requestClass;
+@property (assign) BOOL usesSSL;
+
+
+// Computes and sets the authorization header based on the the
+// HTTP method of, MD5 hash of the HTTP body, etc.
+// so don't change those after set up
+
+- (NSString *)stringToSign;
+- (NSString *)authorizationHeader;
+
+- (NSMutableURLRequest *)composedRequest;
+- (NSMutableURLRequest *)signedRequest;
+
+- (void)show;
+
+@end
@@ -0,0 +1,186 @@
+//
+// BS3Request.m
+// BS3Request
+//
+//
+
+#import "BS3Request.h"
+#import "NSData+Base64.h"
+#import "NSData+MD5.h"
+#import <CommonCrypto/CommonHMAC.h>
+#import "NSString+Crypto.h"
+
+@implementation NSString (URL)
+- (NSString *)urlEncoded;
+@end
+
+@implementation NSString (URL)
+
+- (NSString *)urlEncoded
+{
+ return [[self stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]
+ stringByReplacingOccurrencesOfString:@"+" withString:@"%2B"];
+}
+
+@end
+
+@implementation BS3Request
+
+@synthesize bucketName;
+@synthesize resourcePath;
+@synthesize accessKey;
+@synthesize secretKey;
+
+@synthesize HTTPMethod;
+@synthesize allHTTPHeaderFields;
+@synthesize HTTPBody;
+@synthesize parameters;
+
+@synthesize usesSSL;
+@synthesize date;
+
+- (id)init
+{
+ self = [super init];
+ parameters = [NSMutableDictionary dictionary];
+ HTTPMethod = @"GET";
+ date = [NSDate date];
+ [allHTTPHeaderFields setObject:[self dateHeader] forKey:@"Date"];
+ usesSSL = YES;
+ return self;
+}
+
+//#warning this url encoding doesn't look right
+
++ (NSString *)urlEncodedParameter:(NSString *)parameterValue
+{
+ return [[parameterValue stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]
+ stringByReplacingOccurrencesOfString:@"+" withString:@"%2B"];
+}
+
++ (NSString *)dateHeaderForDate:(NSDate *)date
+{
+ static NSDateFormatter *df = nil;
+ if (!df)
+ {
+ static dispatch_once_t oncePredicate;
+ dispatch_once(&oncePredicate, ^{
+ df = [[NSDateFormatter alloc] init];
+ df.locale = [[NSLocale alloc] initWithLocaleIdentifier:@"en_US"];
+ df.timeZone = [NSTimeZone timeZoneWithAbbreviation:@"GMT"];
+ df.dateFormat = @"EEE',' dd MMM yyyy HH':'mm':'ss '+0000'";
+ });
+ }
+ return [df stringFromDate:date];
+}
+
+
+- (NSString *)stringForParameters
+{
+ if (!parameters || [[parameters allKeys] count] < 1) return @"";
+ static NSSet *validParameters;
+ if (!validParameters)
+ {
+ validParameters = [NSSet setWithObjects:@"delimiter",
+ @"marker",
+ @"max-keys",
+ @"delimiter",
+ @"prefix", nil];
+ }
+
+ NSString *paramStr = @"";
+ for (NSString *key in [parameters allKeys])
+ {
+ paramStr = [validParameters containsObject:key] ?
+ [paramStr stringByAppendingFormat:@"&%@=%@", key, [[parameters objectForKey:key] urlEncoded]] :
+ paramStr;
+ }
+
+ NSLog(@"%@", paramStr);
+
+ return ([paramStr isEqualToString:@""] ?
+ @"" :
+ [paramStr stringByReplacingCharactersInRange:NSMakeRange(0, 1) withString:@""]);
+}
+
+- (NSString *)composedURLString
+{
+ NSString *scheme = usesSSL ? @"https" : @"http";
+
+ //NSString *urlString = [NSString stringWithFormat:@"%@://s3.amazonaws.com/%@%@",
+ // scheme, bucketName, resourcePath];
+
+ NSString *urlString = [NSString stringWithFormat:@"%@://%@.s3.amazonaws.com%@",
+ scheme, bucketName, resourcePath];
+
+ NSString *parameterString = [self stringForParameters];
+
+ if (parameterString.length > 0)
+ {
+ urlString = [urlString stringByAppendingFormat:@"?%@", parameterString];
+ }
+
+ return urlString;
+}
+
+
+- (NSString *)dateHeader
+{
+ return [BS3Request dateHeaderForDate:date];
+}
+
+- (NSString *)stringToSign
+{
+ NSString *contentMd5 = [self.allHTTPHeaderFields objectForKey:@"Content-Md5"];
+ NSString *contentType = [self.allHTTPHeaderFields objectForKey:@"Content-Type"];
+ NSString *dateString = [self.allHTTPHeaderFields objectForKey:@"Date"];
+
+ NSString *result = [NSString stringWithFormat:@""
+ @"%@\n" // HTTP Method
+ @"%@\n" // Content MD5
+ @"%@\n" // Content type
+ @"%@\n" // Date
+ @"%@" // Amazon Canonicalized Headers
+ @"%@", // Amazon Canonicalized Resource
+ self.HTTPMethod,
+ contentMd5 ? contentMd5 : @"",
+ contentType ? contentType : @"",
+ dateString,
+ @"",
+ [NSString stringWithFormat:@"/%@%@", self.bucketName, self.resourcePath]];
+
+ return result;
+}
+
+- (NSString *)authorizationHeader
+{
+ NSData *encryptedStringData = [[self stringToSign] encryptWithKey:secretKey];
+ NSString *authToken = [encryptedStringData base64EncodedString];
+ return [NSString stringWithFormat:@"AWS %@:%@", accessKey, authToken];
+}
+
+- (void)setHTTPBody:(NSData *)body
+{
+ [super setHTTPBody:body];
+ [allHTTPHeaderFields setObject:[HTTPBody md5SignatureBase64] forKey:@"Content-Md5"];
+}
+
+- (void)prepareAndSign
+{
+ NSString *urlString = [self composedURLString];
+ [self setURL:[NSURL URLWithString:urlString]];
+ [request setValue:[self authorizationHeader] forHTTPHeaderField:@"Authorization"];
+}
+
+- (void)show
+{
+ printf("bucketName = %s\n", [bucketName UTF8String]);
+ printf("resourcePath = %s\n", [resourcePath UTF8String]);
+ printf("composedURLString = %s\n", [[self composedURLString] UTF8String]);
+ printf("HTTPMethod = %s\n", [self.HTTPMethod UTF8String]);
+ printf("parameters = %s\n", [[parameters description] UTF8String]);
+ printf("allHTTPHeaderFields = %s\n", [[allHTTPHeaderFields description] UTF8String]);
+ printf("stringToSign = [[%s]]\n", [[self stringToSign] UTF8String]);
+}
+
+@end

0 comments on commit e768da4

Please sign in to comment.