ObjFW  Check-in [bd6dd6dd00]

Overview
Comment:OFURI: Make query items an array of pairs

With a dictionary the order is lost and keys cannot exist more than
once.

Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: bd6dd6dd00ae565ca306dcb751d63e968f1969aaa1831e4c7022b635c9fdbcbd
User & Date: js on 2022-09-29 21:53:01
Other Links: manifest | tags
Context
2022-09-29
22:08
Fix tests on Nintendo consoles & PSP check-in: 01199db504 user: js tags: trunk
21:53
OFURI: Make query items an array of pairs check-in: bd6dd6dd00 user: js tags: trunk
21:26
OFException: Provide stack trace addresses check-in: f93fae010f user: js tags: trunk
Changes

Modified src/OFMutableURI.h from [c337456a13] to [361cff56c9].

142
143
144
145
146
147
148
149

150
151
152

153
154
155
156
157




158
159
160
161
162

163
164
165
166
167
168
169
142
143
144
145
146
147
148

149
150
151

152
153




154
155
156
157
158
159
160
161

162
163
164
165
166
167
168
169







-
+


-
+

-
-
-
-
+
+
+
+




-
+







 * @throw OFInvalidFormatException The query being set is not in the correct
 *				   format
 */
@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic)
    OFString *percentEncodedQuery;

/**
 * @brief The query part of the URI as a dictionary.
 * @brief The query part of the URI as an array.
 *
 * For example, a query like `key1=value1&key2=value2` would correspond to the
 * following dictionary:
 * following array:
 *
 *     @{
 *         @"key1": @"value1",
 *         @"key2": @"value2"
 *     }
 *     @[
 *         [OFPair pairWithFirstObject: @"key1" secondObject: @"value1"],
 *         [OFPair pairWithFirstObject: @"key2" secondObject: @"value2"],
 *     ]
 *
 * @throw OFInvalidFormatException The query is not in the correct format
 */
@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic)
    OFDictionary OF_GENERIC(OFString *, OFString *) *queryDictionary;
    OFArray OF_GENERIC(OFPair OF_GENERIC(OFString *, OFString *) *) *queryItems;

/**
 * @brief The fragment part of the URI.
 */
@property OF_NULLABLE_PROPERTY (readwrite, copy, nonatomic) OFString *fragment;

/**

Modified src/OFMutableURI.m from [963a0a611c] to [a21b779d5d].

18
19
20
21
22
23
24

25
26
27
28
29
30
31
32
33

34
35
36
37
38
39
40
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

34
35
36
37
38
39
40
41







+








-
+







#import "OFMutableURI.h"
#import "OFArray.h"
#import "OFDictionary.h"
#ifdef OF_HAVE_FILES
# import "OFFileManager.h"
#endif
#import "OFNumber.h"
#import "OFPair.h"
#import "OFString.h"

#import "OFInvalidFormatException.h"

@implementation OFMutableURI
@dynamic scheme, percentEncodedScheme, host, percentEncodedHost, port, user;
@dynamic percentEncodedUser, password, percentEncodedPassword, path;
@dynamic percentEncodedPath, pathComponents, query, percentEncodedQuery;
@dynamic queryDictionary, fragment, percentEncodedFragment;
@dynamic queryItems, fragment, percentEncodedFragment;

+ (instancetype)URI
{
	return [[[self alloc] init] autorelease];
}

- (void)setScheme: (OFString *)scheme
231
232
233
234
235
236
237
238
239



240
241
242
243
244
245

246
247

248
249
250
251
252
253
254
255
256
257
258

259

260
261

262
263

264
265
266
267
268
269
270

271
272
273
274
275
276
277
232
233
234
235
236
237
238


239
240
241
242
243
244

245

246
247

248
249
250
251
252
253
254
255


256
257
258

259


260
261

262
263
264
265
266
267
268

269
270
271
272
273
274
275
276







-
-
+
+
+



-

-
+

-
+







-
-


+
-
+
-
-
+

-
+






-
+







		    [OFCharacterSet URIQueryAllowedCharacterSet]);

	old = _percentEncodedQuery;
	_percentEncodedQuery = [percentEncodedQuery copy];
	[old release];
}

- (void)setQueryDictionary:
    (OFDictionary OF_GENERIC(OFString *, OFString *) *)dictionary
- (void)setQueryItems:
    (OFArray OF_GENERIC(OFPair OF_GENERIC(OFString *, OFString *) *) *)
    queryItems
{
	void *pool;
	OFMutableString *percentEncodedQuery;
	OFEnumerator OF_GENERIC(OFString *) *keyEnumerator, *objectEnumerator;
	OFCharacterSet *characterSet;
	OFString *key, *object, *old;
	OFString *old;

	if (dictionary == nil) {
	if (queryItems == nil) {
		[_percentEncodedQuery release];
		_percentEncodedQuery = nil;
		return;
	}

	pool = objc_autoreleasePoolPush();
	percentEncodedQuery = [OFMutableString string];
	keyEnumerator = [dictionary keyEnumerator];
	objectEnumerator = [dictionary objectEnumerator];
	characterSet = [OFCharacterSet URIQueryKeyValueAllowedCharacterSet];

	for (OFPair OF_GENERIC(OFString *, OFString *) *item in queryItems) {
	while ((key = [keyEnumerator nextObject]) != nil &&
		OFString *key = [item.firstObject
	    (object = [objectEnumerator nextObject]) != nil) {
		key = [key stringByAddingPercentEncodingWithAllowedCharacters:
		    stringByAddingPercentEncodingWithAllowedCharacters:
		    characterSet];
		object = [object
		OFString *value = [item.secondObject
		    stringByAddingPercentEncodingWithAllowedCharacters:
		    characterSet];

		if (percentEncodedQuery.length > 0)
			[percentEncodedQuery appendString: @"&"];

		[percentEncodedQuery appendFormat: @"%@=%@", key, object];
		[percentEncodedQuery appendFormat: @"%@=%@", key, value];
	}

	old = _percentEncodedQuery;
	_percentEncodedQuery = [percentEncodedQuery copy];
	[old release];

	objc_autoreleasePoolPop(pool);

Modified src/OFURI.h from [4aa8c42360] to [ef45469449].

18
19
20
21
22
23
24

25
26
27
28
29
30
31
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32







+







#import "OFSerialization.h"

OF_ASSUME_NONNULL_BEGIN

@class OFArray OF_GENERIC(ObjectType);
@class OFDictionary OF_GENERIC(KeyType, ObjectType);
@class OFNumber;
@class OFPair OF_GENERIC(FirstType, SecondType);
@class OFString;

/**
 * @class OFURI OFURI.h ObjFW/OFURI.h
 *
 * @brief A class for parsing URIs and accessing parts of it.
 */
126
127
128
129
130
131
132
133

134
135
136

137
138
139
140
141




142
143
144
145
146

147
148
149
150
151
152
153
127
128
129
130
131
132
133

134
135
136

137
138




139
140
141
142
143
144
145
146

147
148
149
150
151
152
153
154







-
+


-
+

-
-
-
-
+
+
+
+




-
+







/**
 * @brief The query part of the URI in percent-encoded form.
 */
@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic)
    OFString *percentEncodedQuery;

/**
 * @brief The query part of the URI as a dictionary.
 * @brief The query part of the URI as an array.
 *
 * For example, a query like `key1=value1&key2=value2` would correspond to the
 * following dictionary:
 * following array:
 *
 *     @{
 *         @"key1": @"value1",
 *         @"key2": @"value2"
 *     }
 *     @[
 *         [OFPair pairWithFirstObject: @"key1" secondObject: @"value1"],
 *         [OFPair pairWithFirstObject: @"key2" secondObject: @"value2"],
 *     ]
 *
 * @throw OFInvalidFormatException The query is not in the correct format
 */
@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic)
    OFDictionary OF_GENERIC(OFString *, OFString *) *queryDictionary;
    OFArray OF_GENERIC(OFPair OF_GENERIC(OFString *, OFString *) *) *queryItems;

/**
 * @brief The fragment part of the URI.
 */
@property OF_NULLABLE_PROPERTY (readonly, copy, nonatomic) OFString *fragment;

/**

Modified src/OFURI.m from [f31f144d07] to [bd23469364].

23
24
25
26
27
28
29

30
31
32
33
34
35
36
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37







+







#import "OFDictionary.h"
#ifdef OF_HAVE_FILES
# import "OFFileManager.h"
# import "OFFileURIHandler.h"
#endif
#import "OFNumber.h"
#import "OFOnce.h"
#import "OFPair.h"
#import "OFString.h"
#import "OFXMLElement.h"

#import "OFInvalidArgumentException.h"
#import "OFInvalidFormatException.h"
#import "OFOutOfMemoryException.h"

1037
1038
1039
1040
1041
1042
1043
1044

1045
1046
1047
1048


1049
1050
1051
1052
1053
1054
1055

1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068

1069

1070
1071
1072
1073
1074
1075
1076
1038
1039
1040
1041
1042
1043
1044

1045
1046
1047
1048

1049
1050
1051
1052
1053
1054
1055
1056

1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071

1072
1073
1074
1075
1076
1077
1078
1079







-
+



-
+
+






-
+













+
-
+







}

- (OFString *)percentEncodedQuery
{
	return _percentEncodedQuery;
}

- (OFDictionary OF_GENERIC(OFString *, OFString *) *)queryDictionary
- (OFArray OF_GENERIC(OFPair OF_GENERIC(OFString *, OFString *) *) *)queryItems
{
	void *pool;
	OFArray OF_GENERIC(OFString *) *pairs;
	OFMutableDictionary OF_GENERIC(OFString *, OFString *) *ret;
	OFMutableArray OF_GENERIC(OFPair OF_GENERIC(OFString *, OFString *) *)
	    *ret;

	if (_percentEncodedQuery == nil)
		return nil;

	pool = objc_autoreleasePoolPush();
	pairs = [_percentEncodedQuery componentsSeparatedByString: @"&"];
	ret = [OFMutableDictionary dictionaryWithCapacity: pairs.count];
	ret = [OFMutableArray arrayWithCapacity: pairs.count];

	for (OFString *pair in pairs) {
		OFArray *parts = [pair componentsSeparatedByString: @"="];
		OFString *name, *value;

		if (parts.count != 2)
			@throw [OFInvalidFormatException exception];

		name = [[parts objectAtIndex: 0]
		    stringByRemovingPercentEncoding];
		value = [[parts objectAtIndex: 1]
		    stringByRemovingPercentEncoding];

		[ret addObject: [OFPair pairWithFirstObject: name
		[ret setObject: value forKey: name];
					       secondObject: value]];
	}

	[ret makeImmutable];
	[ret retain];

	objc_autoreleasePoolPop(pool);

Modified tests/OFURITests.m from [66101ddcf7] to [5a6871bef0].

169
170
171
172
173
174
175
176
177
178
179




180
181
182
183
184
185
186
169
170
171
172
173
174
175




176
177
178
179
180
181
182
183
184
185
186







-
-
-
-
+
+
+
+







	    [[[OFURI URIWithString: @"http://host/foo/"]
	    lastPathComponent] isEqual: @"foo"] &&
	    [[[OFURI URIWithString: @"http://host/"]
	    lastPathComponent] isEqual: @"/"] &&
	    [URI5.lastPathComponent isEqual: @"foo/bar"])
	TEST(@"-[query]",
	    [URI1.query isEqual: @"que#ry=1&f&oo=b=ar"] && URI4.query == nil)
	TEST(@"-[queryDictionary]",
	    [URI1.queryDictionary isEqual:
	    [OFDictionary dictionaryWithKeysAndObjects:
	    @"que#ry", @"1", @"f&oo", @"b=ar", nil]]);
	TEST(@"-[queryItems]",
	    [URI1.queryItems isEqual: [OFArray arrayWithObjects:
	    [OFPair pairWithFirstObject: @"que#ry" secondObject: @"1"],
	    [OFPair pairWithFirstObject: @"f&oo" secondObject: @"b=ar"], nil]]);
	TEST(@"-[fragment]",
	    [URI1.fragment isEqual: @"frag#ment"] && URI4.fragment == nil)

	TEST(@"-[copy]", R(URI4 = [[URI1 copy] autorelease]))

	TEST(@"-[isEqual:]", [URI1 isEqual: URI4] && ![URI2 isEqual: URI3] &&
	    [[OFURI URIWithString: @"HTTP://bar/"] isEqual: URI3])
285
286
287
288
289
290
291
292
293
294
295
296





297
298
299
300
301
302
303
285
286
287
288
289
290
291





292
293
294
295
296
297
298
299
300
301
302
303







-
-
-
-
-
+
+
+
+
+







	    [mutableURI.query isEqual: @"que/ry?#"])

	EXPECT_EXCEPTION(
	    @"-[setPercentEncodedQuery:] with invalid characters fails",
	    OFInvalidFormatException,
	    mutableURI.percentEncodedQuery = @"`")

	TEST(@"-[setQueryDictionary:]",
	    (mutableURI.queryDictionary =
	    [OFDictionary dictionaryWithKeysAndObjects:
	    @"foo&bar", @"baz=qux", @"f=oobar", @"b&azqux", nil]) &&
	    [mutableURI.percentEncodedQuery isEqual:
	TEST(@"-[setQueryItems:]",
	    (mutableURI.queryItems = [OFArray arrayWithObjects:
	    [OFPair pairWithFirstObject: @"foo&bar" secondObject: @"baz=qux"],
	    [OFPair pairWithFirstObject: @"f=oobar" secondObject: @"b&azqux"],
	    nil]) && [mutableURI.percentEncodedQuery isEqual:
	    @"foo%26bar=baz%3Dqux&f%3Doobar=b%26azqux"])

	TEST(@"-[setFragment:]",
	    (mutableURI.fragment = @"frag/ment?#") &&
	    [mutableURI.percentEncodedFragment isEqual: @"frag/ment?%23"])

	TEST(@"-[setPercentEncodedFragment:]",