diff --git a/src/core/settings.c b/src/core/settings.c index 430cdc84bc..18180219f0 100644 --- a/src/core/settings.c +++ b/src/core/settings.c @@ -697,6 +697,10 @@ int fetch_setting ( struct settings *settings, const struct setting *setting, if ( ( ret = settings->op->fetch ( settings, &tmp, data, len ) ) >= 0 ) { + /* If incoming setting has a type, copy it over in + * case it was overridden. */ + if ( setting->type ) + tmp.type = setting->type; /* Default to string type, if not yet specified */ if ( ! tmp.type ) tmp.type = &setting_type_string; @@ -1714,6 +1718,48 @@ const struct setting_type setting_type_uristring __setting_type = { .format = format_uristring_setting, }; +/** + * Format a URI without the path, query, and fragment portions. + * + * @v type Setting type + * @v raw Raw setting value + * @v raw_len Length of raw setting value + * @v buf Buffer to contain formatted value + * @v len Length of buffer + * @ret len Length of formatted value, or negative error + */ +static int format_uribase_setting ( const struct setting_type *type __unused, + const void *raw, size_t raw_len, + char *buf, size_t len ) { + char *raw_str; + struct uri *base_uri; + size_t ret; + raw_str = strndup((const char*)raw, raw_len); + if (!raw_str) { + return -ENOMEM; + } + base_uri = parse_uri(raw_str); + if (!base_uri) { + ret = -ENOMEM; + goto err_uri_parse; + } + base_uri->path = NULL; + base_uri->query = NULL; + base_uri->fragment = NULL; + ret = format_uri(base_uri, buf, len); + uri_put(base_uri); +err_uri_parse: + free(raw_str); + return ret; +} + +/** A setting to strip path, query, and fragment from a URI */ +const struct setting_type setting_type_uribase __setting_type = { + .name = "uribase", + .format = format_uribase_setting, +}; + + /** * Parse IPv4 address setting value (when IPv4 support is not present) * diff --git a/src/include/ipxe/settings.h b/src/include/ipxe/settings.h index f463e6674d..06ac075847 100644 --- a/src/include/ipxe/settings.h +++ b/src/include/ipxe/settings.h @@ -413,6 +413,7 @@ extern char * expand_settings ( const char *string ); extern const struct setting_type setting_type_string __setting_type; extern const struct setting_type setting_type_uristring __setting_type; +extern const struct setting_type setting_type_uribase __setting_type; extern const struct setting_type setting_type_ipv4 __setting_type; extern const struct setting_type setting_type_ipv6 __setting_type; extern const struct setting_type setting_type_int8 __setting_type; diff --git a/src/tests/settings_test.c b/src/tests/settings_test.c index 828901b066..4fcd925bee 100644 --- a/src/tests/settings_test.c +++ b/src/tests/settings_test.c @@ -172,6 +172,12 @@ static struct setting test_uristring_setting = { .type = &setting_type_uristring, }; +/** Test URI base setting */ +static struct setting test_uribase_setting = { + .name = "test_uribase", + .type = &setting_type_uribase, +}; + /** Test IPv4 address setting type */ static struct setting test_ipv4_setting = { .name = "test_ipv4", @@ -281,6 +287,13 @@ static void settings_test_exec ( void ) { RAW ( 0, ' ', '%', '/', '#', ':', '@', '?', '=', '&' ), "%00%20%25%2F%23%3A%40%3F%3D%26" ); + /* "uribase" setting type (no store capability) */ + fetchf_ok ( &test_settings, &test_uribase_setting, + RAW ( 'h', 't', 't', 'p', ':', '/', '/', 's', 'o', 'm', 'e', + '.', 's', 'e', 'r', 'v', 'e', 'r', ':', '1', '2', '3', + '4', '/', 'p', 'a', 't', 'h', '?', 'q', '#', 'f'), + "http://some.server:1234" ); + /* "ipv4" setting type */ storef_ok ( &test_settings, &test_ipv4_setting, "192.168.0.1", RAW ( 192, 168, 0, 1 ) );