summaryrefslogtreecommitdiffstats
path: root/src/core/uri.c
diff options
context:
space:
mode:
authorMichael Brown2015-08-25 13:33:40 +0200
committerMichael Brown2015-08-25 14:31:46 +0200
commitba3695353add020b686547699ba5e259c339bfa6 (patch)
treed400084f87152adbbbc7dbca3140c1c2789c03b0 /src/core/uri.c
parent[autoboot] Display image information as part of the default control flow (diff)
downloadipxe-ba3695353add020b686547699ba5e259c339bfa6.tar.gz
ipxe-ba3695353add020b686547699ba5e259c339bfa6.tar.xz
ipxe-ba3695353add020b686547699ba5e259c339bfa6.zip
[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>
Diffstat (limited to 'src/core/uri.c')
-rw-r--r--src/core/uri.c93
1 files changed, 71 insertions, 22 deletions
diff --git a/src/core/uri.c b/src/core/uri.c
index 3b5f270f..30f8f6ca 100644
--- a/src/core/uri.c
+++ b/src/core/uri.c
@@ -39,15 +39,19 @@ FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
#include <ipxe/uri.h>
/**
- * Decode URI field (in place)
+ * Decode URI field
*
- * @v string String
+ * @v encoded Encoded field
+ * @v buf Data buffer
+ * @v len Length
+ * @ret len Length of data
*
* URI decoding can never increase the length of a string; we can
* therefore safely decode in place.
*/
-static void uri_decode ( char *string ) {
- char *dest = string;
+size_t uri_decode ( const char *encoded, void *buf, size_t len ) {
+ uint8_t *out = buf;
+ unsigned int count = 0;
char hexbuf[3];
char *hexbuf_end;
char c;
@@ -55,18 +59,42 @@ static void uri_decode ( char *string ) {
unsigned int skip;
/* Copy string, decoding escaped characters as necessary */
- do {
- c = *(string++);
+ while ( ( c = *(encoded++) ) ) {
if ( c == '%' ) {
- snprintf ( hexbuf, sizeof ( hexbuf ), "%s", string );
+ snprintf ( hexbuf, sizeof ( hexbuf ), "%s", encoded );
decoded = strtoul ( hexbuf, &hexbuf_end, 16 );
skip = ( hexbuf_end - hexbuf );
- string += skip;
+ encoded += skip;
if ( skip )
c = decoded;
}
- *(dest++) = c;
- } while ( c );
+ if ( count < len )
+ out[count] = c;
+ count++;
+ }
+ return count;
+}
+
+/**
+ * Decode URI field in-place
+ *
+ * @v uri URI
+ * @v field URI field index
+ */
+static void uri_decode_inplace ( struct uri *uri, unsigned int field ) {
+ const char *encoded = uri_field ( uri, field );
+ char *decoded = ( ( char * ) encoded );
+ size_t len;
+
+ /* Do nothing if field is not present */
+ if ( ! encoded )
+ return;
+
+ /* Decode field in place */
+ len = uri_decode ( encoded, decoded, strlen ( encoded ) );
+
+ /* Terminate decoded string */
+ decoded[len] = '\0';
}
/**
@@ -115,10 +143,15 @@ static int uri_character_escaped ( char c, unsigned int field ) {
* '%', the full set of characters with significance to the
* URL parser is "/#:@?". We choose for each URI field which
* of these require escaping in our use cases.
+ *
+ * For the scheme field (equivalently, if field is zero), we
+ * escape anything that has significance not just for our URI
+ * parser but for any other URI parsers (e.g. HTTP query
+ * string parsers, which care about '=' and '&').
*/
static const char *escaped[URI_FIELDS] = {
- /* Scheme: escape everything */
- [URI_SCHEME] = "/#:@?",
+ /* Scheme or default: escape everything */
+ [URI_SCHEME] = "/#:@?=&",
/* Opaque part: escape characters which would affect
* the reparsing of the URI, allowing everything else
* (e.g. ':', which will appear in iSCSI URIs).
@@ -157,14 +190,16 @@ static int uri_character_escaped ( char c, unsigned int field ) {
/**
* Encode URI field
*
- * @v uri URI
* @v field URI field index
- * @v buf Buffer to contain encoded string
+ * @v raw Raw data
+ * @v raw_len Length of raw data
+ * @v buf Buffer
* @v len Length of buffer
* @ret len Length of encoded string (excluding NUL)
*/
-size_t uri_encode ( const char *string, unsigned int field,
+size_t uri_encode ( unsigned int field, const void *raw, size_t raw_len,
char *buf, ssize_t len ) {
+ const uint8_t *raw_bytes = ( ( const uint8_t * ) raw );
ssize_t remaining = len;
size_t used;
char c;
@@ -174,7 +209,8 @@ size_t uri_encode ( const char *string, unsigned int field,
buf[0] = '\0';
/* Copy string, escaping as necessary */
- while ( ( c = *(string++) ) ) {
+ while ( raw_len-- ) {
+ c = *(raw_bytes++);
if ( uri_character_escaped ( c, field ) ) {
used = ssnprintf ( buf, remaining, "%%%02X", c );
} else {
@@ -188,6 +224,21 @@ size_t uri_encode ( const char *string, unsigned int field,
}
/**
+ * Encode URI field string
+ *
+ * @v field URI field index
+ * @v string String
+ * @v buf Buffer
+ * @v len Length of buffer
+ * @ret len Length of encoded string (excluding NUL)
+ */
+size_t uri_encode_string ( unsigned int field, const char *string,
+ char *buf, ssize_t len ) {
+
+ return uri_encode ( field, string, strlen ( string ), buf, len );
+}
+
+/**
* Dump URI for debugging
*
* @v uri URI
@@ -368,10 +419,8 @@ struct uri * parse_uri ( const char *uri_string ) {
}
/* Decode fields in-place */
- for ( field = 0 ; field < URI_FIELDS ; field++ ) {
- if ( uri_field ( uri, field ) )
- uri_decode ( ( char * ) uri_field ( uri, field ) );
- }
+ for ( field = 0 ; field < URI_FIELDS ; field++ )
+ uri_decode_inplace ( uri, field );
done:
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 ) {
}
/* Encode this field */
- used += uri_encode ( uri_field ( uri, field ), field,
- ( buf + used ), ( len - used ) );
+ used += uri_encode_string ( field, uri_field ( uri, field ),
+ ( buf + used ), ( len - used ) );
/* Suffix this field, if applicable */
if ( ( field == URI_SCHEME ) && ( ! uri->opaque ) ) {