|
@@ -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 ) ) {
|