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