@@ -39,34 +39,62 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
3939#include <ipxe/uri.h>
4040
4141/**
42- * Decode URI field (in place)
42+ * Decode URI field
4343 *
44- * @v string String
44+ * @v encoded Encoded field
45+ * @v buf Data buffer
46+ * @v len Length
47+ * @ret len Length of data
4548 *
4649 * URI decoding can never increase the length of a string; we can
4750 * therefore safely decode in place.
4851 */
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 ;
5155 char hexbuf [3 ];
5256 char * hexbuf_end ;
5357 char c ;
5458 char decoded ;
5559 unsigned int skip ;
5660
5761 /* Copy string, decoding escaped characters as necessary */
58- do {
59- c = * (string ++ );
62+ while ( ( c = * (encoded ++ ) ) ) {
6063 if ( c == '%' ) {
61- snprintf ( hexbuf , sizeof ( hexbuf ), "%s" , string );
64+ snprintf ( hexbuf , sizeof ( hexbuf ), "%s" , encoded );
6265 decoded = strtoul ( hexbuf , & hexbuf_end , 16 );
6366 skip = ( hexbuf_end - hexbuf );
64- string += skip ;
67+ encoded += skip ;
6568 if ( skip )
6669 c = decoded ;
6770 }
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' ;
7098}
7199
72100/**
@@ -115,10 +143,15 @@ static int uri_character_escaped ( char c, unsigned int field ) {
115143 * '%', the full set of characters with significance to the
116144 * URL parser is "/#:@?". We choose for each URI field which
117145 * 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 '&').
118151 */
119152 static const char * escaped [URI_FIELDS ] = {
120- /* Scheme: escape everything */
121- [URI_SCHEME ] = "/#:@?" ,
153+ /* Scheme or default : escape everything */
154+ [URI_SCHEME ] = "/#:@?=& " ,
122155 /* Opaque part: escape characters which would affect
123156 * the reparsing of the URI, allowing everything else
124157 * (e.g. ':', which will appear in iSCSI URIs).
@@ -157,14 +190,16 @@ static int uri_character_escaped ( char c, unsigned int field ) {
157190/**
158191 * Encode URI field
159192 *
160- * @v uri URI
161193 * @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
163197 * @v len Length of buffer
164198 * @ret len Length of encoded string (excluding NUL)
165199 */
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 ,
167201 char * buf , ssize_t len ) {
202+ const uint8_t * raw_bytes = ( ( const uint8_t * ) raw );
168203 ssize_t remaining = len ;
169204 size_t used ;
170205 char c ;
@@ -174,7 +209,8 @@ size_t uri_encode ( const char *string, unsigned int field,
174209 buf [0 ] = '\0' ;
175210
176211 /* Copy string, escaping as necessary */
177- while ( ( c = * (string ++ ) ) ) {
212+ while ( raw_len -- ) {
213+ c = * (raw_bytes ++ );
178214 if ( uri_character_escaped ( c , field ) ) {
179215 used = ssnprintf ( buf , remaining , "%%%02X" , c );
180216 } else {
@@ -187,6 +223,21 @@ size_t uri_encode ( const char *string, unsigned int field,
187223 return ( len - remaining );
188224}
189225
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+
190241/**
191242 * Dump URI for debugging
192243 *
@@ -368,10 +419,8 @@ struct uri * parse_uri ( const char *uri_string ) {
368419 }
369420
370421 /* 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 );
375424
376425 done :
377426 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 ) {
444493 }
445494
446495 /* 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 ) );
449498
450499 /* Suffix this field, if applicable */
451500 if ( ( field == URI_SCHEME ) && ( ! uri -> opaque ) ) {
0 commit comments