iPXE
uri.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23 
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25 
26 /** @file
27  *
28  * Uniform Resource Identifiers
29  *
30  */
31 
32 #include <stdint.h>
33 #include <stdlib.h>
34 #include <string.h>
35 #include <libgen.h>
36 #include <ctype.h>
37 #include <ipxe/vsprintf.h>
38 #include <ipxe/params.h>
39 #include <ipxe/tcpip.h>
40 #include <ipxe/uri.h>
41 
42 /**
43  * Decode URI field
44  *
45  * @v encoded Encoded field
46  * @v buf Data buffer
47  * @v len Length
48  * @ret len Length of data
49  *
50  * URI decoding can never increase the length of a string; we can
51  * therefore safely decode in place.
52  */
53 size_t uri_decode ( const char *encoded, void *buf, size_t len ) {
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 }
78 
79 /**
80  * Decode URI field in-place
81  *
82  * @v uri URI
83  * @v field URI field index
84  */
85 static void uri_decode_inplace ( struct uri *uri, unsigned int field ) {
86  const char *encoded = uri_field ( uri, field );
87  char *decoded = ( ( char * ) encoded );
88  size_t len;
89 
90  /* Do nothing if field is not present */
91  if ( ! encoded )
92  return;
93 
94  /* Decode field in place */
95  len = uri_decode ( encoded, decoded, strlen ( encoded ) );
96 
97  /* Terminate decoded string */
98  decoded[len] = '\0';
99 }
100 
101 /**
102  * Check if character should be escaped within a URI field
103  *
104  * @v c Character
105  * @v field URI field index
106  * @ret escaped Character should be escaped
107  */
108 static int uri_character_escaped ( char c, unsigned int field ) {
109 
110  /* Non-printing characters and whitespace should always be
111  * escaped, since they cannot sensibly be displayed as part of
112  * a coherent URL string. (This test also catches control
113  * characters such as CR and LF, which could affect the
114  * operation of line-based protocols such as HTTP.)
115  *
116  * We should also escape characters which would alter the
117  * interpretation of the URL if not escaped, i.e. characters
118  * which have significance to the URL parser. We should not
119  * blindly escape all such characters, because this would lead
120  * to some very strange-looking URLs (e.g. if we were to
121  * always escape '/' as "%2F" even within the URI path).
122  *
123  * We do not need to be perfect. Our primary role is as a
124  * consumer of URIs rather than a producer; the main situation
125  * in which we produce a URI string is for display to a human
126  * user, who can probably tolerate some variance from the
127  * formal specification. The only situation in which we
128  * currently produce a URI string to be consumed by a computer
129  * is when constructing an HTTP request URI, which contains
130  * only the path and query fields.
131  *
132  * We can therefore sacrifice some correctness for the sake of
133  * code size. For example, colons within the URI host should
134  * be escaped unless they form part of an IPv6 literal
135  * address; doing this correctly would require the URI
136  * formatter to be aware of whether or not the URI host
137  * contained an IPv4 address, an IPv6 address, or a host name.
138  * We choose to simplify and never escape colons within the
139  * URI host field: in the event of a pathological hostname
140  * containing colons, this could potentially produce a URI
141  * string which could not be reparsed.
142  *
143  * After excluding non-printing characters, whitespace, and
144  * '%', the full set of characters with significance to the
145  * URL parser is "/#:@?". We choose for each URI field which
146  * of these require escaping in our use cases.
147  *
148  * For the scheme field (equivalently, if field is zero), we
149  * escape anything that has significance not just for our URI
150  * parser but for any other URI parsers (e.g. HTTP query
151  * string parsers, which care about '=' and '&').
152  */
153  static const char *escaped[URI_FIELDS] = {
154  /* Scheme or default: escape everything */
155  [URI_SCHEME] = "/#:@?=&",
156  /* Opaque part: escape characters which would affect
157  * the reparsing of the URI, allowing everything else
158  * (e.g. ':', which will appear in iSCSI URIs).
159  */
160  [URI_OPAQUE] = "#",
161  /* User name: escape everything */
162  [URI_USER] = "/#:@?",
163  /* Password: escape everything */
164  [URI_PASSWORD] = "/#:@?",
165  /* Host name: escape everything except ':', which may
166  * appear as part of an IPv6 literal address.
167  */
168  [URI_HOST] = "/#@?",
169  /* Port number: escape everything */
170  [URI_PORT] = "/#:@?",
171  /* Path: escape everything except '/', which usually
172  * appears within paths.
173  */
174  [URI_PATH] = "#:@?",
175  /* Query: escape everything except '/', which
176  * sometimes appears within queries.
177  */
178  [URI_QUERY] = "#:@?",
179  /* Fragment: escape everything */
180  [URI_FRAGMENT] = "/#:@?",
181  };
182 
183  return ( /* Always escape non-printing characters and whitespace */
184  ( ! isprint ( c ) ) || ( c == ' ' ) ||
185  /* Always escape '%' */
186  ( c == '%' ) ||
187  /* Escape field-specific characters */
188  strchr ( escaped[field], c ) );
189 }
190 
191 /**
192  * Encode URI field
193  *
194  * @v field URI field index
195  * @v raw Raw data
196  * @v raw_len Length of raw data
197  * @v buf Buffer
198  * @v len Length of buffer
199  * @ret len Length of encoded string (excluding NUL)
200  */
201 size_t uri_encode ( unsigned int field, const void *raw, size_t raw_len,
202  char *buf, ssize_t len ) {
203  const uint8_t *raw_bytes = ( ( const uint8_t * ) raw );
204  ssize_t remaining = len;
205  size_t used;
206  char c;
207 
208  /* Ensure encoded string is NUL-terminated even if empty */
209  if ( len > 0 )
210  buf[0] = '\0';
211 
212  /* Copy string, escaping as necessary */
213  while ( raw_len-- ) {
214  c = *(raw_bytes++);
215  if ( uri_character_escaped ( c, field ) ) {
216  used = ssnprintf ( buf, remaining, "%%%02X", c );
217  } else {
218  used = ssnprintf ( buf, remaining, "%c", c );
219  }
220  buf += used;
221  remaining -= used;
222  }
223 
224  return ( len - remaining );
225 }
226 
227 /**
228  * Encode URI field string
229  *
230  * @v field URI field index
231  * @v string String
232  * @v buf Buffer
233  * @v len Length of buffer
234  * @ret len Length of encoded string (excluding NUL)
235  */
236 size_t uri_encode_string ( unsigned int field, const char *string,
237  char *buf, ssize_t len ) {
238 
239  return uri_encode ( field, string, strlen ( string ), buf, len );
240 }
241 
242 /**
243  * Dump URI for debugging
244  *
245  * @v uri URI
246  */
247 static void uri_dump ( const struct uri *uri ) {
248 
249  if ( ! uri )
250  return;
251  if ( uri->scheme )
252  DBGC ( uri, " scheme \"%s\"", uri->scheme );
253  if ( uri->opaque )
254  DBGC ( uri, " opaque \"%s\"", uri->opaque );
255  if ( uri->user )
256  DBGC ( uri, " user \"%s\"", uri->user );
257  if ( uri->password )
258  DBGC ( uri, " password \"%s\"", uri->password );
259  if ( uri->host )
260  DBGC ( uri, " host \"%s\"", uri->host );
261  if ( uri->port )
262  DBGC ( uri, " port \"%s\"", uri->port );
263  if ( uri->path )
264  DBGC ( uri, " path \"%s\"", uri->path );
265  if ( uri->query )
266  DBGC ( uri, " query \"%s\"", uri->query );
267  if ( uri->fragment )
268  DBGC ( uri, " fragment \"%s\"", uri->fragment );
269  if ( uri->params )
270  DBGC ( uri, " params \"%s\"", uri->params->name );
271 }
272 
273 /**
274  * Free URI
275  *
276  * @v refcnt Reference count
277  */
278 static void uri_free ( struct refcnt *refcnt ) {
279  struct uri *uri = container_of ( refcnt, struct uri, refcnt );
280 
281  params_put ( uri->params );
282  free ( uri );
283 }
284 
285 /**
286  * Parse URI
287  *
288  * @v uri_string URI as a string
289  * @ret uri URI
290  *
291  * Splits a URI into its component parts. The return URI structure is
292  * dynamically allocated and must eventually be freed by calling
293  * uri_put().
294  */
295 struct uri * parse_uri ( const char *uri_string ) {
296  struct uri *uri;
297  struct parameters *params;
298  char *raw;
299  char *tmp;
300  char *path;
301  char *authority;
302  size_t raw_len;
303  unsigned int field;
304 
305  /* Allocate space for URI struct and a copy of the string */
306  raw_len = ( strlen ( uri_string ) + 1 /* NUL */ );
307  uri = zalloc ( sizeof ( *uri ) + raw_len );
308  if ( ! uri )
309  return NULL;
310  ref_init ( &uri->refcnt, uri_free );
311  raw = ( ( ( void * ) uri ) + sizeof ( *uri ) );
312 
313  /* Copy in the raw string */
314  memcpy ( raw, uri_string, raw_len );
315 
316  /* Identify the parameter list, if present */
317  if ( ( tmp = strstr ( raw, "##params" ) ) ) {
318  *tmp = '\0';
319  tmp += 8 /* "##params" */;
320  params = find_parameters ( *tmp ? ( tmp + 1 ) : NULL );
321  if ( params ) {
322  uri->params = claim_parameters ( params );
323  } else {
324  /* Ignore non-existent submission blocks */
325  }
326  }
327 
328  /* Chop off the fragment, if it exists */
329  if ( ( tmp = strchr ( raw, '#' ) ) ) {
330  *(tmp++) = '\0';
331  uri->fragment = tmp;
332  }
333 
334  /* Identify absolute/relative URI */
335  if ( ( tmp = strchr ( raw, ':' ) ) ) {
336  /* Absolute URI: identify hierarchical/opaque */
337  uri->scheme = raw;
338  *(tmp++) = '\0';
339  if ( *tmp == '/' ) {
340  /* Absolute URI with hierarchical part */
341  path = tmp;
342  } else {
343  /* Absolute URI with opaque part */
344  uri->opaque = tmp;
345  path = NULL;
346  }
347  } else {
348  /* Relative URI */
349  path = raw;
350  }
351 
352  /* If we don't have a path (i.e. we have an absolute URI with
353  * an opaque portion, we're already finished processing
354  */
355  if ( ! path )
356  goto done;
357 
358  /* Chop off the query, if it exists */
359  if ( ( tmp = strchr ( path, '?' ) ) ) {
360  *(tmp++) = '\0';
361  uri->query = tmp;
362  }
363 
364  /* If we have no path remaining, then we're already finished
365  * processing.
366  */
367  if ( ! path[0] )
368  goto done;
369 
370  /* Identify net/absolute/relative path */
371  if ( uri->scheme && ( strncmp ( path, "//", 2 ) == 0 ) ) {
372  /* Net path. If this is terminated by the first '/'
373  * of an absolute path, then we have no space for a
374  * terminator after the authority field, so shuffle
375  * the authority down by one byte, overwriting one of
376  * the two slashes.
377  */
378  authority = ( path + 2 );
379  if ( ( tmp = strchr ( authority, '/' ) ) ) {
380  /* Shuffle down */
381  uri->path = tmp;
382  memmove ( ( authority - 1 ), authority,
383  ( tmp - authority ) );
384  authority--;
385  *(--tmp) = '\0';
386  }
387  } else {
388  /* Absolute/relative path */
389  uri->path = path;
390  authority = NULL;
391  }
392 
393  /* If we don't have an authority (i.e. we have a non-net
394  * path), we're already finished processing
395  */
396  if ( ! authority )
397  goto done;
398 
399  /* Split authority into user[:password] and host[:port] portions */
400  if ( ( tmp = strchr ( authority, '@' ) ) ) {
401  /* Has user[:password] */
402  *(tmp++) = '\0';
403  uri->host = tmp;
404  uri->user = authority;
405  if ( ( tmp = strchr ( authority, ':' ) ) ) {
406  /* Has password */
407  *(tmp++) = '\0';
408  uri->password = tmp;
409  }
410  } else {
411  /* No user:password */
412  uri->host = authority;
413  }
414 
415  /* Split host into host[:port] */
416  if ( ( uri->host[ strlen ( uri->host ) - 1 ] != ']' ) &&
417  ( tmp = strrchr ( uri->host, ':' ) ) ) {
418  *(tmp++) = '\0';
419  uri->port = tmp;
420  }
421 
422  done:
423  /* Decode fields in-place */
424  for ( field = 0 ; field < URI_FIELDS ; field++ )
425  uri_decode_inplace ( uri, field );
426 
427  DBGC ( uri, "URI parsed \"%s\" to", uri_string );
428  uri_dump ( uri );
429  DBGC ( uri, "\n" );
430 
431  return uri;
432 }
433 
434 /**
435  * Get port from URI
436  *
437  * @v uri URI, or NULL
438  * @v default_port Default port to use if none specified in URI
439  * @ret port Port
440  */
441 unsigned int uri_port ( const struct uri *uri, unsigned int default_port ) {
442 
443  if ( ( ! uri ) || ( ! uri->port ) )
444  return default_port;
445 
446  return ( strtoul ( uri->port, NULL, 0 ) );
447 }
448 
449 /**
450  * Format URI
451  *
452  * @v uri URI
453  * @v buf Buffer to fill with URI string
454  * @v size Size of buffer
455  * @ret len Length of URI string
456  */
457 size_t format_uri ( const struct uri *uri, char *buf, size_t len ) {
458  static const char prefixes[URI_FIELDS] = {
459  [URI_PASSWORD] = ':',
460  [URI_PORT] = ':',
461  [URI_QUERY] = '?',
462  [URI_FRAGMENT] = '#',
463  };
464  char prefix;
465  size_t used = 0;
466  unsigned int field;
467 
468  /* Ensure buffer is NUL-terminated */
469  if ( len )
470  buf[0] = '\0';
471 
472  /* Special-case NULL URI */
473  if ( ! uri )
474  return 0;
475 
476  /* Generate fields */
477  for ( field = 0 ; field < URI_FIELDS ; field++ ) {
478 
479  /* Skip non-existent fields */
480  if ( ! uri_field ( uri, field ) )
481  continue;
482 
483  /* Prefix this field, if applicable */
484  prefix = prefixes[field];
485  if ( ( field == URI_HOST ) && ( uri->user != NULL ) )
486  prefix = '@';
487  if ( prefix ) {
488  used += ssnprintf ( ( buf + used ), ( len - used ),
489  "%c", prefix );
490  }
491 
492  /* Encode this field */
493  used += uri_encode_string ( field, uri_field ( uri, field ),
494  ( buf + used ), ( len - used ) );
495 
496  /* Suffix this field, if applicable */
497  if ( field == URI_SCHEME ) {
498  used += ssnprintf ( ( buf + used ), ( len - used ),
499  ":%s", ( uri->host ? "//" : "" ) );
500  }
501  }
502 
503  if ( len ) {
504  DBGC ( uri, "URI formatted" );
505  uri_dump ( uri );
506  DBGC ( uri, " to \"%s%s\"\n", buf,
507  ( ( used > len ) ? "<TRUNCATED>" : "" ) );
508  }
509 
510  return used;
511 }
512 
513 /**
514  * Format URI
515  *
516  * @v uri URI
517  * @ret string URI string, or NULL on failure
518  *
519  * The caller is responsible for eventually freeing the allocated
520  * memory.
521  */
522 char * format_uri_alloc ( const struct uri *uri ) {
523  size_t len;
524  char *string;
525 
526  len = ( format_uri ( uri, NULL, 0 ) + 1 /* NUL */ );
527  string = malloc ( len );
528  if ( string )
529  format_uri ( uri, string, len );
530  return string;
531 }
532 
533 /**
534  * Copy URI fields
535  *
536  * @v src Source URI
537  * @v dest Destination URI, or NULL to calculate length
538  * @ret len Length of raw URI
539  */
540 static size_t uri_copy_fields ( const struct uri *src, struct uri *dest ) {
541  size_t len = sizeof ( *dest );
542  char *out = ( ( void * ) dest + len );
543  unsigned int field;
544  size_t field_len;
545 
546  /* Copy existent fields */
547  for ( field = 0 ; field < URI_FIELDS ; field++ ) {
548 
549  /* Skip non-existent fields */
550  if ( ! uri_field ( src, field ) )
551  continue;
552 
553  /* Calculate field length */
554  field_len = ( strlen ( uri_field ( src, field ) )
555  + 1 /* NUL */ );
556  len += field_len;
557 
558  /* Copy field, if applicable */
559  if ( dest ) {
560  memcpy ( out, uri_field ( src, field ), field_len );
561  uri_field ( dest, field ) = out;
562  out += field_len;
563  }
564  }
565  return len;
566 }
567 
568 /**
569  * Duplicate URI
570  *
571  * @v uri URI
572  * @ret uri Duplicate URI
573  *
574  * Creates a modifiable copy of a URI.
575  */
576 struct uri * uri_dup ( const struct uri *uri ) {
577  struct uri *dup;
578  size_t len;
579 
580  /* Allocate new URI */
581  len = uri_copy_fields ( uri, NULL );
582  dup = zalloc ( len );
583  if ( ! dup )
584  return NULL;
585  ref_init ( &dup->refcnt, uri_free );
586 
587  /* Copy fields */
588  uri_copy_fields ( uri, dup );
589 
590  /* Copy parameters */
591  dup->params = params_get ( uri->params );
592 
593  DBGC ( uri, "URI duplicated" );
594  uri_dump ( uri );
595  DBGC ( uri, "\n" );
596 
597  return dup;
598 }
599 
600 /**
601  * Resolve base+relative path
602  *
603  * @v base_uri Base path
604  * @v relative_uri Relative path
605  * @ret resolved_uri Resolved path, or NULL on failure
606  *
607  * Takes a base path (e.g. "/var/lib/tftpboot/vmlinuz" and a relative
608  * path (e.g. "initrd.gz") and produces a new path
609  * (e.g. "/var/lib/tftpboot/initrd.gz"). Note that any non-directory
610  * portion of the base path will automatically be stripped; this
611  * matches the semantics used when resolving the path component of
612  * URIs.
613  */
614 char * resolve_path ( const char *base_path,
615  const char *relative_path ) {
616  char *base_copy;
617  char *base_tmp;
618  char *resolved;
619 
620  /* If relative path is absolute, just re-use it */
621  if ( relative_path[0] == '/' )
622  return strdup ( relative_path );
623 
624  /* Create modifiable copy of path for dirname() */
625  base_copy = strdup ( base_path );
626  if ( ! base_copy )
627  return NULL;
628 
629  /* Strip filename portion of base path */
630  base_tmp = dirname ( base_copy );
631 
632  /* Process "./" and "../" elements */
633  while ( *relative_path == '.' ) {
634  relative_path++;
635  if ( *relative_path == 0 ) {
636  /* Do nothing */
637  } else if ( *relative_path == '/' ) {
638  relative_path++;
639  } else if ( *relative_path == '.' ) {
640  relative_path++;
641  if ( *relative_path == 0 ) {
642  base_tmp = dirname ( base_tmp );
643  } else if ( *relative_path == '/' ) {
644  base_tmp = dirname ( base_tmp );
645  relative_path++;
646  } else {
647  relative_path -= 2;
648  break;
649  }
650  } else {
651  relative_path--;
652  break;
653  }
654  }
655 
656  /* Create and return new path */
657  if ( asprintf ( &resolved, "%s%s%s", base_tmp,
658  ( ( base_tmp[ strlen ( base_tmp ) - 1 ] == '/' ) ?
659  "" : "/" ), relative_path ) < 0 )
660  resolved = NULL;
661  free ( base_copy );
662  return resolved;
663 }
664 
665 /**
666  * Resolve base+relative URI
667  *
668  * @v base_uri Base URI, or NULL
669  * @v relative_uri Relative URI
670  * @ret resolved_uri Resolved URI, or NULL on failure
671  *
672  * Takes a base URI (e.g. "http://ipxe.org/kernels/vmlinuz" and a
673  * relative URI (e.g. "../initrds/initrd.gz") and produces a new URI
674  * (e.g. "http://ipxe.org/initrds/initrd.gz").
675  */
676 struct uri * resolve_uri ( const struct uri *base_uri,
677  struct uri *relative_uri ) {
678  struct uri tmp_uri;
679  char *tmp_path = NULL;
680  struct uri *new_uri;
681 
682  /* If relative URI is absolute, just re-use it */
683  if ( uri_is_absolute ( relative_uri ) || ( ! base_uri ) )
684  return uri_get ( relative_uri );
685 
686  /* Mangle URI */
687  memcpy ( &tmp_uri, base_uri, sizeof ( tmp_uri ) );
688  if ( relative_uri->path ) {
689  tmp_path = resolve_path ( ( base_uri->path ?
690  base_uri->path : "/" ),
691  relative_uri->path );
692  tmp_uri.path = tmp_path;
693  tmp_uri.query = relative_uri->query;
694  tmp_uri.fragment = relative_uri->fragment;
695  tmp_uri.params = relative_uri->params;
696  } else if ( relative_uri->query ) {
697  tmp_uri.query = relative_uri->query;
698  tmp_uri.fragment = relative_uri->fragment;
699  tmp_uri.params = relative_uri->params;
700  } else if ( relative_uri->fragment ) {
701  tmp_uri.fragment = relative_uri->fragment;
702  tmp_uri.params = relative_uri->params;
703  } else if ( relative_uri->params ) {
704  tmp_uri.params = relative_uri->params;
705  }
706 
707  /* Create demangled URI */
708  new_uri = uri_dup ( &tmp_uri );
709  free ( tmp_path );
710  return new_uri;
711 }
712 
713 /**
714  * Construct TFTP URI from server address and filename
715  *
716  * @v sa_server Server address
717  * @v filename Filename
718  * @ret uri URI, or NULL on failure
719  */
720 static struct uri * tftp_uri ( struct sockaddr *sa_server,
721  const char *filename ) {
722  struct sockaddr_tcpip *st_server =
723  ( ( struct sockaddr_tcpip * ) sa_server );
724  char buf[ 6 /* "65535" + NUL */ ];
725  char *path;
726  struct uri tmp;
727  struct uri *uri = NULL;
728 
729  /* Initialise TFTP URI */
730  memset ( &tmp, 0, sizeof ( tmp ) );
731  tmp.scheme = "tftp";
732 
733  /* Construct TFTP server address */
734  tmp.host = sock_ntoa ( sa_server );
735  if ( ! tmp.host )
736  goto err_host;
737 
738  /* Construct TFTP server port, if applicable */
739  if ( st_server->st_port ) {
740  snprintf ( buf, sizeof ( buf ), "%d",
741  ntohs ( st_server->st_port ) );
742  tmp.port = buf;
743  }
744 
745  /* Construct TFTP path */
746  if ( asprintf ( &path, "/%s", filename ) < 0 )
747  goto err_path;
748  tmp.path = path;
749 
750  /* Demangle URI */
751  uri = uri_dup ( &tmp );
752  if ( ! uri )
753  goto err_uri;
754 
755  err_uri:
756  free ( path );
757  err_path:
758  err_host:
759  return uri;
760 }
761 
762 /**
763  * Construct URI from server address and filename
764  *
765  * @v sa_server Server address
766  * @v filename Filename
767  * @ret uri URI, or NULL on failure
768  *
769  * PXE TFTP filenames specified via the DHCP next-server field often
770  * contain characters such as ':' or '#' which would confuse the
771  * generic URI parser. We provide a mechanism for directly
772  * constructing a TFTP URI from the next-server and filename.
773  */
774 struct uri * pxe_uri ( struct sockaddr *sa_server, const char *filename ) {
775  struct uri *uri;
776 
777  /* Fail if filename is empty */
778  if ( ! ( filename && filename[0] ) )
779  return NULL;
780 
781  /* If filename is a hierarchical absolute URI, then use that
782  * URI. (We accept only hierarchical absolute URIs, since PXE
783  * filenames sometimes start with DOS drive letters such as
784  * "C:\", which get misinterpreted as opaque absolute URIs.)
785  */
786  uri = parse_uri ( filename );
787  if ( uri && uri_is_absolute ( uri ) && ( ! uri->opaque ) )
788  return uri;
789  uri_put ( uri );
790 
791  /* Otherwise, construct a TFTP URI directly */
792  return tftp_uri ( sa_server, filename );
793 }
Definition: uri.h:100
TCP/IP socket address.
Definition: tcpip.h:75
static void uri_put(struct uri *uri)
Decrement URI reference count.
Definition: uri.h:188
Definition: uri.h:96
unsigned long strtoul(const char *string, char **endp, int base)
Convert string to numeric value.
Definition: string.c:441
size_t uri_encode_string(unsigned int field, const char *string, char *buf, ssize_t len)
Encode URI field string.
Definition: uri.c:236
static struct uri * uri_get(struct uri *uri)
Increment URI reference count.
Definition: uri.h:177
static void uri_dump(const struct uri *uri)
Dump URI for debugging.
Definition: uri.c:247
static int uri_is_absolute(const struct uri *uri)
URI is an absolute URI.
Definition: uri.h:118
char * strrchr(const char *src, int character)
Find rightmost character within a string.
Definition: string.c:259
char * dirname(char *path)
Return directory name from path.
Definition: basename.c:57
#define ref_init(refcnt, free)
Initialise a reference counter.
Definition: refcnt.h:64
struct uri * pxe_uri(struct sockaddr *sa_server, const char *filename)
Construct URI from server address and filename.
Definition: uri.c:774
A form parameter list.
Definition: params.h:16
printf() and friends
#define DBGC(...)
Definition: compiler.h:505
uint32_t string
Definition: multiboot.h:14
char prefix[4]
Definition: vmconsole.c:53
#define ntohs(value)
Definition: byteswap.h:136
static __always_inline void off_t int c
Definition: efi_uaccess.h:87
Definition: uri.h:101
Character types.
Uniform Resource Identifiers.
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:170
static size_t uri_copy_fields(const struct uri *src, struct uri *dest)
Copy URI fields.
Definition: uri.c:540
static int isprint(int character)
Check if character is printable.
Definition: ctype.h:86
A reference counter.
Definition: refcnt.h:26
const char * port
Port number.
Definition: uri.h:64
int ssnprintf(char *buf, ssize_t ssize, const char *fmt,...)
Version of vsnprintf() that accepts a signed buffer size.
Definition: vsprintf.c:420
char * strstr(const char *haystack, const char *needle)
Find substring.
Definition: string.c:279
const char * scheme
Scheme.
Definition: uri.h:54
void * memcpy(void *dest, const void *src, size_t len) __nonnull
Definition: uri.h:102
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:201
Form parameters.
#define container_of(ptr, type, field)
Get containing structure.
Definition: stddef.h:35
const char * path
Path.
Definition: uri.h:66
__be32 out[4]
Definition: CIB_PRM.h:36
Transport-network layer interface.
size_t format_uri(const struct uri *uri, char *buf, size_t len)
Format URI.
Definition: uri.c:457
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
char * format_uri_alloc(const struct uri *uri)
Format URI.
Definition: uri.c:522
static void * dest
Definition: strings.h:176
char * resolve_path(const char *base_path, const char *relative_path)
Resolve base+relative path.
Definition: uri.c:614
struct parameters * params
Form parameters.
Definition: uri.h:72
Definition: uri.h:97
static __always_inline void off_t userptr_t src
Definition: efi_uaccess.h:66
static size_t raw_len
Definition: base16.h:50
uint16_t st_port
TCP/IP port.
Definition: tcpip.h:81
Generalized socket address structure.
Definition: socket.h:96
static void(* free)(struct refcnt *refcnt))
Definition: refcnt.h:54
static int uri_character_escaped(char c, unsigned int field)
Check if character should be escaped within a URI field.
Definition: uri.c:108
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:241
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:576
uint8_t * tmp
Definition: entropy.h:156
size_t uri_decode(const char *encoded, void *buf, size_t len)
Decode URI field.
Definition: uri.c:53
char * strdup(const char *src)
Duplicate string.
Definition: string.c:350
size_t strlen(const char *src)
Get length of string.
Definition: string.c:213
unsigned char uint8_t
Definition: stdint.h:10
Definition: uri.h:98
const char * name
Name.
Definition: params.h:22
static struct uri * tftp_uri(struct sockaddr *sa_server, const char *filename)
Construct TFTP URI from server address and filename.
Definition: uri.c:720
void * malloc(size_t size)
Allocate memory.
Definition: malloc.c:583
const char * host
Host name.
Definition: uri.h:62
void * memmove(void *dest, const void *src, size_t len) __nonnull
Definition: uri.h:103
static void uri_decode_inplace(struct uri *uri, unsigned int field)
Decode URI field in-place.
Definition: uri.c:85
const char * sock_ntoa(struct sockaddr *sa)
Transcribe socket address.
Definition: socket.c:42
const char * query
Query.
Definition: uri.h:68
uint32_t len
Length.
Definition: ena.h:14
#define uri_field(uri, field)
Access URI field.
Definition: uri.h:82
const char * opaque
Opaque part.
Definition: uri.h:56
const char * fragment
Fragment.
Definition: uri.h:70
struct refcnt refcnt
Reference count.
Definition: uri.h:52
uint16_t count
Number of entries.
Definition: ena.h:22
static void uri_free(struct refcnt *refcnt)
Free URI.
Definition: uri.c:278
unsigned int uri_port(const struct uri *uri, unsigned int default_port)
Get port from URI.
Definition: uri.c:441
const char * password
Password.
Definition: uri.h:60
__be32 raw[7]
Definition: CIB_PRM.h:28
const char * user
User name.
Definition: uri.h:58
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:50
signed long ssize_t
Definition: stdint.h:7
struct uri * resolve_uri(const struct uri *base_uri, struct uri *relative_uri)
Resolve base+relative URI.
Definition: uri.c:676
#define NULL
NULL pointer (VOID *)
Definition: Base.h:362
String functions.
struct bofm_section_header done
Definition: bofm_test.c:46
struct uri * parse_uri(const char *uri_string)
Parse URI.
Definition: uri.c:295
void * memset(void *dest, int character, size_t len) __nonnull