@@ -39,34 +39,62 @@ 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 ;
54
58
char decoded ;
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 ) ) {
0 commit comments