iPXE
Functions
uri.c File Reference

Uniform Resource Identifiers. More...

#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <libgen.h>
#include <ctype.h>
#include <ipxe/vsprintf.h>
#include <ipxe/params.h>
#include <ipxe/tcpip.h>
#include <ipxe/uri.h>

Go to the source code of this file.

Functions

 FILE_LICENCE (GPL2_OR_LATER_OR_UBDL)
 
size_t uri_decode (const char *encoded, void *buf, size_t len)
 Decode URI field. More...
 
static void uri_decode_inplace (char *encoded)
 Decode URI field in-place. More...
 
static int uri_character_escaped (char c, unsigned int field)
 Check if character should be escaped within a URI field. More...
 
size_t uri_encode (unsigned int field, const void *raw, size_t raw_len, char *buf, ssize_t len)
 Encode URI field. More...
 
size_t uri_encode_string (unsigned int field, const char *string, char *buf, ssize_t len)
 Encode URI field string. More...
 
static void uri_dump (const struct uri *uri)
 Dump URI for debugging. More...
 
static void uri_free (struct refcnt *refcnt)
 Free URI. More...
 
struct uriparse_uri (const char *uri_string)
 Parse URI. More...
 
unsigned int uri_port (const struct uri *uri, unsigned int default_port)
 Get port from URI. More...
 
size_t format_uri (const struct uri *uri, char *buf, size_t len)
 Format URI. More...
 
char * format_uri_alloc (const struct uri *uri)
 Format URI. More...
 
static size_t uri_copy_fields (const struct uri *src, struct uri *dest)
 Copy URI fields. More...
 
struct uriuri_dup (const struct uri *uri)
 Duplicate URI. More...
 
char * resolve_path (const char *base_path, const char *relative_path)
 Resolve base+relative path. More...
 
struct uriresolve_uri (const struct uri *base_uri, struct uri *relative_uri)
 Resolve base+relative URI. More...
 
static struct uritftp_uri (struct sockaddr *sa_server, const char *filename)
 Construct TFTP URI from server address and filename. More...
 
struct uripxe_uri (struct sockaddr *sa_server, const char *filename)
 Construct URI from server address and filename. More...
 

Detailed Description

Uniform Resource Identifiers.

Definition in file uri.c.

Function Documentation

◆ FILE_LICENCE()

FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL  )

◆ uri_decode()

size_t uri_decode ( const char *  encoded,
void *  buf,
size_t  len 
)

Decode URI field.

Parameters
encodedEncoded field
bufData buffer
lenLength
Return values
lenLength of data

URI decoding can never increase the length of a string; we can therefore safely decode in place.

Definition at line 53 of file uri.c.

53  {
54  uint8_t *out = buf;
55  unsigned int count = 0;
56  char hexbuf[3];
57  char *hexbuf_end;
58  char c;
59  char decoded;
60  unsigned int skip;
61 
62  /* Copy string, decoding escaped characters as necessary */
63  while ( ( c = *(encoded++) ) ) {
64  if ( c == '%' ) {
65  snprintf ( hexbuf, sizeof ( hexbuf ), "%s", encoded );
66  decoded = strtoul ( hexbuf, &hexbuf_end, 16 );
67  skip = ( hexbuf_end - hexbuf );
68  encoded += skip;
69  if ( skip )
70  c = decoded;
71  }
72  if ( count < len )
73  out[count] = c;
74  count++;
75  }
76  return count;
77 }
uint32_t c
Definition: md4.c:30
unsigned long strtoul(const char *string, char **endp, int base)
Convert string to numeric value.
Definition: string.c:471
__be32 out[4]
Definition: CIB_PRM.h:36
unsigned char uint8_t
Definition: stdint.h:10
uint32_t len
Length.
Definition: ena.h:14
uint16_t count
Number of entries.
Definition: ena.h:22
int snprintf(char *buf, size_t size, const char *fmt,...)
Write a formatted string to a buffer.
Definition: vsprintf.c:382

References c, count, len, out, snprintf(), and strtoul().

Referenced by parse_uristring_setting(), and uri_decode_inplace().

◆ uri_decode_inplace()

static void uri_decode_inplace ( char *  encoded)
static

Decode URI field in-place.

Parameters
encodedEncoded field, or NULL

Definition at line 84 of file uri.c.

84  {
85  char *decoded = encoded;
86  size_t len;
87 
88  /* Do nothing if field is not present */
89  if ( ! encoded )
90  return;
91 
92  /* Decode field in place */
93  len = uri_decode ( encoded, decoded, strlen ( encoded ) );
94 
95  /* Terminate decoded string */
96  decoded[len] = '\0';
97 }
size_t uri_decode(const char *encoded, void *buf, size_t len)
Decode URI field.
Definition: uri.c:53
size_t strlen(const char *src)
Get length of string.
Definition: string.c:243
uint32_t len
Length.
Definition: ena.h:14

References len, strlen(), and uri_decode().

Referenced by parse_uri(), and resolve_uri().

◆ uri_character_escaped()

static int uri_character_escaped ( char  c,
unsigned int  field 
)
static

Check if character should be escaped within a URI field.

Parameters
cCharacter
fieldURI field index
Return values
escapedCharacter should be escaped

Definition at line 106 of file uri.c.

106  {
107 
108  /* Non-printing characters and whitespace should always be
109  * escaped, since they cannot sensibly be displayed as part of
110  * a coherent URL string. (This test also catches control
111  * characters such as CR and LF, which could affect the
112  * operation of line-based protocols such as HTTP.)
113  *
114  * We should also escape characters which would alter the
115  * interpretation of the URL if not escaped, i.e. characters
116  * which have significance to the URL parser. We should not
117  * blindly escape all such characters, because this would lead
118  * to some very strange-looking URLs (e.g. if we were to
119  * always escape '/' as "%2F" even within the URI path).
120  *
121  * We do not need to be perfect. Our primary role is as a
122  * consumer of URIs rather than a producer; the main situation
123  * in which we produce a URI string is for display to a human
124  * user, who can probably tolerate some variance from the
125  * formal specification. The only situation in which we
126  * currently produce a URI string to be consumed by a computer
127  * is when constructing an HTTP request URI, which contains
128  * only the path and query fields.
129  *
130  * We can therefore sacrifice some correctness for the sake of
131  * code size. For example, colons within the URI host should
132  * be escaped unless they form part of an IPv6 literal
133  * address; doing this correctly would require the URI
134  * formatter to be aware of whether or not the URI host
135  * contained an IPv4 address, an IPv6 address, or a host name.
136  * We choose to simplify and never escape colons within the
137  * URI host field: in the event of a pathological hostname
138  * containing colons, this could potentially produce a URI
139  * string which could not be reparsed.
140  *
141  * After excluding non-printing characters, whitespace, and
142  * '%', the full set of characters with significance to the
143  * URL parser is "/#:@?". We choose for each URI field which
144  * of these require escaping in our use cases.
145  *
146  * For the scheme field (equivalently, if field is zero), we
147  * escape anything that has significance not just for our URI
148  * parser but for any other URI parsers (e.g. HTTP query
149  * string parsers, which care about '=' and '&').
150  */
151  static const char *escaped[URI_EPATH] = {
152  /* Scheme or default: escape everything */
153  [URI_SCHEME] = "/#:@?=&",
154  /* Opaque part: escape characters which would affect
155  * the reparsing of the URI, allowing everything else
156  * (e.g. ':', which will appear in iSCSI URIs).
157  */
158  [URI_OPAQUE] = "#",
159  /* User name: escape everything */
160  [URI_USER] = "/#:@?",
161  /* Password: escape everything */
162  [URI_PASSWORD] = "/#:@?",
163  /* Host name: escape everything except ':', which may
164  * appear as part of an IPv6 literal address.
165  */
166  [URI_HOST] = "/#@?",
167  /* Port number: escape everything */
168  [URI_PORT] = "/#:@?",
169  /* Path: escape everything except '/', which usually
170  * appears within paths.
171  */
172  [URI_PATH] = "#:@?",
173  };
174 
175  /* Always escape non-printing characters and whitespace */
176  if ( ( ! isprint ( c ) ) || ( c == ' ' ) )
177  return 1;
178 
179  /* Escape nothing else in already-escaped fields */
180  if ( field >= URI_EPATH )
181  return 0;
182 
183  /* Escape '%' and any field-specific characters */
184  if ( ( c == '%' ) || strchr ( escaped[field], c ) )
185  return 1;
186 
187  return 0;
188 }
Definition: uri.h:116
uint32_t c
Definition: md4.c:30
Definition: uri.h:117
static int isprint(int character)
Check if character is printable.
Definition: ctype.h:86
Definition: uri.h:118
char * strchr(const char *src, int character)
Find character within a string.
Definition: string.c:271
Definition: uri.h:114
Definition: uri.h:119

References c, isprint(), strchr(), URI_EPATH, URI_HOST, URI_OPAQUE, URI_PASSWORD, URI_PATH, URI_PORT, URI_SCHEME, and URI_USER.

Referenced by uri_encode().

◆ uri_encode()

size_t uri_encode ( unsigned int  field,
const void *  raw,
size_t  raw_len,
char *  buf,
ssize_t  len 
)

Encode URI field.

Parameters
fieldURI field index
rawRaw data
raw_lenLength of raw data
bufBuffer
lenLength of buffer
Return values
lenLength of encoded string (excluding NUL)

Definition at line 200 of file uri.c.

201  {
202  const uint8_t *raw_bytes = ( ( const uint8_t * ) raw );
203  ssize_t remaining = len;
204  size_t used;
205  char c;
206 
207  /* Ensure encoded string is NUL-terminated even if empty */
208  if ( len > 0 )
209  buf[0] = '\0';
210 
211  /* Copy string, escaping as necessary */
212  while ( raw_len-- ) {
213  c = *(raw_bytes++);
214  if ( uri_character_escaped ( c, field ) ) {
215  used = ssnprintf ( buf, remaining, "%%%02X", c );
216  } else {
217  used = ssnprintf ( buf, remaining, "%c", c );
218  }
219  buf += used;
220  remaining -= used;
221  }
222 
223  return ( len - remaining );
224 }
uint32_t c
Definition: md4.c:30
int ssnprintf(char *buf, ssize_t ssize, const char *fmt,...)
Version of vsnprintf() that accepts a signed buffer size.
Definition: vsprintf.c:420
static size_t raw_len
Definition: base16.h:50
static int uri_character_escaped(char c, unsigned int field)
Check if character should be escaped within a URI field.
Definition: uri.c:106
unsigned char uint8_t
Definition: stdint.h:10
uint32_t len
Length.
Definition: ena.h:14
__be32 raw[7]
Definition: CIB_PRM.h:28
signed long ssize_t
Definition: stdint.h:7

References c, len, raw, raw_len, ssnprintf(), and uri_character_escaped().

Referenced by format_uristring_setting(), ocsp_uri_string(), and uri_encode_string().

◆ uri_encode_string()

size_t uri_encode_string ( unsigned int  field,
const char *  string,
char *  buf,
ssize_t  len 
)

Encode URI field string.

Parameters
fieldURI field index
stringString
bufBuffer
lenLength of buffer
Return values
lenLength of encoded string (excluding NUL)

Definition at line 235 of file uri.c.

236  {
237 
238  return uri_encode ( field, string, strlen ( string ), buf, len );
239 }
size_t uri_encode(unsigned int field, const void *raw, size_t raw_len, char *buf, ssize_t len)
Encode URI field.
Definition: uri.c:200
size_t strlen(const char *src)
Get length of string.
Definition: string.c:243
uint32_t len
Length.
Definition: ena.h:14

References len, strlen(), and uri_encode().

Referenced by format_uri(), and http_params().

◆ uri_dump()

static void uri_dump ( const struct uri uri)
static

Dump URI for debugging.

Parameters
uriURI

Definition at line 246 of file uri.c.

246  {
247 
248  if ( ! uri )
249  return;
250  if ( uri->scheme )
251  DBGC ( uri, " scheme \"%s\"", uri->scheme );
252  if ( uri->opaque )
253  DBGC ( uri, " opaque \"%s\"", uri->opaque );
254  if ( uri->user )
255  DBGC ( uri, " user \"%s\"", uri->user );
256  if ( uri->password )
257  DBGC ( uri, " password \"%s\"", uri->password );
258  if ( uri->host )
259  DBGC ( uri, " host \"%s\"", uri->host );
260  if ( uri->port )
261  DBGC ( uri, " port \"%s\"", uri->port );
262  if ( uri->path )
263  DBGC ( uri, " path \"%s\"", uri->path );
264  if ( uri->epath )
265  DBGC ( uri, " epath \"%s\"", uri->epath );
266  if ( uri->equery )
267  DBGC ( uri, " equery \"%s\"", uri->equery );
268  if ( uri->efragment )
269  DBGC ( uri, " efragment \"%s\"", uri->efragment );
270  if ( uri->params )
271  DBGC ( uri, " params \"%s\"", uri->params->name );
272 }
const char * equery
Query (with original URI encoding)
Definition: uri.h:84
#define DBGC(...)
Definition: compiler.h:505
const char * port
Port number.
Definition: uri.h:78
const char * scheme
Scheme.
Definition: uri.h:68
const char * path
Path (after URI decoding)
Definition: uri.h:80
struct parameters * params
Form parameters.
Definition: uri.h:88
const char * name
Name.
Definition: params.h:22
const char * host
Host name.
Definition: uri.h:76
const char * efragment
Fragment (with original URI encoding)
Definition: uri.h:86
const char * opaque
Opaque part.
Definition: uri.h:70
const char * password
Password.
Definition: uri.h:74
const char * epath
Path (with original URI encoding)
Definition: uri.h:82
const char * user
User name.
Definition: uri.h:72
A Uniform Resource Identifier.
Definition: uri.h:64

References DBGC, uri::efragment, uri::epath, uri::equery, uri::host, parameters::name, uri::opaque, uri::params, uri::password, uri::path, uri::port, uri::scheme, and uri::user.

Referenced by format_uri(), parse_uri(), and uri_dup().

◆ uri_free()

static void uri_free ( struct refcnt refcnt)
static

Free URI.

Parameters
refcntReference count

Definition at line 279 of file uri.c.

279  {
280  struct uri *uri = container_of ( refcnt, struct uri, refcnt );
281 
282  params_put ( uri->params );
283  free ( uri );
284 }
A reference counter.
Definition: refcnt.h:26
#define container_of(ptr, type, field)
Get containing structure.
Definition: stddef.h:35
struct parameters * params
Form parameters.
Definition: uri.h:88
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:54
A Uniform Resource Identifier.
Definition: uri.h:64

References container_of, free, and uri::params.

Referenced by parse_uri(), and uri_dup().

◆ parse_uri()

struct uri* parse_uri ( const char *  uri_string)

Parse URI.

Parameters
uri_stringURI as a string
Return values
uriURI

Splits a URI into its component parts. The return URI structure is dynamically allocated and must eventually be freed by calling uri_put().

Definition at line 296 of file uri.c.

296  {
297  struct uri *uri;
298  struct parameters *params;
299  char *raw;
300  char *tmp;
301  char *path;
302  char *epath;
303  char *authority;
304  size_t raw_len;
305  unsigned int field;
306 
307  /* Allocate space for URI struct and two copies of the string */
308  raw_len = ( strlen ( uri_string ) + 1 /* NUL */ );
309  uri = zalloc ( sizeof ( *uri ) + ( 2 * raw_len ) );
310  if ( ! uri )
311  return NULL;
312  ref_init ( &uri->refcnt, uri_free );
313  raw = ( ( ( void * ) uri ) + sizeof ( *uri ) );
314  path = ( raw + raw_len );
315 
316  /* Copy in the raw string */
317  memcpy ( raw, uri_string, raw_len );
318 
319  /* Identify the parameter list, if present */
320  if ( ( tmp = strstr ( raw, "##params" ) ) ) {
321  *tmp = '\0';
322  tmp += 8 /* "##params" */;
323  params = find_parameters ( *tmp ? ( tmp + 1 ) : NULL );
324  if ( params ) {
325  uri->params = claim_parameters ( params );
326  } else {
327  /* Ignore non-existent submission blocks */
328  }
329  }
330 
331  /* Chop off the fragment, if it exists */
332  if ( ( tmp = strchr ( raw, '#' ) ) ) {
333  *(tmp++) = '\0';
334  uri->efragment = tmp;
335  }
336 
337  /* Identify absolute URIs */
338  epath = raw;
339  for ( tmp = raw ; ; tmp++ ) {
340  /* Possible scheme character (for our URI schemes) */
341  if ( isalpha ( *tmp ) || ( *tmp == '-' ) || ( *tmp == '_' ) )
342  continue;
343  /* Invalid scheme character or NUL: is a relative URI */
344  if ( *tmp != ':' )
345  break;
346  /* Absolute URI: identify hierarchical/opaque */
347  uri->scheme = raw;
348  *(tmp++) = '\0';
349  if ( *tmp == '/' ) {
350  /* Absolute URI with hierarchical part */
351  epath = tmp;
352  } else {
353  /* Absolute URI with opaque part */
354  uri->opaque = tmp;
355  epath = NULL;
356  }
357  break;
358  }
359 
360  /* If we don't have a path (i.e. we have an absolute URI with
361  * an opaque portion, we're already finished processing
362  */
363  if ( ! epath )
364  goto done;
365 
366  /* Chop off the query, if it exists */
367  if ( ( tmp = strchr ( epath, '?' ) ) ) {
368  *(tmp++) = '\0';
369  uri->equery = tmp;
370  }
371 
372  /* If we have no path remaining, then we're already finished
373  * processing.
374  */
375  if ( ! epath[0] )
376  goto done;
377 
378  /* Identify net/absolute/relative path */
379  if ( uri->scheme && ( strncmp ( epath, "//", 2 ) == 0 ) ) {
380  /* Net path. If this is terminated by the first '/'
381  * of an absolute path, then we have no space for a
382  * terminator after the authority field, so shuffle
383  * the authority down by one byte, overwriting one of
384  * the two slashes.
385  */
386  authority = ( epath + 2 );
387  if ( ( tmp = strchr ( authority, '/' ) ) ) {
388  /* Shuffle down */
389  uri->epath = tmp;
390  memmove ( ( authority - 1 ), authority,
391  ( tmp - authority ) );
392  authority--;
393  *(--tmp) = '\0';
394  }
395  } else {
396  /* Absolute/relative path */
397  uri->epath = epath;
398  authority = NULL;
399  }
400 
401  /* Create copy of path for decoding */
402  if ( uri->epath ) {
403  strcpy ( path, uri->epath );
404  uri->path = path;
405  }
406 
407  /* If we don't have an authority (i.e. we have a non-net
408  * path), we're already finished processing
409  */
410  if ( ! authority )
411  goto done;
412 
413  /* Split authority into user[:password] and host[:port] portions */
414  if ( ( tmp = strchr ( authority, '@' ) ) ) {
415  /* Has user[:password] */
416  *(tmp++) = '\0';
417  uri->host = tmp;
418  uri->user = authority;
419  if ( ( tmp = strchr ( authority, ':' ) ) ) {
420  /* Has password */
421  *(tmp++) = '\0';
422  uri->password = tmp;
423  }
424  } else {
425  /* No user:password */
426  uri->host = authority;
427  }
428 
429  /* Split host into host[:port] */
430  if ( ( tmp = strrchr ( uri->host, ':' ) ) &&
431  ( uri->host[ strlen ( uri->host ) - 1 ] != ']' ) ) {
432  *(tmp++) = '\0';
433  uri->port = tmp;
434  }
435 
436  done:
437  /* Decode fields in-place */
438  for ( field = 0 ; field < URI_EPATH ; field++ )
439  uri_decode_inplace ( ( char * ) uri_field ( uri, field ) );
440 
441  DBGC ( uri, "URI parsed \"%s\" to", uri_string );
442  uri_dump ( uri );
443  DBGC ( uri, "\n" );
444 
445  return uri;
446 }
const char * equery
Query (with original URI encoding)
Definition: uri.h:84
static void uri_dump(const struct uri *uri)
Dump URI for debugging.
Definition: uri.c:246
char * strrchr(const char *src, int character)
Find rightmost character within a string.
Definition: string.c:289
#define ref_init(refcnt, free)
Initialise a reference counter.
Definition: refcnt.h:64
A form parameter list.
Definition: params.h:16
#define DBGC(...)
Definition: compiler.h:505
static int isalpha(int character)
Check if character is alphabetic.
Definition: ctype.h:64
struct parameters * find_parameters(const char *name)
Find form parameter list by name.
Definition: params.c:68
int strncmp(const char *first, const char *second, size_t max)
Compare strings.
Definition: string.c:186
const char * port
Port number.
Definition: uri.h:78
char * strstr(const char *haystack, const char *needle)
Find substring.
Definition: string.c:309
const char * scheme
Scheme.
Definition: uri.h:68
void * memcpy(void *dest, const void *src, size_t len) __nonnull
const char * path
Path (after URI decoding)
Definition: uri.h:80
char * strcpy(char *dest, const char *src)
Copy string.
Definition: string.c:326
struct parameters * params
Form parameters.
Definition: uri.h:88
static void uri_decode_inplace(char *encoded)
Decode URI field in-place.
Definition: uri.c:84
static size_t raw_len
Definition: base16.h:50
void * zalloc(size_t size)
Allocate cleared memory.
Definition: malloc.c:624
char * strchr(const char *src, int character)
Find character within a string.
Definition: string.c:271
uint8_t * tmp
Definition: entropy.h:156
size_t strlen(const char *src)
Get length of string.
Definition: string.c:243
const char * host
Host name.
Definition: uri.h:76
void * memmove(void *dest, const void *src, size_t len) __nonnull
Definition: uri.h:119
const char * efragment
Fragment (with original URI encoding)
Definition: uri.h:86
#define uri_field(uri, field)
Access URI field.
Definition: uri.h:98
const char * opaque
Opaque part.
Definition: uri.h:70
struct refcnt refcnt
Reference count.
Definition: uri.h:66
static void uri_free(struct refcnt *refcnt)
Free URI.
Definition: uri.c:279
const char * password
Password.
Definition: uri.h:74
const char * epath
Path (with original URI encoding)
Definition: uri.h:82
__be32 raw[7]
Definition: CIB_PRM.h:28
const char * user
User name.
Definition: uri.h:72
A Uniform Resource Identifier.
Definition: uri.h:64
#define NULL
NULL pointer (VOID *)
Definition: Base.h:362
struct bofm_section_header done
Definition: bofm_test.c:46

References DBGC, done, uri::efragment, uri::epath, uri::equery, find_parameters(), uri::host, isalpha(), memcpy(), memmove(), NULL, uri::opaque, uri::params, uri::password, uri::path, uri::port, raw, raw_len, ref_init, uri::refcnt, uri::scheme, strchr(), strcpy(), strlen(), strncmp(), strrchr(), strstr(), tmp, uri_decode_inplace(), uri_dump(), URI_EPATH, uri_field, uri_free(), uri::user, and zalloc().

Referenced by fetch_root_path(), http_redirect(), imgdownload_string(), peerblk_retrieval_uri(), pxe_uri(), sanboot_core_exec(), tftp_apply_settings(), uri_churi_okx(), uri_params_okx(), uri_parse_okx(), uri_port_okx(), uri_resolve_okx(), and xfer_open_uri_string().

◆ uri_port()

unsigned int uri_port ( const struct uri uri,
unsigned int  default_port 
)

Get port from URI.

Parameters
uriURI, or NULL
default_portDefault port to use if none specified in URI
Return values
portPort

Definition at line 455 of file uri.c.

455  {
456 
457  if ( ( ! uri ) || ( ! uri->port ) )
458  return default_port;
459 
460  return ( strtoul ( uri->port, NULL, 0 ) );
461 }
unsigned long strtoul(const char *string, char **endp, int base)
Convert string to numeric value.
Definition: string.c:471
const char * port
Port number.
Definition: uri.h:78
A Uniform Resource Identifier.
Definition: uri.h:64
#define NULL
NULL pointer (VOID *)
Definition: Base.h:362

References NULL, uri::port, and strtoul().

Referenced by ftp_open(), http_connect(), slam_open(), tcp_open_uri(), tftp_core_open(), udp_open_uri(), and uri_port_okx().

◆ format_uri()

size_t format_uri ( const struct uri uri,
char *  buf,
size_t  len 
)

Format URI.

Parameters
uriURI
bufBuffer to fill with URI string
sizeSize of buffer
Return values
lenLength of URI string

Definition at line 471 of file uri.c.

471  {
472  static const char prefixes[URI_FIELDS] = {
473  [URI_PASSWORD] = ':',
474  [URI_PORT] = ':',
475  [URI_EQUERY] = '?',
476  [URI_EFRAGMENT] = '#',
477  };
478  char prefix;
479  size_t used = 0;
480  unsigned int field;
481 
482  /* Ensure buffer is NUL-terminated */
483  if ( len )
484  buf[0] = '\0';
485 
486  /* Special-case NULL URI */
487  if ( ! uri )
488  return 0;
489 
490  /* Generate fields */
491  for ( field = 0 ; field < URI_FIELDS ; field++ ) {
492 
493  /* Skip non-existent fields */
494  if ( ! uri_field ( uri, field ) )
495  continue;
496 
497  /* Skip path field if encoded path is present */
498  if ( ( field == URI_PATH ) && uri->epath )
499  continue;
500 
501  /* Prefix this field, if applicable */
502  prefix = prefixes[field];
503  if ( ( field == URI_HOST ) && ( uri->user != NULL ) )
504  prefix = '@';
505  if ( prefix ) {
506  used += ssnprintf ( ( buf + used ), ( len - used ),
507  "%c", prefix );
508  }
509 
510  /* Encode this field */
511  used += uri_encode_string ( field, uri_field ( uri, field ),
512  ( buf + used ), ( len - used ) );
513 
514  /* Suffix this field, if applicable */
515  if ( field == URI_SCHEME ) {
516  used += ssnprintf ( ( buf + used ), ( len - used ),
517  ":%s", ( uri->host ? "//" : "" ) );
518  }
519  }
520 
521  if ( len ) {
522  DBGC ( uri, "URI formatted" );
523  uri_dump ( uri );
524  DBGC ( uri, " to \"%s%s\"\n", buf,
525  ( ( used > len ) ? "<TRUNCATED>" : "" ) );
526  }
527 
528  return used;
529 }
Definition: uri.h:116
size_t uri_encode_string(unsigned int field, const char *string, char *buf, ssize_t len)
Encode URI field string.
Definition: uri.c:235
static void uri_dump(const struct uri *uri)
Dump URI for debugging.
Definition: uri.c:246
#define DBGC(...)
Definition: compiler.h:505
char prefix[4]
Definition: vmconsole.c:53
Definition: uri.h:117
int ssnprintf(char *buf, ssize_t ssize, const char *fmt,...)
Version of vsnprintf() that accepts a signed buffer size.
Definition: vsprintf.c:420
Definition: uri.h:118
const char * host
Host name.
Definition: uri.h:76
uint32_t len
Length.
Definition: ena.h:14
#define uri_field(uri, field)
Access URI field.
Definition: uri.h:98
const char * epath
Path (with original URI encoding)
Definition: uri.h:82
const char * user
User name.
Definition: uri.h:72
A Uniform Resource Identifier.
Definition: uri.h:64
#define NULL
NULL pointer (VOID *)
Definition: Base.h:362

References DBGC, uri::epath, uri::host, len, NULL, prefix, ssnprintf(), uri_dump(), URI_EFRAGMENT, uri_encode_string(), URI_EQUERY, uri_field, URI_FIELDS, URI_HOST, URI_PASSWORD, URI_PATH, URI_PORT, URI_SCHEME, and uri::user.

Referenced by efi_uri_path(), format_uri_alloc(), http_open(), multiboot_add_cmdline(), uri_format_okx(), and uri_pxe_okx().

◆ format_uri_alloc()

char* format_uri_alloc ( const struct uri uri)

Format URI.

Parameters
uriURI
Return values
stringURI string, or NULL on failure

The caller is responsible for eventually freeing the allocated memory.

Definition at line 540 of file uri.c.

540  {
541  size_t len;
542  char *string;
543 
544  len = ( format_uri ( uri, NULL, 0 ) + 1 /* NUL */ );
545  string = malloc ( len );
546  if ( string )
547  format_uri ( uri, string, len );
548  return string;
549 }
uint32_t string
Definition: multiboot.h:14
size_t format_uri(const struct uri *uri, char *buf, size_t len)
Format URI.
Definition: uri.c:471
void * malloc(size_t size)
Allocate memory.
Definition: malloc.c:583
uint32_t len
Length.
Definition: ena.h:14
A Uniform Resource Identifier.
Definition: uri.h:64
#define NULL
NULL pointer (VOID *)
Definition: Base.h:362

References format_uri(), len, malloc(), NULL, and string.

Referenced by imgdownload(), uri_churi_okx(), uri_format_okx(), and uri_resolve_okx().

◆ uri_copy_fields()

static size_t uri_copy_fields ( const struct uri src,
struct uri dest 
)
static

Copy URI fields.

Parameters
srcSource URI
destDestination URI, or NULL to calculate length
Return values
lenLength of raw URI

Definition at line 558 of file uri.c.

558  {
559  size_t len = sizeof ( *dest );
560  char *out = ( ( void * ) dest + len );
561  unsigned int field;
562  size_t field_len;
563 
564  /* Copy existent fields */
565  for ( field = 0 ; field < URI_FIELDS ; field++ ) {
566 
567  /* Skip non-existent fields */
568  if ( ! uri_field ( src, field ) )
569  continue;
570 
571  /* Calculate field length */
572  field_len = ( strlen ( uri_field ( src, field ) )
573  + 1 /* NUL */ );
574  len += field_len;
575 
576  /* Copy field, if applicable */
577  if ( dest ) {
578  memcpy ( out, uri_field ( src, field ), field_len );
579  uri_field ( dest, field ) = out;
580  out += field_len;
581  }
582  }
583  return len;
584 }
void * memcpy(void *dest, const void *src, size_t len) __nonnull
__be32 out[4]
Definition: CIB_PRM.h:36
static void * dest
Definition: strings.h:176
static __always_inline void off_t userptr_t src
Definition: efi_uaccess.h:66
size_t strlen(const char *src)
Get length of string.
Definition: string.c:243
uint32_t len
Length.
Definition: ena.h:14
#define uri_field(uri, field)
Access URI field.
Definition: uri.h:98

References dest, len, memcpy(), out, src, strlen(), uri_field, and URI_FIELDS.

Referenced by uri_dup().

◆ uri_dup()

struct uri* uri_dup ( const struct uri uri)

Duplicate URI.

Parameters
uriURI
Return values
uriDuplicate URI

Creates a modifiable copy of a URI.

Definition at line 594 of file uri.c.

594  {
595  struct uri *dup;
596  size_t len;
597 
598  /* Allocate new URI */
599  len = uri_copy_fields ( uri, NULL );
600  dup = zalloc ( len );
601  if ( ! dup )
602  return NULL;
603  ref_init ( &dup->refcnt, uri_free );
604 
605  /* Copy fields */
606  uri_copy_fields ( uri, dup );
607 
608  /* Copy parameters */
609  dup->params = params_get ( uri->params );
610 
611  DBGC ( uri, "URI duplicated" );
612  uri_dump ( uri );
613  DBGC ( uri, "\n" );
614 
615  return dup;
616 }
static void uri_dump(const struct uri *uri)
Dump URI for debugging.
Definition: uri.c:246
#define ref_init(refcnt, free)
Initialise a reference counter.
Definition: refcnt.h:64
#define DBGC(...)
Definition: compiler.h:505
static size_t uri_copy_fields(const struct uri *src, struct uri *dest)
Copy URI fields.
Definition: uri.c:558
struct parameters * params
Form parameters.
Definition: uri.h:88
void * zalloc(size_t size)
Allocate cleared memory.
Definition: malloc.c:624
uint32_t len
Length.
Definition: ena.h:14
struct refcnt refcnt
Reference count.
Definition: uri.h:66
static void uri_free(struct refcnt *refcnt)
Free URI.
Definition: uri.c:279
A Uniform Resource Identifier.
Definition: uri.h:64
#define NULL
NULL pointer (VOID *)
Definition: Base.h:362

References DBGC, len, NULL, uri::params, ref_init, uri::refcnt, uri_copy_fields(), uri_dump(), uri_free(), and zalloc().

Referenced by resolve_uri(), tftp_uri(), uri_dup_okx(), and uri_params_okx().

◆ resolve_path()

char* resolve_path ( const char *  base_path,
const char *  relative_path 
)

Resolve base+relative path.

Parameters
base_uriBase path
relative_uriRelative path
Return values
resolved_uriResolved path, or NULL on failure

Takes a base path (e.g. "/var/lib/tftpboot/vmlinuz" and a relative path (e.g. "initrd.gz") and produces a new path (e.g. "/var/lib/tftpboot/initrd.gz"). Note that any non-directory portion of the base path will automatically be stripped; this matches the semantics used when resolving the path component of URIs.

Definition at line 632 of file uri.c.

633  {
634  char *base_copy;
635  char *base_tmp;
636  char *resolved;
637 
638  /* If relative path is absolute, just re-use it */
639  if ( relative_path[0] == '/' )
640  return strdup ( relative_path );
641 
642  /* Create modifiable copy of path for dirname() */
643  base_copy = strdup ( base_path );
644  if ( ! base_copy )
645  return NULL;
646 
647  /* Strip filename portion of base path */
648  base_tmp = dirname ( base_copy );
649 
650  /* Process "./" and "../" elements */
651  while ( *relative_path == '.' ) {
652  relative_path++;
653  if ( *relative_path == 0 ) {
654  /* Do nothing */
655  } else if ( *relative_path == '/' ) {
656  relative_path++;
657  } else if ( *relative_path == '.' ) {
658  relative_path++;
659  if ( *relative_path == 0 ) {
660  base_tmp = dirname ( base_tmp );
661  } else if ( *relative_path == '/' ) {
662  base_tmp = dirname ( base_tmp );
663  relative_path++;
664  } else {
665  relative_path -= 2;
666  break;
667  }
668  } else {
669  relative_path--;
670  break;
671  }
672  }
673 
674  /* Create and return new path */
675  if ( asprintf ( &resolved, "%s%s%s", base_tmp,
676  ( ( base_tmp[ strlen ( base_tmp ) - 1 ] == '/' ) ?
677  "" : "/" ), relative_path ) < 0 )
678  resolved = NULL;
679  free ( base_copy );
680  return resolved;
681 }
char * dirname(char *path)
Return directory name from path.
Definition: basename.c:57
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:54
int asprintf(char **strp, const char *fmt,...)
Write a formatted string to newly allocated memory.
Definition: asprintf.c:41
char * strdup(const char *src)
Duplicate string.
Definition: string.c:380
size_t strlen(const char *src)
Get length of string.
Definition: string.c:243
#define NULL
NULL pointer (VOID *)
Definition: Base.h:362

References asprintf(), dirname(), free, NULL, strdup(), and strlen().

Referenced by efi_local_open_path(), resolve_uri(), and uri_resolve_path_okx().

◆ resolve_uri()

struct uri* resolve_uri ( const struct uri base_uri,
struct uri relative_uri 
)

Resolve base+relative URI.

Parameters
base_uriBase URI, or NULL
relative_uriRelative URI
Return values
resolved_uriResolved URI, or NULL on failure

Takes a base URI (e.g. "http://ipxe.org/kernels/vmlinuz" and a relative URI (e.g. "../initrds/initrd.gz") and produces a new URI (e.g. "http://ipxe.org/initrds/initrd.gz").

Definition at line 694 of file uri.c.

695  {
696  struct uri tmp_uri;
697  char *tmp_epath = NULL;
698  char *tmp_path = NULL;
699  struct uri *new_uri;
700 
701  /* If relative URI is absolute, just re-use it */
702  if ( uri_is_absolute ( relative_uri ) || ( ! base_uri ) )
703  return uri_get ( relative_uri );
704 
705  /* Mangle URI */
706  memcpy ( &tmp_uri, base_uri, sizeof ( tmp_uri ) );
707  if ( relative_uri->epath ) {
708  tmp_epath = resolve_path ( ( base_uri->epath ?
709  base_uri->epath : "/" ),
710  relative_uri->epath );
711  if ( ! tmp_epath )
712  goto err_epath;
713  tmp_path = strdup ( tmp_epath );
714  if ( ! tmp_path )
715  goto err_path;
716  uri_decode_inplace ( tmp_path );
717  tmp_uri.epath = tmp_epath;
718  tmp_uri.path = tmp_path;
719  tmp_uri.equery = relative_uri->equery;
720  tmp_uri.efragment = relative_uri->efragment;
721  tmp_uri.params = relative_uri->params;
722  } else if ( relative_uri->equery ) {
723  tmp_uri.equery = relative_uri->equery;
724  tmp_uri.efragment = relative_uri->efragment;
725  tmp_uri.params = relative_uri->params;
726  } else if ( relative_uri->efragment ) {
727  tmp_uri.efragment = relative_uri->efragment;
728  tmp_uri.params = relative_uri->params;
729  } else if ( relative_uri->params ) {
730  tmp_uri.params = relative_uri->params;
731  }
732 
733  /* Create demangled URI */
734  new_uri = uri_dup ( &tmp_uri );
735  free ( tmp_path );
736  free ( tmp_epath );
737  return new_uri;
738 
739  free ( tmp_path );
740  err_path:
741  free ( tmp_epath );
742  err_epath:
743  return NULL;
744 }
const char * equery
Query (with original URI encoding)
Definition: uri.h:84
static struct uri * uri_get(struct uri *uri)
Increment URI reference count.
Definition: uri.h:194
static int uri_is_absolute(const struct uri *uri)
URI is an absolute URI.
Definition: uri.h:135
void * memcpy(void *dest, const void *src, size_t len) __nonnull
char * resolve_path(const char *base_path, const char *relative_path)
Resolve base+relative path.
Definition: uri.c:632
struct parameters * params
Form parameters.
Definition: uri.h:88
static void uri_decode_inplace(char *encoded)
Decode URI field in-place.
Definition: uri.c:84
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:54
struct uri * uri_dup(const struct uri *uri)
Duplicate URI.
Definition: uri.c:594
char * strdup(const char *src)
Duplicate string.
Definition: string.c:380
const char * efragment
Fragment (with original URI encoding)
Definition: uri.h:86
const char * epath
Path (with original URI encoding)
Definition: uri.h:82
A Uniform Resource Identifier.
Definition: uri.h:64
#define NULL
NULL pointer (VOID *)
Definition: Base.h:362

References uri::efragment, uri::epath, uri::equery, free, memcpy(), NULL, uri::params, uri::path, resolve_path(), strdup(), uri_decode_inplace(), uri_dup(), uri_get(), and uri_is_absolute().

Referenced by churi(), http_redirect(), imgdownload(), uri_resolve_okx(), and xfer_open_uri().

◆ tftp_uri()

static struct uri* tftp_uri ( struct sockaddr sa_server,
const char *  filename 
)
static

Construct TFTP URI from server address and filename.

Parameters
sa_serverServer address
filenameFilename
Return values
uriURI, or NULL on failure

Definition at line 753 of file uri.c.

754  {
755  struct sockaddr_tcpip *st_server =
756  ( ( struct sockaddr_tcpip * ) sa_server );
757  char buf[ 6 /* "65535" + NUL */ ];
758  char *path;
759  struct uri tmp;
760  struct uri *uri = NULL;
761 
762  /* Initialise TFTP URI */
763  memset ( &tmp, 0, sizeof ( tmp ) );
764  tmp.scheme = "tftp";
765 
766  /* Construct TFTP server address */
767  tmp.host = sock_ntoa ( sa_server );
768  if ( ! tmp.host )
769  goto err_host;
770 
771  /* Construct TFTP server port, if applicable */
772  if ( st_server->st_port ) {
773  snprintf ( buf, sizeof ( buf ), "%d",
774  ntohs ( st_server->st_port ) );
775  tmp.port = buf;
776  }
777 
778  /* Construct TFTP path */
779  if ( asprintf ( &path, "/%s", filename ) < 0 )
780  goto err_path;
781  tmp.path = path;
782  tmp.epath = path;
783 
784  /* Demangle URI */
785  uri = uri_dup ( &tmp );
786  if ( ! uri )
787  goto err_uri;
788 
789  err_uri:
790  free ( path );
791  err_path:
792  err_host:
793  return uri;
794 }
TCP/IP socket address.
Definition: tcpip.h:75
#define ntohs(value)
Definition: byteswap.h:136
const char * path
Path (after URI decoding)
Definition: uri.h:80
uint16_t st_port
TCP/IP port.
Definition: tcpip.h:81
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:54
int asprintf(char **strp, const char *fmt,...)
Write a formatted string to newly allocated memory.
Definition: asprintf.c:41
struct uri * uri_dup(const struct uri *uri)
Duplicate URI.
Definition: uri.c:594
uint8_t * tmp
Definition: entropy.h:156
const char * sock_ntoa(struct sockaddr *sa)
Transcribe socket address.
Definition: socket.c:42
int snprintf(char *buf, size_t size, const char *fmt,...)
Write a formatted string to a buffer.
Definition: vsprintf.c:382
A Uniform Resource Identifier.
Definition: uri.h:64
#define NULL
NULL pointer (VOID *)
Definition: Base.h:362
void * memset(void *dest, int character, size_t len) __nonnull

References asprintf(), free, memset(), ntohs, NULL, uri::path, snprintf(), sock_ntoa(), sockaddr_tcpip::st_port, tmp, and uri_dup().

Referenced by pxe_uri().

◆ pxe_uri()

struct uri* pxe_uri ( struct sockaddr sa_server,
const char *  filename 
)

Construct URI from server address and filename.

Parameters
sa_serverServer address
filenameFilename
Return values
uriURI, or NULL on failure

PXE TFTP filenames specified via the DHCP next-server field often contain characters such as ':' or '#' which would confuse the generic URI parser. We provide a mechanism for directly constructing a TFTP URI from the next-server and filename.

Definition at line 808 of file uri.c.

808  {
809  struct uri *uri;
810 
811  /* Fail if filename is empty */
812  if ( ! ( filename && filename[0] ) )
813  return NULL;
814 
815  /* If filename is a hierarchical absolute URI, then use that
816  * URI. (We accept only hierarchical absolute URIs, since PXE
817  * filenames sometimes start with DOS drive letters such as
818  * "C:\", which get misinterpreted as opaque absolute URIs.)
819  */
820  uri = parse_uri ( filename );
821  if ( uri && uri_is_absolute ( uri ) && ( ! uri->opaque ) )
822  return uri;
823  uri_put ( uri );
824 
825  /* Otherwise, construct a TFTP URI directly */
826  return tftp_uri ( sa_server, filename );
827 }
static void uri_put(struct uri *uri)
Decrement URI reference count.
Definition: uri.h:205
static int uri_is_absolute(const struct uri *uri)
URI is an absolute URI.
Definition: uri.h:135
static struct uri * tftp_uri(struct sockaddr *sa_server, const char *filename)
Construct TFTP URI from server address and filename.
Definition: uri.c:753
const char * opaque
Opaque part.
Definition: uri.h:70
A Uniform Resource Identifier.
Definition: uri.h:64
#define NULL
NULL pointer (VOID *)
Definition: Base.h:362
struct uri * parse_uri(const char *uri_string)
Parse URI.
Definition: uri.c:296

References NULL, uri::opaque, parse_uri(), tftp_uri(), uri_is_absolute(), and uri_put().

Referenced by efi_pxe_tftp_open(), fetch_next_server_and_filename(), pxe_tftp_open(), and uri_pxe_okx().