00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 FILE_LICENCE ( GPL2_OR_LATER );
00020
00021
00022
00023
00024
00025
00026
00027 #include <stdint.h>
00028 #include <stdlib.h>
00029 #include <string.h>
00030 #include <libgen.h>
00031 #include <ctype.h>
00032 #include <gpxe/vsprintf.h>
00033 #include <gpxe/uri.h>
00034
00035
00036
00037
00038
00039
00040 static void dump_uri ( struct uri *uri ) {
00041 if ( ! uri )
00042 return;
00043 if ( uri->scheme )
00044 DBG ( " scheme \"%s\"", uri->scheme );
00045 if ( uri->opaque )
00046 DBG ( " opaque \"%s\"", uri->opaque );
00047 if ( uri->user )
00048 DBG ( " user \"%s\"", uri->user );
00049 if ( uri->password )
00050 DBG ( " password \"%s\"", uri->password );
00051 if ( uri->host )
00052 DBG ( " host \"%s\"", uri->host );
00053 if ( uri->port )
00054 DBG ( " port \"%s\"", uri->port );
00055 if ( uri->path )
00056 DBG ( " path \"%s\"", uri->path );
00057 if ( uri->query )
00058 DBG ( " query \"%s\"", uri->query );
00059 if ( uri->fragment )
00060 DBG ( " fragment \"%s\"", uri->fragment );
00061 }
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073 struct uri * parse_uri ( const char *uri_string ) {
00074 struct uri *uri;
00075 char *raw;
00076 char *tmp;
00077 char *path = NULL;
00078 char *authority = NULL;
00079 int i;
00080 size_t raw_len;
00081
00082
00083 raw_len = ( strlen ( uri_string ) + 1 );
00084 uri = zalloc ( sizeof ( *uri ) + raw_len );
00085 if ( ! uri )
00086 return NULL;
00087 raw = ( ( ( char * ) uri ) + sizeof ( *uri ) );
00088
00089
00090 memcpy ( raw, uri_string, raw_len );
00091
00092
00093 if ( ( tmp = strchr ( raw, '#' ) ) ) {
00094 *(tmp++) = '\0';
00095 uri->fragment = tmp;
00096 }
00097
00098
00099
00100
00101
00102
00103 if ( ( tmp = strchr ( raw, ':' ) ) && ( tmp > ( raw + 1 ) ) ) {
00104
00105 uri->scheme = raw;
00106 *(tmp++) = '\0';
00107 if ( *tmp == '/' ) {
00108
00109 path = tmp;
00110 } else {
00111
00112 uri->opaque = tmp;
00113 }
00114 } else {
00115
00116 path = raw;
00117 }
00118
00119
00120
00121
00122 if ( ! path )
00123 goto done;
00124
00125
00126 if ( ( tmp = strchr ( path, '?' ) ) ) {
00127 *(tmp++) = '\0';
00128 uri->query = tmp;
00129 }
00130
00131
00132 if ( strncmp ( path, "//", 2 ) == 0 ) {
00133
00134
00135
00136
00137
00138
00139 authority = ( path + 2 );
00140 if ( ( tmp = strchr ( authority, '/' ) ) ) {
00141
00142 uri->path = tmp;
00143 memmove ( ( authority - 1 ), authority,
00144 ( tmp - authority ) );
00145 authority--;
00146 *(--tmp) = '\0';
00147 }
00148 } else {
00149
00150 uri->path = path;
00151 }
00152
00153
00154 if ( ( tmp = strchr ( authority, '@' ) ) ) {
00155
00156 *(tmp++) = '\0';
00157 uri->host = tmp;
00158 uri->user = authority;
00159 if ( ( tmp = strchr ( authority, ':' ) ) ) {
00160
00161 *(tmp++) = '\0';
00162 uri->password = tmp;
00163 }
00164 } else {
00165
00166 uri->host = authority;
00167 }
00168
00169
00170 if ( ( tmp = strchr ( uri->host, ':' ) ) ) {
00171 *(tmp++) = '\0';
00172 uri->port = tmp;
00173 }
00174
00175
00176 for ( i = URI_FIRST_FIELD; i <= URI_LAST_FIELD; i++ ) {
00177 const char *field = uri_get_field ( uri, i );
00178 if ( field && ( URI_ENCODED & ( 1 << i ) ) )
00179 uri_decode ( field, ( char * ) field,
00180 strlen ( field ) + 1 );
00181 }
00182
00183 done:
00184 DBG ( "URI \"%s\" split into", uri_string );
00185 dump_uri ( uri );
00186 DBG ( "\n" );
00187
00188 return uri;
00189 }
00190
00191
00192
00193
00194
00195
00196
00197
00198 unsigned int uri_port ( struct uri *uri, unsigned int default_port ) {
00199 if ( ( ! uri ) || ( ! uri->port ) )
00200 return default_port;
00201 return ( strtoul ( uri->port, NULL, 0 ) );
00202 }
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00213 int unparse_uri ( char *buf, size_t size, struct uri *uri,
00214 unsigned int fields ) {
00215
00216 static char separators[] = { 0, ':',
00217 0, ':',
00218 '@', ':',
00219 0, '?',
00220 '#' };
00221 int used = 0;
00222 int i;
00223
00224 DBG ( "URI unparsing" );
00225 dump_uri ( uri );
00226 DBG ( "\n" );
00227
00228
00229 if ( size )
00230 buf[0] = '\0';
00231
00232
00233 if ( ! uri )
00234 return 0;
00235
00236
00237 for ( i = URI_FIRST_FIELD; i <= URI_LAST_FIELD; i++ ) {
00238 const char *field = uri_get_field ( uri, i );
00239 char sep = separators[i];
00240
00241
00242 if ( ! field )
00243 fields &= ~( 1 << i );
00244
00245
00246 if ( fields & ( 1 << i ) ) {
00247
00248 if ( ( fields & URI_SCHEME_BIT ) &&
00249 ( i > URI_OPAQUE ) ) {
00250 used += ssnprintf ( buf + used, size - used,
00251 "://" );
00252
00253 fields &= ~URI_SCHEME_BIT;
00254 }
00255
00256
00257 if ( sep && ( fields & ( ( 1 << i ) - 1 ) ) )
00258 used += ssnprintf ( buf + used, size - used,
00259 "%c", sep );
00260
00261
00262 if ( URI_ENCODED & ( 1 << i ) )
00263 used += uri_encode ( field, buf + used,
00264 size - used, i );
00265 else
00266 used += ssnprintf ( buf + used, size - used,
00267 "%s", field );
00268 }
00269 }
00270
00271 return used;
00272 }
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282 struct uri * uri_dup ( struct uri *uri ) {
00283 size_t len = ( unparse_uri ( NULL, 0, uri, URI_ALL ) + 1 );
00284 char buf[len];
00285
00286 unparse_uri ( buf, len, uri, URI_ALL );
00287 return parse_uri ( buf );
00288 }
00289
00290
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304 char * resolve_path ( const char *base_path,
00305 const char *relative_path ) {
00306 size_t base_len = ( strlen ( base_path ) + 1 );
00307 char base_path_copy[base_len];
00308 char *base_tmp = base_path_copy;
00309 char *resolved;
00310
00311
00312 if ( relative_path[0] == '/' )
00313 return strdup ( relative_path );
00314
00315
00316 memcpy ( base_tmp, base_path, base_len );
00317 base_tmp = dirname ( base_tmp );
00318
00319
00320 while ( *relative_path == '.' ) {
00321 relative_path++;
00322 if ( *relative_path == 0 ) {
00323
00324 } else if ( *relative_path == '/' ) {
00325 relative_path++;
00326 } else if ( *relative_path == '.' ) {
00327 relative_path++;
00328 if ( *relative_path == 0 ) {
00329 base_tmp = dirname ( base_tmp );
00330 } else if ( *relative_path == '/' ) {
00331 base_tmp = dirname ( base_tmp );
00332 relative_path++;
00333 } else {
00334 relative_path -= 2;
00335 break;
00336 }
00337 } else {
00338 relative_path--;
00339 break;
00340 }
00341 }
00342
00343
00344 if ( asprintf ( &resolved, "%s%s%s", base_tmp,
00345 ( ( base_tmp[ strlen ( base_tmp ) - 1 ] == '/' ) ?
00346 "" : "/" ), relative_path ) < 0 )
00347 return NULL;
00348
00349 return resolved;
00350 }
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363 struct uri * resolve_uri ( struct uri *base_uri,
00364 struct uri *relative_uri ) {
00365 struct uri tmp_uri;
00366 char *tmp_path = NULL;
00367 struct uri *new_uri;
00368
00369
00370 if ( uri_is_absolute ( relative_uri ) || ( ! base_uri ) )
00371 return uri_get ( relative_uri );
00372
00373
00374 memcpy ( &tmp_uri, base_uri, sizeof ( tmp_uri ) );
00375 if ( relative_uri->path ) {
00376 tmp_path = resolve_path ( ( base_uri->path ?
00377 base_uri->path : "/" ),
00378 relative_uri->path );
00379 tmp_uri.path = tmp_path;
00380 tmp_uri.query = relative_uri->query;
00381 tmp_uri.fragment = relative_uri->fragment;
00382 } else if ( relative_uri->query ) {
00383 tmp_uri.query = relative_uri->query;
00384 tmp_uri.fragment = relative_uri->fragment;
00385 } else if ( relative_uri->fragment ) {
00386 tmp_uri.fragment = relative_uri->fragment;
00387 }
00388
00389
00390 new_uri = uri_dup ( &tmp_uri );
00391 free ( tmp_path );
00392 return new_uri;
00393 }
00394
00395
00396
00397
00398
00399
00400
00401
00402 static int is_unreserved_uri_char ( int c, int field ) {
00403
00404
00405
00406
00407
00408
00409
00410 int ok = ( isupper ( c ) || islower ( c ) || isdigit ( c ) ||
00411 ( c == '-' ) || ( c == '_' ) ||
00412 ( c == '.' ) || ( c == '~' ) );
00413
00414 if ( field == URI_QUERY )
00415 ok = ok || ( c == ';' ) || ( c == '&' ) || ( c == '=' );
00416
00417 if ( field == URI_PATH )
00418 ok = ok || ( c == '/' );
00419
00420 if ( field == URI_OPAQUE )
00421 ok = 1;
00422
00423 return ok;
00424 }
00425
00426
00427
00428
00429
00430
00431
00432
00433
00434
00435 size_t uri_encode ( const char *raw_string, char *buf, ssize_t len,
00436 int field ) {
00437 ssize_t remaining = len;
00438 size_t used;
00439 unsigned char c;
00440
00441 if ( len > 0 )
00442 buf[0] = '\0';
00443
00444 while ( ( c = *(raw_string++) ) ) {
00445 if ( is_unreserved_uri_char ( c, field ) ) {
00446 used = ssnprintf ( buf, remaining, "%c", c );
00447 } else {
00448 used = ssnprintf ( buf, remaining, "%%%02X", c );
00449 }
00450 buf += used;
00451 remaining -= used;
00452 }
00453
00454 return ( len - remaining );
00455 }
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465
00466
00467
00468 size_t uri_decode ( const char *encoded_string, char *buf, ssize_t len ) {
00469 ssize_t remaining;
00470 char hexbuf[3];
00471 char *hexbuf_end;
00472 unsigned char c;
00473
00474 for ( remaining = len; *encoded_string; remaining-- ) {
00475 if ( *encoded_string == '%' ) {
00476 encoded_string++;
00477 snprintf ( hexbuf, sizeof ( hexbuf ), "%s",
00478 encoded_string );
00479 c = strtoul ( hexbuf, &hexbuf_end, 16 );
00480 encoded_string += ( hexbuf_end - hexbuf );
00481 } else {
00482 c = *(encoded_string++);
00483 }
00484 if ( remaining > 1 )
00485 *buf++ = c;
00486 }
00487
00488 if ( len )
00489 *buf = 0;
00490
00491 return ( len - remaining );
00492 }