/** * Unparse URI * * @v buf Buffer to fill with URI string * @v size Size of buffer * @v uri URI to write into buffer, or NULL * @v fields Bitmask of fields to include in URI string, or URI_ALL * @ret len Length of URI string */ int unparse_uri ( char *buf, size_t size, struct uri *uri, unsigned int fields ) { /* List of characters that typically go before certain fields */ static char separators[] = { /* scheme */ 0, /* opaque */ ':', /* user */ 0, /* password */ ':', /* host */ '@', /* port */ ':', /* path */ 0, /* query */ '?', /* fragment */ '#' }; int used = 0; int i; DBG ( "URI unparsing" ); dump_uri ( uri ); DBG ( "\n" ); /* Ensure buffer is NUL-terminated */ if ( size ) buf[0] = '\0'; /* Special-case NULL URI */ if ( ! uri ) return 0; /* Iterate through requested fields */ for ( i = URI_FIRST_FIELD; i <= URI_LAST_FIELD; i++ ) { const char *field = uri_get_field ( uri, i ); char sep = separators[i]; /* Ensure `fields' only contains bits for fields that exist */ if ( ! field ) fields &= ~( 1 << i ); /* Store this field if we were asked to */ if ( fields & ( 1 << i ) ) { /* Print :// if we're non-opaque and had a scheme */ if ( ( fields & URI_SCHEME_BIT ) && ( i > URI_OPAQUE ) ) { used += ssnprintf ( buf + used, size - used, "://" ); /* Only print :// once */ fields &= ~URI_SCHEME_BIT; } /* Only print separator if an earlier field exists */ if ( sep && ( fields & ( ( 1 << i ) - 1 ) ) ) used += ssnprintf ( buf + used, size - used, "%c", sep ); /* Print contents of field, possibly encoded */ if ( URI_ENCODED & ( 1 << i ) ) used += uri_encode ( field, buf + used, size - used, i ); else used += ssnprintf ( buf + used, size - used, "%s", field ); } } return used; }
void test_main (int argc, char **argv) { const char *url; E2kUri *euri; if (argc != 2) { fprintf (stderr, "Usage: %s url \n", argv[0]); exit (1); } url = argv[1]; euri = e2k_uri_new (url); dump_uri (euri); test_quit (); }
/** Test parsing and rebuilding a URI. * * \param uri Pre-created URI structure. * \param original The original URI string. * \param expected The expected, re-built string, or NULL if original is expected. * \return 1 on error, 0 on success. */ static int test_parsing_uri(VC_URI_PARTS_T *uri, const char *original, const char *expected) { bool parsed; LOG_INFO(NULL, "URI: <%s>", original); parsed = vc_uri_parse( uri, original ); if (!parsed) { LOG_ERROR(NULL, "*** Expected <%s> to parse, but it didn't", original); return 1; } dump_uri(uri); return check_uri(uri, expected ? expected : original); }
/** * Parse URI * * @v uri_string URI as a string * @ret uri URI * * Splits a URI into its component parts. The return URI structure is * dynamically allocated and must eventually be freed by calling * uri_put(). */ struct uri * parse_uri ( const char *uri_string ) { struct uri *uri; char *raw; char *tmp; char *path = NULL; char *authority = NULL; size_t raw_len; /* Allocate space for URI struct and a copy of the string */ raw_len = ( strlen ( uri_string ) + 1 /* NUL */ ); uri = zalloc ( sizeof ( *uri ) + raw_len ); if ( ! uri ) return NULL; raw = ( ( ( char * ) uri ) + sizeof ( *uri ) ); /* Zero URI struct and copy in the raw string */ memcpy ( raw, uri_string, raw_len ); /* Start by chopping off the fragment, if it exists */ if ( ( tmp = strchr ( raw, '#' ) ) ) { *(tmp++) = '\0'; uri->fragment = tmp; } /* Identify absolute/relative URI. We ignore schemes that are * apparently only a single character long, since otherwise we * misinterpret a DOS-style path name ("C:\path\to\file") as a * URI with scheme="C",opaque="\path\to\file". */ if ( ( tmp = strchr ( raw, ':' ) ) && ( tmp > ( raw + 1 ) ) ) { /* Absolute URI: identify hierarchical/opaque */ uri->scheme = raw; *(tmp++) = '\0'; if ( *tmp == '/' ) { /* Absolute URI with hierarchical part */ path = tmp; } else { /* Absolute URI with opaque part */ uri->opaque = tmp; } } else { /* Relative URI */ path = raw; } /* If we don't have a path (i.e. we have an absolute URI with * an opaque portion, we're already finished processing */ if ( ! path ) goto done; /* Chop off the query, if it exists */ if ( ( tmp = strchr ( path, '?' ) ) ) { *(tmp++) = '\0'; uri->query = tmp; } /* Identify net/absolute/relative path */ if ( strncmp ( path, "//", 2 ) == 0 ) { /* Net path. If this is terminated by the first '/' * of an absolute path, then we have no space for a * terminator after the authority field, so shuffle * the authority down by one byte, overwriting one of * the two slashes. */ authority = ( path + 2 ); if ( ( tmp = strchr ( authority, '/' ) ) ) { /* Shuffle down */ uri->path = tmp; memmove ( ( authority - 1 ), authority, ( tmp - authority ) ); authority--; *(--tmp) = '\0'; } } else { /* Absolute/relative path */ uri->path = path; } /* Split authority into user[:password] and host[:port] portions */ if ( ( tmp = strchr ( authority, '@' ) ) ) { /* Has user[:password] */ *(tmp++) = '\0'; uri->host = tmp; uri->user = authority; if ( ( tmp = strchr ( authority, ':' ) ) ) { /* Has password */ *(tmp++) = '\0'; uri->password = tmp; } } else { /* No user:password */ uri->host = authority; } /* Split host into host[:port] */ if ( ( tmp = strchr ( uri->host, ':' ) ) ) { *(tmp++) = '\0'; uri->port = tmp; } done: DBG ( "URI \"%s\" split into", uri_string ); dump_uri ( uri ); DBG ( "\n" ); return uri; }
/** * Unparse URI * * @v buf Buffer to fill with URI string * @v size Size of buffer * @v uri URI to write into buffer, or NULL * @ret len Length of URI string */ int unparse_uri ( char *buf, size_t size, struct uri *uri ) { int used = 0; DBG ( "URI unparsing" ); dump_uri ( uri ); DBG ( "\n" ); /* Special-case NULL URI */ if ( ! uri ) { if ( size ) buf[0] = '\0'; return 0; } /* Special-case opaque URIs */ if ( uri->opaque ) { return ssnprintf ( ( buf + used ), ( size - used ), "%s:%s", uri->scheme, uri->opaque ); } /* scheme:// */ if ( uri->scheme ) { used += ssnprintf ( ( buf + used ), ( size - used ), "%s://", uri->scheme ); } /* [user[:password]@]host[:port] */ if ( uri->host ) { if ( uri->user ) { used += ssnprintf ( ( buf + used ), ( size - used ), "%s", uri->user ); if ( uri->password ) { used += ssnprintf ( ( buf + used ), ( size - used ), ":%s", uri->password ); } used += ssnprintf ( ( buf + used ), ( size - used ), "@" ); } used += ssnprintf ( ( buf + used ), ( size - used ), "%s", uri->host ); if ( uri->port ) { used += ssnprintf ( ( buf + used ), ( size - used ), ":%s", uri->port ); } } /* /path */ if ( uri->path ) { used += ssnprintf ( ( buf + used ), ( size - used ), "%s", uri->path ); } /* ?query */ if ( uri->query ) { used += ssnprintf ( ( buf + used ), ( size - used ), "?%s", uri->query ); } /* #fragment */ if ( uri->fragment ) { used += ssnprintf ( ( buf + used ), ( size - used ), "#%s", uri->fragment ); } return used; }
/** Test building a URI from component parts. * * \param uri Pre-created URI structure. * \param uri_data The data for building the URI and the expected output. * \return 1 on error, 0 on success. */ static int test_building_uri(VC_URI_PARTS_T *uri, BUILD_URI_T *uri_data) { const char **p_str; const char *name, *value; LOG_INFO(NULL, "Building URI <%s>", uri_data->expected_uri); vc_uri_clear(uri); if (!vc_uri_set_scheme(uri, uri_data->scheme)) { LOG_ERROR(NULL, "*** Failed to set scheme"); return 1; } if (!vc_uri_set_userinfo(uri, uri_data->userinfo)) { LOG_ERROR(NULL, "*** Failed to set userinfo"); return 1; } if (!vc_uri_set_host(uri, uri_data->host)) { LOG_ERROR(NULL, "*** Failed to set host"); return 1; } if (!vc_uri_set_port(uri, uri_data->port)) { LOG_ERROR(NULL, "*** Failed to set port"); return 1; } if (!vc_uri_set_path(uri, uri_data->path)) { LOG_ERROR(NULL, "*** Failed to set path"); return 1; } if (!vc_uri_set_fragment(uri, uri_data->fragment)) { LOG_ERROR(NULL, "*** Failed to set fragment"); return 1; } p_str = uri_data->queries; name = *p_str++; while (name) { value = *p_str++; if (!vc_uri_add_query(uri, name, value)) { LOG_ERROR(NULL, "*** Failed to add query"); return 1; } name = *p_str++; } dump_uri(uri); return check_uri(uri, uri_data->expected_uri); }