Browse Source

[settings] Re-add "uristring" setting type

Commit 09b057c ("[settings] Remove "uristring" setting type") removed
support for URI-encoded settings via the "uristring" setting type, on
the basis that such encoding was no longer necessary to avoid problems
with the command line parser.

Other valid use cases for the "uristring" setting type do exist: for
example, a password containing a '/' character expanded via

  chain http://username:${password:uristring}@server.name/boot.php

Restore the existence of the "uristring" setting, avoiding the
potentially large stack allocations that were used in the old code
prior to commit 09b057c ("[settings] Remove "uristring" setting
type").

Requested-by: Robin Smidsrød <robin@smidsrod.no>
Signed-off-by: Michael Brown <mcb30@ipxe.org>
tags/v1.20.1
Michael Brown 9 years ago
parent
commit
ba3695353a
5 changed files with 126 additions and 30 deletions
  1. 33
    5
      src/core/settings.c
  2. 71
    22
      src/core/uri.c
  3. 4
    1
      src/include/ipxe/uri.h
  4. 2
    2
      src/net/tcp/httpcore.c
  5. 16
    0
      src/tests/settings_test.c

+ 33
- 5
src/core/settings.c View File

1666
 	.format = format_string_setting,
1666
 	.format = format_string_setting,
1667
 };
1667
 };
1668
 
1668
 
1669
-/** A URI-encoded string setting type
1669
+/**
1670
+ * Parse URI-encoded string setting value
1670
  *
1671
  *
1671
- * This setting type is obsolete; the name ":uristring" is retained to
1672
- * avoid breaking existing scripts.
1672
+ * @v type		Setting type
1673
+ * @v value		Formatted setting value
1674
+ * @v buf		Buffer to contain raw value
1675
+ * @v len		Length of buffer
1676
+ * @ret len		Length of raw value, or negative error
1673
  */
1677
  */
1678
+static int parse_uristring_setting ( const struct setting_type *type __unused,
1679
+				     const char *value, void *buf, size_t len ){
1680
+
1681
+	return uri_decode ( value, buf, len );
1682
+}
1683
+
1684
+/**
1685
+ * Format URI-encoded string setting value
1686
+ *
1687
+ * @v type		Setting type
1688
+ * @v raw		Raw setting value
1689
+ * @v raw_len		Length of raw setting value
1690
+ * @v buf		Buffer to contain formatted value
1691
+ * @v len		Length of buffer
1692
+ * @ret len		Length of formatted value, or negative error
1693
+ */
1694
+static int format_uristring_setting ( const struct setting_type *type __unused,
1695
+				      const void *raw, size_t raw_len,
1696
+				      char *buf, size_t len ) {
1697
+
1698
+	return uri_encode ( 0, raw, raw_len, buf, len );
1699
+}
1700
+
1701
+/** A URI-encoded string setting type */
1674
 const struct setting_type setting_type_uristring __setting_type = {
1702
 const struct setting_type setting_type_uristring __setting_type = {
1675
 	.name = "uristring",
1703
 	.name = "uristring",
1676
-	.parse = parse_string_setting,
1677
-	.format = format_string_setting,
1704
+	.parse = parse_uristring_setting,
1705
+	.format = format_uristring_setting,
1678
 };
1706
 };
1679
 
1707
 
1680
 /**
1708
 /**

+ 71
- 22
src/core/uri.c View File

39
 #include <ipxe/uri.h>
39
 #include <ipxe/uri.h>
40
 
40
 
41
 /**
41
 /**
42
- * Decode URI field (in place)
42
+ * Decode URI field
43
  *
43
  *
44
- * @v string		String
44
+ * @v encoded		Encoded field
45
+ * @v buf		Data buffer
46
+ * @v len		Length
47
+ * @ret len		Length of data
45
  *
48
  *
46
  * URI decoding can never increase the length of a string; we can
49
  * URI decoding can never increase the length of a string; we can
47
  * therefore safely decode in place.
50
  * therefore safely decode in place.
48
  */
51
  */
49
-static void uri_decode ( char *string ) {
50
-	char *dest = string;
52
+size_t uri_decode ( const char *encoded, void *buf, size_t len ) {
53
+	uint8_t *out = buf;
54
+	unsigned int count = 0;
51
 	char hexbuf[3];
55
 	char hexbuf[3];
52
 	char *hexbuf_end;
56
 	char *hexbuf_end;
53
 	char c;
57
 	char c;
55
 	unsigned int skip;
59
 	unsigned int skip;
56
 
60
 
57
 	/* Copy string, decoding escaped characters as necessary */
61
 	/* Copy string, decoding escaped characters as necessary */
58
-	do {
59
-		c = *(string++);
62
+	while ( ( c = *(encoded++) ) ) {
60
 		if ( c == '%' ) {
63
 		if ( c == '%' ) {
61
-			snprintf ( hexbuf, sizeof ( hexbuf ), "%s", string );
64
+			snprintf ( hexbuf, sizeof ( hexbuf ), "%s", encoded );
62
 			decoded = strtoul ( hexbuf, &hexbuf_end, 16 );
65
 			decoded = strtoul ( hexbuf, &hexbuf_end, 16 );
63
 			skip = ( hexbuf_end - hexbuf );
66
 			skip = ( hexbuf_end - hexbuf );
64
-			string += skip;
67
+			encoded += skip;
65
 			if ( skip )
68
 			if ( skip )
66
 				c = decoded;
69
 				c = decoded;
67
 		}
70
 		}
68
-		*(dest++) = c;
69
-	} while ( c );
71
+		if ( count < len )
72
+			out[count] = c;
73
+		count++;
74
+	}
75
+	return count;
76
+}
77
+
78
+/**
79
+ * Decode URI field in-place
80
+ *
81
+ * @v uri		URI
82
+ * @v field		URI field index
83
+ */
84
+static void uri_decode_inplace ( struct uri *uri, unsigned int field ) {
85
+	const char *encoded = uri_field ( uri, field );
86
+	char *decoded = ( ( char * ) encoded );
87
+	size_t len;
88
+
89
+	/* Do nothing if field is not present */
90
+	if ( ! encoded )
91
+		return;
92
+
93
+	/* Decode field in place */
94
+	len = uri_decode ( encoded, decoded, strlen ( encoded ) );
95
+
96
+	/* Terminate decoded string */
97
+	decoded[len] = '\0';
70
 }
98
 }
71
 
99
 
72
 /**
100
 /**
115
 	 * '%', the full set of characters with significance to the
143
 	 * '%', the full set of characters with significance to the
116
 	 * URL parser is "/#:@?".  We choose for each URI field which
144
 	 * URL parser is "/#:@?".  We choose for each URI field which
117
 	 * of these require escaping in our use cases.
145
 	 * of these require escaping in our use cases.
146
+	 *
147
+	 * For the scheme field (equivalently, if field is zero), we
148
+	 * escape anything that has significance not just for our URI
149
+	 * parser but for any other URI parsers (e.g. HTTP query
150
+	 * string parsers, which care about '=' and '&').
118
 	 */
151
 	 */
119
 	static const char *escaped[URI_FIELDS] = {
152
 	static const char *escaped[URI_FIELDS] = {
120
-		/* Scheme: escape everything */
121
-		[URI_SCHEME]	= "/#:@?",
153
+		/* Scheme or default: escape everything */
154
+		[URI_SCHEME]	= "/#:@?=&",
122
 		/* Opaque part: escape characters which would affect
155
 		/* Opaque part: escape characters which would affect
123
 		 * the reparsing of the URI, allowing everything else
156
 		 * the reparsing of the URI, allowing everything else
124
 		 * (e.g. ':', which will appear in iSCSI URIs).
157
 		 * (e.g. ':', which will appear in iSCSI URIs).
157
 /**
190
 /**
158
  * Encode URI field
191
  * Encode URI field
159
  *
192
  *
160
- * @v uri		URI
161
  * @v field		URI field index
193
  * @v field		URI field index
162
- * @v buf		Buffer to contain encoded string
194
+ * @v raw		Raw data
195
+ * @v raw_len		Length of raw data
196
+ * @v buf		Buffer
163
  * @v len		Length of buffer
197
  * @v len		Length of buffer
164
  * @ret len		Length of encoded string (excluding NUL)
198
  * @ret len		Length of encoded string (excluding NUL)
165
  */
199
  */
166
-size_t uri_encode ( const char *string, unsigned int field,
200
+size_t uri_encode ( unsigned int field, const void *raw, size_t raw_len,
167
 		    char *buf, ssize_t len ) {
201
 		    char *buf, ssize_t len ) {
202
+	const uint8_t *raw_bytes = ( ( const uint8_t * ) raw );
168
 	ssize_t remaining = len;
203
 	ssize_t remaining = len;
169
 	size_t used;
204
 	size_t used;
170
 	char c;
205
 	char c;
174
 		buf[0] = '\0';
209
 		buf[0] = '\0';
175
 
210
 
176
 	/* Copy string, escaping as necessary */
211
 	/* Copy string, escaping as necessary */
177
-	while ( ( c = *(string++) ) ) {
212
+	while ( raw_len-- ) {
213
+		c = *(raw_bytes++);
178
 		if ( uri_character_escaped ( c, field ) ) {
214
 		if ( uri_character_escaped ( c, field ) ) {
179
 			used = ssnprintf ( buf, remaining, "%%%02X", c );
215
 			used = ssnprintf ( buf, remaining, "%%%02X", c );
180
 		} else {
216
 		} else {
187
 	return ( len - remaining );
223
 	return ( len - remaining );
188
 }
224
 }
189
 
225
 
226
+/**
227
+ * Encode URI field string
228
+ *
229
+ * @v field		URI field index
230
+ * @v string		String
231
+ * @v buf		Buffer
232
+ * @v len		Length of buffer
233
+ * @ret len		Length of encoded string (excluding NUL)
234
+ */
235
+size_t uri_encode_string ( unsigned int field, const char *string,
236
+			   char *buf, ssize_t len ) {
237
+
238
+	return uri_encode ( field, string, strlen ( string ), buf, len );
239
+}
240
+
190
 /**
241
 /**
191
  * Dump URI for debugging
242
  * Dump URI for debugging
192
  *
243
  *
368
 	}
419
 	}
369
 
420
 
370
 	/* Decode fields in-place */
421
 	/* Decode fields in-place */
371
-	for ( field = 0 ; field < URI_FIELDS ; field++ ) {
372
-		if ( uri_field ( uri, field ) )
373
-			uri_decode ( ( char * ) uri_field ( uri, field ) );
374
-	}
422
+	for ( field = 0 ; field < URI_FIELDS ; field++ )
423
+		uri_decode_inplace ( uri, field );
375
 
424
 
376
  done:
425
  done:
377
 	DBGC ( uri, "URI parsed \"%s\" to", uri_string );
426
 	DBGC ( uri, "URI parsed \"%s\" to", uri_string );
444
 		}
493
 		}
445
 
494
 
446
 		/* Encode this field */
495
 		/* Encode this field */
447
-		used += uri_encode ( uri_field ( uri, field ), field,
448
-				     ( buf + used ), ( len - used ) );
496
+		used += uri_encode_string ( field, uri_field ( uri, field ),
497
+					    ( buf + used ), ( len - used ) );
449
 
498
 
450
 		/* Suffix this field, if applicable */
499
 		/* Suffix this field, if applicable */
451
 		if ( ( field == URI_SCHEME ) && ( ! uri->opaque ) ) {
500
 		if ( ( field == URI_SCHEME ) && ( ! uri->opaque ) ) {

+ 4
- 1
src/include/ipxe/uri.h View File

191
 
191
 
192
 extern struct uri *cwuri;
192
 extern struct uri *cwuri;
193
 
193
 
194
-extern size_t uri_encode ( const char *string, unsigned int field,
194
+extern size_t uri_decode ( const char *encoded, void *buf, size_t len );
195
+extern size_t uri_encode ( unsigned int field, const void *raw, size_t raw_len,
195
 			   char *buf, ssize_t len );
196
 			   char *buf, ssize_t len );
197
+extern size_t uri_encode_string ( unsigned int field, const char *string,
198
+				  char *buf, ssize_t len );
196
 extern struct uri * parse_uri ( const char *uri_string );
199
 extern struct uri * parse_uri ( const char *uri_string );
197
 extern size_t format_uri ( const struct uri *uri, char *buf, size_t len );
200
 extern size_t format_uri ( const struct uri *uri, char *buf, size_t len );
198
 extern char * format_uri_alloc ( const struct uri *uri );
201
 extern char * format_uri_alloc ( const struct uri *uri );

+ 2
- 2
src/net/tcp/httpcore.c View File

1826
 		}
1826
 		}
1827
 
1827
 
1828
 		/* URI-encode the key */
1828
 		/* URI-encode the key */
1829
-		frag_len = uri_encode ( param->key, 0, buf, remaining );
1829
+		frag_len = uri_encode_string ( 0, param->key, buf, remaining );
1830
 		buf += frag_len;
1830
 		buf += frag_len;
1831
 		len += frag_len;
1831
 		len += frag_len;
1832
 		remaining -= frag_len;
1832
 		remaining -= frag_len;
1839
 		remaining--;
1839
 		remaining--;
1840
 
1840
 
1841
 		/* URI-encode the value */
1841
 		/* URI-encode the value */
1842
-		frag_len = uri_encode ( param->value, 0, buf, remaining );
1842
+		frag_len = uri_encode_string ( 0, param->value, buf, remaining);
1843
 		buf += frag_len;
1843
 		buf += frag_len;
1844
 		len += frag_len;
1844
 		len += frag_len;
1845
 		remaining -= frag_len;
1845
 		remaining -= frag_len;

+ 16
- 0
src/tests/settings_test.c View File

166
 	.type = &setting_type_string,
166
 	.type = &setting_type_string,
167
 };
167
 };
168
 
168
 
169
+/** Test URI-encoded string setting */
170
+static struct setting test_uristring_setting = {
171
+	.name = "test_uristring",
172
+	.type = &setting_type_uristring,
173
+};
174
+
169
 /** Test IPv4 address setting type */
175
 /** Test IPv4 address setting type */
170
 static struct setting test_ipv4_setting = {
176
 static struct setting test_ipv4_setting = {
171
 	.name = "test_ipv4",
177
 	.name = "test_ipv4",
265
 	fetchf_ok ( &test_settings, &test_string_setting,
271
 	fetchf_ok ( &test_settings, &test_string_setting,
266
 		    RAW ( 'w', 'o', 'r', 'l', 'd' ), "world" );
272
 		    RAW ( 'w', 'o', 'r', 'l', 'd' ), "world" );
267
 
273
 
274
+	/* "uristring" setting type */
275
+	storef_ok ( &test_settings, &test_uristring_setting, "hello%20world",
276
+		    RAW ( 'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l',
277
+			  'd' ) );
278
+	fetchf_ok ( &test_settings, &test_uristring_setting,
279
+		    RAW ( 1, 2, 3, 4, 5 ), "%01%02%03%04%05" );
280
+	fetchf_ok ( &test_settings, &test_uristring_setting,
281
+		    RAW ( 0, ' ', '%', '/', '#', ':', '@', '?', '=', '&' ),
282
+		    "%00%20%25%2F%23%3A%40%3F%3D%26" );
283
+
268
 	/* "ipv4" setting type */
284
 	/* "ipv4" setting type */
269
 	storef_ok ( &test_settings, &test_ipv4_setting, "192.168.0.1",
285
 	storef_ok ( &test_settings, &test_ipv4_setting, "192.168.0.1",
270
 		    RAW ( 192, 168, 0, 1 ) );
286
 		    RAW ( 192, 168, 0, 1 ) );

Loading…
Cancel
Save