Skip to content
This repository has been archived by the owner on Dec 12, 2019. It is now read-only.

Commit

Permalink
Merge pull request #20 from chillpop/master
Browse files Browse the repository at this point in the history
Handle super long query strings
  • Loading branch information
chillpop committed Jan 12, 2015
2 parents 2aec3d8 + 730b785 commit f2d6e44
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 45 deletions.
18 changes: 18 additions & 0 deletions Example/Tests/HttpFileParsingTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -99,4 +99,22 @@ - (void)testHttpFileHeadersNoBody
XCTAssertEqual(data.length, 0);
}

- (void)testHttpLongQueryFile
{
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://example.com/details?one=1&two=2&three=3&four=4&five=5&six=6&seven=7&eight=8&nine=9&ten=10&eleven=11&twelve=12&thirteen=13&fourteen=14&fifteen=15&sixteen=16&seventeen=17&eighteen=18&nineteen=19&twenty=20&twentyone=21&twntytwo=22&twentythree=23&twentyfour=24&twentyfive=25"]];
NSError *error;
NSHTTPURLResponse *response;
NSData *data = [NSURLConnection sendSynchronousRequest:request
returningResponse:&response
error:&error];
if (!data) {
XCTFail();
return;
}
XCTAssertNil(error);
XCTAssertEqual(response.statusCode, kHTTPStatusCodeAccepted);
XCTAssertEqual(response.allHeaderFields.count, 0);
XCTAssertEqual(data.length, 0);
}

@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
HTTP/1.1 202 Accepted

2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
The MIT License (MIT)

Copyright (c) 2014 VOKAL Interactive
Copyright (c) 2014 Vokal

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
Expand Down
43 changes: 30 additions & 13 deletions MockDataNaming.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ The base name consists of:
- if there is a query string:
- a question mark `?`
- the query string (it is expected that the keys and values in a standard query string will be [percent-encoded](http://en.wikipedia.org/wiki/Percent-encoding) )
- if the percent-encoded query string would make the filename too long for HFS+ (255 character max) the SHA-256 hash of the percent-encoded query string (as a 64-character lower-case hexadecimal string) will be used instead
- if there is a request body:
- a pipe character `|`
- the encoding of the request body, [as described below](#request-body)
Expand All @@ -45,10 +46,10 @@ Otherwise, use the SHA-256 hash of the request body, as a 64-character lower-cas
The request

```
GET /foo/?page=2 HTTP/1.1
Host: example.com
Accept: */*
GET /foo/?page=2 HTTP/1.1
Host: example.com
Accept: */*
```

yields the base name
Expand All @@ -61,11 +62,27 @@ GET|-foo-?page=2
The request

```
POST /login/ HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Content-Length: 42
GET /details?one=1&two=2&three=3&four=4&five=5&six=6&seven=7&eight=8&nine=9&ten=10&eleven=11&twelve=12&thirteen=13&fourteen=14&fifteen=15&sixteen=16&seventeen=17&eighteen=18&nineteen=19&twenty=20&twentyone=21&twntytwo=22&twentythree=23&twentyfour=24&twentyfive=25" HTTP/1.1
Host: example.com
Accept: */*
```

yields the base name
```
GET|-details?fb73ef92daa60d3b526724dd5f50738e8477d10e0edcf96ce79794666f6b0c0e
```

---

The request

```
POST /login/ HTTP/1.1
Host: example.com
Content-Type: application/x-www-form-urlencoded; charset=utf-8
Content-Length: 42
email=user%40example.com&password=password
```

Expand All @@ -83,11 +100,11 @@ POST|-login-|169d720631e603967135cfce10d235e94aac22b87500ea09d1be295f5b300dca
The request

```
POST /login/ HTTP/1.1
Host: example.com
POST /login/ HTTP/1.1
Host: example.com
Content-Type: application/json
Content-Length: 50
Content-Length: 50
{"email":"user@example.com","password":"password"}
```

Expand Down
2 changes: 1 addition & 1 deletion VOKMockUrlProtocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// VOKMockUrlProtocol.h
//
// Created by Isaac Greenspan on 7/31/14.
// Copyright (c) 2014 VOKAL Interactive. All rights reserved.
// Copyright (c) 2014 Vokal. All rights reserved.
//

#import <Foundation/Foundation.h>
Expand Down
63 changes: 37 additions & 26 deletions VOKMockUrlProtocol.m
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// VOKMockUrlProtocol.m
//
// Created by Isaac Greenspan on 7/31/14.
// Copyright (c) 2014 VOKAL Interactive. All rights reserved.
// Copyright (c) 2014 Vokal. All rights reserved.
//

#import "VOKMockUrlProtocol.h"
Expand All @@ -12,6 +12,7 @@
#import <HTTPStatusCodes.h>
#import <HTTPMethods.h>
#import <VOKBenkode.h>
#import <sys/syslimits.h>

#ifndef DLOG
// Define DLOG to log to NSLog when DEBUG is defined
Expand All @@ -30,6 +31,9 @@
static NSString *const HTTPHeaderContentTypeFormUrlencoded = @"application/x-www-form-urlencoded";
static NSString *const HTTPHeaderContentTypeJson = @"application/json";

//255 HFS+ filename limit - 5 for file extension suffix
static NSInteger const MaxBaseFilenameLength = NAME_MAX - 5;

#pragma mark -

@interface VOKMockUrlProtocolResponseAndDataContainer : NSObject
Expand Down Expand Up @@ -88,59 +92,66 @@ - (NSArray *)resourceNames
// Append separator and the path.
[resourceName appendFormat:AppendSeparatorFormat, self.request.URL.path];

NSMutableArray *resourceNames = [NSMutableArray arrayWithObject:resourceName];

// If there's a query string, append ? and the query string.
if (self.request.URL.query) {
[resourceName appendFormat:@"?%@", self.request.URL.query];
NSString *queryFormat = @"?%@";
//take the SHA-256 hash of the query, just in case things get too long later
NSData *queryData = [self.request.URL.query dataUsingEncoding:NSUTF8StringEncoding];
NSString *hashedQuery = [self sha256HexOfData:queryData];
[resourceNames addObject:[[resourceName stringByAppendingFormat:queryFormat, hashedQuery] mutableCopy]];

[resourceName appendFormat:queryFormat, self.request.URL.query];
}

NSArray *resourceNames;

// If the request is one that can have a body...
if ([kHTTPMethodPost isEqualToString:self.request.HTTPMethod]
|| [kHTTPMethodPatch isEqualToString:self.request.HTTPMethod]
|| [kHTTPMethodPut isEqualToString:self.request.HTTPMethod]) {
NSData *bodyData = [self bodyDataFromRequest:self.request];

// Compute the SHA-256 of the body and generate a resource name from that.
NSMutableString *hashResourceName = [resourceName mutableCopy];
[hashResourceName appendFormat:AppendSeparatorFormat, [self sha256HexOfData:bodyData]];
NSString *bodyHash = [self sha256HexOfData:bodyData];

NSString *contentType = [self.request valueForHTTPHeaderField:HTTPHeaderContentType];

NSString *bodyString;
if ([HTTPHeaderContentTypeFormUrlencoded isEqualToString:contentType]) {
// If it's form-URL-encoded, generate a resource name by appending the body as a string.
NSString *bodyString = [[NSString alloc] initWithData:bodyData encoding:NSUTF8StringEncoding];
[resourceName appendFormat:AppendSeparatorFormat, bodyString];
resourceNames = @[ resourceName, hashResourceName, ];
bodyString = [[NSString alloc] initWithData:bodyData encoding:NSUTF8StringEncoding];

} else if ([HTTPHeaderContentTypeJson isEqualToString:contentType]) {
// Otherwise, if it's JSON, generate a resource name by bencoding the JSON datastructure and percent-
// escaping the resulting string.
// Otherwise, if it's JSON, generate a resource name by bencoding the JSON datastructure and
// percent-escaping the resulting string.
NSData *bencoded = [VOKBenkode encode:
[NSJSONSerialization JSONObjectWithData:bodyData
options:NSJSONReadingAllowFragments
error:NULL]];
if (bencoded) {
[resourceName appendFormat:AppendSeparatorFormat,
[[[NSString alloc] initWithData:bencoded encoding:NSUTF8StringEncoding]
stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
resourceNames = @[ resourceName, hashResourceName, ];
} else {
// If the bencode fails (or the JSON-decode fails), just use the hash resource name.
resourceNames = @[ hashResourceName, ];
bodyString = [[NSString alloc] initWithData:bencoded encoding:NSUTF8StringEncoding];
bodyString = [bodyString stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
}

} else {
// Otherwise, just use the hash resource name.
resourceNames = @[ hashResourceName, ];
}

} else {
// Otherwise, the only possible name is what we have so far.
resourceNames = @[ resourceName, ];
NSArray *resourceNamesWithoutBody = [resourceNames copy];
[resourceNames removeAllObjects];
for (NSMutableString *name in resourceNamesWithoutBody) {
if (bodyString) {
[resourceNames addObject:[[name stringByAppendingFormat:AppendSeparatorFormat, bodyString] mutableCopy]];
}
[resourceNames addObject:[[name stringByAppendingFormat:AppendSeparatorFormat, bodyHash] mutableCopy]];
}
}

for (NSMutableString *name in resourceNames) {
for (NSMutableString *name in [resourceNames copy]) {

//test to see if the filename is too long
if (name.length > MaxBaseFilenameLength) {
[resourceNames removeObject:name];
continue;
}

[self replacePathSeparatorsInMutableString:name];
}

Expand Down
8 changes: 4 additions & 4 deletions VOKMockUrlProtocol.podspec
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
Pod::Spec.new do |s|
s.name = "VOKMockUrlProtocol"
s.version = "2.0.0"
s.version = "2.0.1"
s.summary = "A url protocol that parses and returns fake responses with mock data."
s.homepage = "https://github.com/vokalinteractive/VOKMockUrlProtocol"
s.homepage = "https://github.com/vokal/VOKMockUrlProtocol"
s.license = { :type => "MIT", :file => "LICENSE"}
s.author = { "VOKAL Interactive" => "hello@vokalinteractive.com" }
s.source = { :git => "https://github.com/vokalinteractive/VOKMockUrlProtocol.git", :tag => s.version.to_s }
s.author = { "Vokal" => "hello@vokalinteractive.com" }
s.source = { :git => "https://github.com/vokal/VOKMockUrlProtocol.git", :tag => s.version.to_s }

s.platform = :ios, '6.0'
s.requires_arc = true
Expand Down

0 comments on commit f2d6e44

Please sign in to comment.