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 8 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,15 +1666,43 @@ const struct setting_type setting_type_string __setting_type = {
1666 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 1702
 const struct setting_type setting_type_uristring __setting_type = {
1675 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,15 +39,19 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
39 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 49
  * URI decoding can never increase the length of a string; we can
47 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 55
 	char hexbuf[3];
52 56
 	char *hexbuf_end;
53 57
 	char c;
@@ -55,18 +59,42 @@ static void uri_decode ( char *string ) {
55 59
 	unsigned int skip;
56 60
 
57 61
 	/* Copy string, decoding escaped characters as necessary */
58
-	do {
59
-		c = *(string++);
62
+	while ( ( c = *(encoded++) ) ) {
60 63
 		if ( c == '%' ) {
61
-			snprintf ( hexbuf, sizeof ( hexbuf ), "%s", string );
64
+			snprintf ( hexbuf, sizeof ( hexbuf ), "%s", encoded );
62 65
 			decoded = strtoul ( hexbuf, &hexbuf_end, 16 );
63 66
 			skip = ( hexbuf_end - hexbuf );
64
-			string += skip;
67
+			encoded += skip;
65 68
 			if ( skip )
66 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,10 +143,15 @@ static int uri_character_escaped ( char c, unsigned int field ) {
115 143
 	 * '%', the full set of characters with significance to the
116 144
 	 * URL parser is "/#:@?".  We choose for each URI field which
117 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 152
 	static const char *escaped[URI_FIELDS] = {
120
-		/* Scheme: escape everything */
121
-		[URI_SCHEME]	= "/#:@?",
153
+		/* Scheme or default: escape everything */
154
+		[URI_SCHEME]	= "/#:@?=&",
122 155
 		/* Opaque part: escape characters which would affect
123 156
 		 * the reparsing of the URI, allowing everything else
124 157
 		 * (e.g. ':', which will appear in iSCSI URIs).
@@ -157,14 +190,16 @@ static int uri_character_escaped ( char c, unsigned int field ) {
157 190
 /**
158 191
  * Encode URI field
159 192
  *
160
- * @v uri		URI
161 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 197
  * @v len		Length of buffer
164 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 201
 		    char *buf, ssize_t len ) {
202
+	const uint8_t *raw_bytes = ( ( const uint8_t * ) raw );
168 203
 	ssize_t remaining = len;
169 204
 	size_t used;
170 205
 	char c;
@@ -174,7 +209,8 @@ size_t uri_encode ( const char *string, unsigned int field,
174 209
 		buf[0] = '\0';
175 210
 
176 211
 	/* Copy string, escaping as necessary */
177
-	while ( ( c = *(string++) ) ) {
212
+	while ( raw_len-- ) {
213
+		c = *(raw_bytes++);
178 214
 		if ( uri_character_escaped ( c, field ) ) {
179 215
 			used = ssnprintf ( buf, remaining, "%%%02X", c );
180 216
 		} else {
@@ -187,6 +223,21 @@ size_t uri_encode ( const char *string, unsigned int field,
187 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 242
  * Dump URI for debugging
192 243
  *
@@ -368,10 +419,8 @@ struct uri * parse_uri ( const char *uri_string ) {
368 419
 	}
369 420
 
370 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 425
  done:
377 426
 	DBGC ( uri, "URI parsed \"%s\" to", uri_string );
@@ -444,8 +493,8 @@ size_t format_uri ( const struct uri *uri, char *buf, size_t len ) {
444 493
 		}
445 494
 
446 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 499
 		/* Suffix this field, if applicable */
451 500
 		if ( ( field == URI_SCHEME ) && ( ! uri->opaque ) ) {

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

@@ -191,8 +191,11 @@ uri_put ( struct uri *uri ) {
191 191
 
192 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 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 199
 extern struct uri * parse_uri ( const char *uri_string );
197 200
 extern size_t format_uri ( const struct uri *uri, char *buf, size_t len );
198 201
 extern char * format_uri_alloc ( const struct uri *uri );

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

@@ -1826,7 +1826,7 @@ static size_t http_params ( struct parameters *params, char *buf, size_t len ) {
1826 1826
 		}
1827 1827
 
1828 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 1830
 		buf += frag_len;
1831 1831
 		len += frag_len;
1832 1832
 		remaining -= frag_len;
@@ -1839,7 +1839,7 @@ static size_t http_params ( struct parameters *params, char *buf, size_t len ) {
1839 1839
 		remaining--;
1840 1840
 
1841 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 1843
 		buf += frag_len;
1844 1844
 		len += frag_len;
1845 1845
 		remaining -= frag_len;

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

@@ -166,6 +166,12 @@ static struct setting test_string_setting = {
166 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 175
 /** Test IPv4 address setting type */
170 176
 static struct setting test_ipv4_setting = {
171 177
 	.name = "test_ipv4",
@@ -265,6 +271,16 @@ static void settings_test_exec ( void ) {
265 271
 	fetchf_ok ( &test_settings, &test_string_setting,
266 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 284
 	/* "ipv4" setting type */
269 285
 	storef_ok ( &test_settings, &test_ipv4_setting, "192.168.0.1",
270 286
 		    RAW ( 192, 168, 0, 1 ) );

Loading…
Cancel
Save