Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
277e1c8
Lovely pair of APIs for retrieving URL query components
mikeabdullah Jul 23, 2013
beb5051
Merge branch 'master' into query-parameters
mikeabdullah Jul 24, 2013
e2adee3
Test empty keys and values
mikeabdullah Jul 24, 2013
169b7af
Redeclare queryParameters as a @property
mikeabdullah Jul 24, 2013
3a292f8
Make .queryParameters readwrite
mikeabdullah Jul 24, 2013
4d1b37a
Merge branch 'master' into query-parameters
mikeabdullah Jul 24, 2013
2e84a04
Flesh out query encoding tests
mikeabdullah Jul 24, 2013
8f8aaeb
Introduce KSURLComponentsQueryParameterDecodingOptions
mikeabdullah Oct 15, 2013
ca18a68
Enumeration block shouldn't be null
mikeabdullah Oct 15, 2013
b7ddc9a
Break apart .queryParameters property to take options too
mikeabdullah Oct 15, 2013
aee6264
Test + as space decoding option
mikeabdullah Oct 15, 2013
014f612
Fix copy & paste mistake
mikeabdullah Oct 15, 2013
568ebd4
Merge branch 'master' into query-parameters
mikeabdullah Oct 15, 2013
9e66e35
Remove options argument from query parameter setter for now
mikeabdullah Oct 15, 2013
461ab89
Bring KSMailtoURLs into the test target
mikeabdullah Oct 15, 2013
571ac44
Merge branch 'master' into query-parameters
mikeabdullah Oct 15, 2013
4432ec7
Remove reference to options argument
mikeabdullah Oct 15, 2013
c0d52f1
Merge branch 'master' into query-parameters
mikeabdullah Dec 9, 2013
7cb488d
Make query handling a category
mikeabdullah Dec 9, 2013
e276c85
remove redundant #prama mark
mikeabdullah Dec 12, 2013
bfa162a
Try a KSURLQuery class
mikeabdullah Dec 12, 2013
ad69038
Internally hand off KSURLComponents' query parameter handling to KSUR…
mikeabdullah Dec 12, 2013
2b0b248
Note logic behind resolving
mikeabdullah Dec 12, 2013
5d7c907
Use correct constant
mikeabdullah Dec 12, 2013
ff59e75
Switch over to CFURL for query retrieval instead of KSURLComponents
mikeabdullah Dec 12, 2013
b368f47
Shift tests over to KSURLQuery
mikeabdullah Dec 12, 2013
eedaeac
Make percentEncodedString atomic
mikeabdullah Dec 12, 2013
5791ca6
Make KSURLComponents.percentEncodedQuery readwrite
mikeabdullah Dec 12, 2013
2b6d302
+[KSURLQuery encodeParameters:] convenience
mikeabdullah Dec 12, 2013
0258ca5
Start document KSURLQuery better
mikeabdullah Dec 12, 2013
ecbbaae
Remove query parameter handling from KSURLComponents
mikeabdullah Dec 12, 2013
e626860
Document .percentEncodedString
mikeabdullah Dec 12, 2013
aa1fc5a
Correct constant
mikeabdullah Dec 12, 2013
1dd74aa
-addParameter:value: method for building up queries pice-by-piece
mikeabdullah Dec 12, 2013
f524b89
Reimplement -setParameters: to use -addParameter:value:
mikeabdullah Dec 12, 2013
17e8d3e
Publish -initWithPercentEncodedString: too
mikeabdullah Dec 12, 2013
560b800
Add +parametersOfPercentEncodedQuery:options: convenience too
mikeabdullah Dec 12, 2013
a67b23e
Remove +queryWithPercentEncodedString:
mikeabdullah Dec 12, 2013
3d756b0
Deprecate KSURLQueryUtilities in favour of KSURLQuery
mikeabdullah Dec 12, 2013
3d3831a
Switch KSMailtoURLs over to use KSURLQuery
mikeabdullah Dec 12, 2013
ac1b545
Deprecate NSString (KSURLQueryUtilities) too
mikeabdullah Dec 12, 2013
6c495f8
Simplify API to +decodeString:options:
mikeabdullah Dec 13, 2013
0a5397f
Remove #import of KSURLQuery
mikeabdullah Dec 14, 2013
e710102
Adopt block-based enumeration internally
mikeabdullah Dec 15, 2013
ab245ae
Document -setParameters:' lack of ordering
mikeabdullah Dec 15, 2013
d806293
Support encoding arbitrary objects for values
mikeabdullah Dec 15, 2013
ca6868a
-setParameters: encodes in alphabetical order
mikeabdullah Dec 16, 2013
1bb3260
Test file:/// URLs briefly
mikeabdullah Aug 19, 2014
c84e76b
Handle file:/// URLs specially
mikeabdullah Aug 19, 2014
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions KSFileUtilities.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
27A90103165C003A00D23C4B /* nameprep.c in Sources */ = {isa = PBXBuildFile; fileRef = 27A90101165C003A00D23C4B /* nameprep.c */; };
27A90106165C005700D23C4B /* puny.c in Sources */ = {isa = PBXBuildFile; fileRef = 27A90104165C005600D23C4B /* puny.c */; };
27DA2577148E641100209E50 /* TestKSURLUtilities.m in Sources */ = {isa = PBXBuildFile; fileRef = 27DA2576148E641100209E50 /* TestKSURLUtilities.m */; };
27DC29041859BC2C0089D717 /* KSURLQuery.m in Sources */ = {isa = PBXBuildFile; fileRef = 27DC29031859BC2C0089D717 /* KSURLQuery.m */; };
27F0501C178829220019FC07 /* KSURLComponents.m in Sources */ = {isa = PBXBuildFile; fileRef = 27F0501B178829180019FC07 /* KSURLComponents.m */; };
27F0501E1788399E0019FC07 /* TestKSURLComponents.m in Sources */ = {isa = PBXBuildFile; fileRef = 27F0501D1788399E0019FC07 /* TestKSURLComponents.m */; };
27F86FBF164FBA9D003608CC /* KSEncodeURLString.m in Sources */ = {isa = PBXBuildFile; fileRef = 27F86FBE164FBA9D003608CC /* KSEncodeURLString.m */; };
Expand Down Expand Up @@ -50,6 +51,8 @@
27A90104165C005600D23C4B /* puny.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = puny.c; path = IFUnicodeURL/IDNSDK/puny.c; sourceTree = "<group>"; };
27A90105165C005700D23C4B /* puny.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = puny.h; path = IFUnicodeURL/IDNSDK/puny.h; sourceTree = "<group>"; };
27DA2576148E641100209E50 /* TestKSURLUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TestKSURLUtilities.m; sourceTree = "<group>"; };
27DC29021859BC2C0089D717 /* KSURLQuery.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KSURLQuery.h; sourceTree = SOURCE_ROOT; };
27DC29031859BC2C0089D717 /* KSURLQuery.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KSURLQuery.m; sourceTree = SOURCE_ROOT; };
27F0501A178829180019FC07 /* KSURLComponents.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = KSURLComponents.h; sourceTree = SOURCE_ROOT; };
27F0501B178829180019FC07 /* KSURLComponents.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = KSURLComponents.m; sourceTree = SOURCE_ROOT; };
27F0501D1788399E0019FC07 /* TestKSURLComponents.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TestKSURLComponents.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -124,6 +127,8 @@
27246F10165BF1D2001B638E /* IFUnicodeURL */,
27F0501A178829180019FC07 /* KSURLComponents.h */,
27F0501B178829180019FC07 /* KSURLComponents.m */,
27DC29021859BC2C0089D717 /* KSURLQuery.h */,
27DC29031859BC2C0089D717 /* KSURLQuery.m */,
27422A77180D609B00136F43 /* KSMailtoURLs.h */,
27422A78180D609B00136F43 /* KSMailtoURLs.m */,
27F86FBD164FBA9D003608CC /* KSEncodeURLString.h */,
Expand Down Expand Up @@ -296,6 +301,7 @@
EE43C85213898D7B008ABD16 /* KSWebLocation.m in Sources */,
EE43C85313898D7B008ABD16 /* KSWebLocationPasteboardUtilities.m in Sources */,
27F0501E1788399E0019FC07 /* TestKSURLComponents.m in Sources */,
27DC29041859BC2C0089D717 /* KSURLQuery.m in Sources */,
27F0501C178829220019FC07 /* KSURLComponents.m in Sources */,
EE43C85413898D7B008ABD16 /* KSWorkspaceUtilities.m in Sources */,
27DA2577148E641100209E50 /* TestKSURLUtilities.m in Sources */,
Expand Down
6 changes: 3 additions & 3 deletions KSMailtoURLs.m
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@

#import "KSMailtoURLs.h"

#import "KSURLQueryUtilities.h"
#import "KSURLQuery.h"


NSString *KSURLMailtoScheme = @"mailto";
Expand All @@ -52,7 +52,7 @@ + (NSURL *)ks_mailtoURLWithEmailAddress:(NSString *)address headerLines:(NSDicti

if (headers)
{
NSString *query = [self ks_queryWithParameters:headers];
NSString *query = [KSURLQuery encodeParameters:headers];
if ([query length])
{
string = [string stringByAppendingFormat:@"?%@", query];
Expand All @@ -72,7 +72,7 @@ - (NSDictionary *)ks_mailHeaderLines;
if (queryIndicatorRange.location != NSNotFound)
{
NSString *query = [urlString substringFromIndex:NSMaxRange(queryIndicatorRange)];
return [NSURL ks_parametersOfQuery:query];
return [KSURLQuery decodeString:query options:0];
}

return nil;
Expand Down
6 changes: 3 additions & 3 deletions KSURLComponents.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

#import <Foundation/Foundation.h>


@interface KSURLComponents : NSObject <NSCopying>
{
@private
Expand Down Expand Up @@ -117,13 +118,12 @@
@property (nonatomic, copy) NSString *query;
@property (nonatomic, copy) NSString *fragment;

// Getting these properties retains any percent encoding these components may have. Setting these properties is currently not supported as I am lazy and doing so is rarely useful. If you do have a use case, please send me a pull request or file an issue on GitHub.
// Getting these properties retains any percent encoding these components may have. Setting most of these properties is currently not supported as I am lazy and doing so is rarely useful. If you do have a use case, please send me a pull request or file an issue on GitHub.
@property (nonatomic, copy, readonly) NSString *percentEncodedUser;
@property (nonatomic, copy, readonly) NSString *percentEncodedPassword;
@property (nonatomic, copy, readonly) NSString *percentEncodedHost;
@property (nonatomic, copy, readonly) NSString *percentEncodedPath;
@property (nonatomic, copy, readonly) NSString *percentEncodedQuery;
@property (nonatomic, copy) NSString *percentEncodedQuery;
@property (nonatomic, copy, readonly) NSString *percentEncodedFragment;


@end
7 changes: 6 additions & 1 deletion KSURLComponents.m
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ @interface KSURLComponents ()
@property (nonatomic, copy, readwrite) NSString *percentEncodedPassword;
@property (nonatomic, copy, readwrite) NSString *percentEncodedHost;
@property (nonatomic, copy, readwrite) NSString *percentEncodedPath;
@property (nonatomic, copy, readwrite) NSString *percentEncodedQuery;
@property (nonatomic, copy, readwrite) NSString *percentEncodedFragment;
@end

Expand Down Expand Up @@ -447,6 +446,12 @@ - (void)setPath:(NSString *)path;
}

@synthesize percentEncodedQuery = _queryComponent;
- (void)setPercentEncodedQuery:(NSString *)percentEncodedQuery;
{
// FIXME: Check the query is valid
percentEncodedQuery = [percentEncodedQuery copy];
[_queryComponent release]; _queryComponent = percentEncodedQuery;
}
- (NSString *)query;
{
return [self.percentEncodedQuery stringByReplacingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
Expand Down
119 changes: 119 additions & 0 deletions KSURLQuery.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
//
// KSURLQuery.h
// KSFileUtilities
//
// Created by Mike on 12/12/2013.
// Copyright (c) 2013 Karelia Software. All rights reserved.
//

#import <Foundation/Foundation.h>


typedef NS_OPTIONS(NSUInteger, KSURLQueryParameterDecodingOptions) {
KSURLQueryParameterDecodingPlusAsSpace = 1UL << 0, // + characters are interpreted as spaces, rather than regular + symbols
};


@interface KSURLQuery : NSObject
{
@private
NSString *_percentEncodedString;
}

#pragma mark Convenience
+ (NSString *)encodeParameters:(NSDictionary *)parameters;
+ (NSDictionary *)decodeString:(NSString *)percentEncodedQuery options:(KSURLQueryParameterDecodingOptions)options;
+ (NSDictionary *)parametersFromURL:(NSURL *)url options:(KSURLQueryParameterDecodingOptions)options;


#pragma mark Creating a KSURLQuery
+ (instancetype)queryWithURL:(NSURL *)url;
- initWithPercentEncodedString:(NSString *)string;


#pragma mark Decoding Parameters

/**
Converts the query into a dictionary representation.

For example:

http://example.com?key=value&foo=bar

can be interpreted as:

@{ @"key" : @"value", @"foo" : @"bar" }

Keys and values are percent decoded according to `options`.

If you have a query which doesn't match `NSDictionary`'s design, drop down to
the primitive `-enumerateParametersWithOptions:usingBlock:` method instead.

@param options A mask that specifies options for parameter decoding.
@return `nil` if query doesn't neatly fit an `NSDictionary` representation
*/
- (NSDictionary *)parametersWithOptions:(KSURLQueryParameterDecodingOptions)options;

/**
Enumerates the receiver's parameters, handling cases where an NSDictionary representation doesn't suffice.

* Parameters are reported in the order they appear in the URL
* Keys and values are percent decoded for your convenience
* Parameters without a value are reported as `nil`
* Duplicate parameters are correctly reported too

@param options A mask that specifies options for parameter decoding.
@param block A block called for each parameter of the query.
*/
- (void)enumerateParametersWithOptions:(KSURLQueryParameterDecodingOptions)options usingBlock:(void (^)(NSString *key, NSString *value, BOOL *stop))block __attribute((nonnull(2)));


#pragma mark Encoding Parameters

/**
Replaces any existing query by encoding the `parameters` dictionary.

For example:

@{ @"key" : @"value", @"foo" : @"bar" }

can be represented as:

http://example.com?key=value&foo=bar

See `-addParameter:value:` for full details on encoding of keys and values.

Parameters are encoded in alphabetical order (of keys) for consistency across
platforms and OS releases. If ordering is important to your use case, or you
particularly need to eke out a little more performance, use `-addParameter:value:`
directly instead.

@param parameters A dictionary to encode, whose keys and values are all strings.
*/
- (void)setParameters:(NSDictionary *)parameters;

/**
Adds an extra parameter to end of the receiver.

Enables the query to be built up piece-by-piece. This can be especially useful
when the ordering of parameters is critical, and/or parameters appear more than
once.

Both the key and value are percent encoded.

`value` is sent a `-description` message to obtain a string representation
suitable for encoding, enabling objects like `NSNumber`s to be easily encoded,
as well as strings.
*/
- (void)addParameter:(NSString *)key value:(id <NSObject>)value __attribute((nonnull(1)));

/**
@result The encoded representation of the receiver.

Generally you then pass the result of this method to `NSURLComponents.percentEncodedQuery`
(or `KSURLComponents`) to build up a full URL.
*/
@property(atomic, readonly, copy) NSString *percentEncodedString;


@end
Loading