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 encoded Encoded field, or NULL
83  */
84 static void uri_decode_inplace ( char *encoded ) {
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 }
98 
99 /**
100  * Check if character should be escaped within a URI field
101  *
102  * @v c Character
103  * @v field URI field index
104  * @ret escaped Character should be escaped
105  */
106 static int uri_character_escaped ( char c, unsigned int field ) {
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 }
189 
190 /**
191  * Encode URI field
192  *
193  * @v field URI field index
194  * @v raw Raw data
195  * @v raw_len Length of raw data
196  * @v buf Buffer
197  * @v len Length of buffer
198  * @ret len Length of encoded string (excluding NUL)
199  */
200 size_t uri_encode ( unsigned int field, const void *raw, size_t raw_len,
201  char *buf, ssize_t len ) {
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 }
225 
226 /**
227  * Encode URI field string
228  *
229  * @v field URI field index
230  * @v string String
231  * @v buf Buffer
232  * @v len Length of buffer
233  * @ret len Length of encoded string (excluding NUL)
234  */
235 size_t uri_encode_string ( unsigned int field, const char *string,
236  char *buf, ssize_t len ) {
237 
238  return uri_encode ( field, string, strlen ( string ), buf, len );
239 }
240 
241 /**
242  * Dump URI for debugging
243  *
244  * @v uri URI
245  */
246 static void uri_dump ( const struct uri *uri ) {
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 }
273 
274 /**
275  * Free URI
276  *
277  * @v refcnt Reference count
278  */
279 static void uri_free ( struct refcnt *refcnt ) {
280  struct uri *uri = container_of ( refcnt, struct uri, refcnt );
281 
282  params_put ( uri->params );
283  free ( uri );
284 }
285 
286 /**
287  * Parse URI
288  *
289  * @v uri_string URI as a string
290  * @ret uri URI
291  *
292  * Splits a URI into its component parts. The return URI structure is
293  * dynamically allocated and must eventually be freed by calling
294  * uri_put().
295  */
296 struct uri * parse_uri ( const char *uri_string ) {
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 }
447 
448 /**
449  * Get port from URI
450  *
451  * @v uri URI, or NULL
452  * @v default_port Default port to use if none specified in URI
453  * @ret port Port
454  */
455 unsigned int uri_port ( const struct uri *uri, unsigned int default_port ) {
456 
457  if ( ( ! uri ) || ( ! uri->port ) )
458  return default_port;
459 
460  return ( strtoul ( uri->port, NULL, 0 ) );
461 }
462 
463 /**
464  * Format URI
465  *
466  * @v uri URI
467  * @v buf Buffer to fill with URI string
468  * @v size Size of buffer
469  * @ret len Length of URI string
470  */
471 size_t format_uri ( const struct uri *uri, char *buf, size_t len ) {
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 }
530 
531 /**
532  * Format URI
533  *
534  * @v uri URI
535  * @ret string URI string, or NULL on failure
536  *
537  * The caller is responsible for eventually freeing the allocated
538  * memory.
539  */
540 char * format_uri_alloc ( const struct uri *uri ) {
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 }
550 
551 /**
552  * Copy URI fields
553  *
554  * @v src Source URI
555  * @v dest Destination URI, or NULL to calculate length
556  * @ret len Length of raw URI
557  */
558 static size_t uri_copy_fields ( const struct uri *src, struct uri *dest ) {
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 }
585 
586 /**
587  * Duplicate URI
588  *
589  * @v uri URI
590  * @ret uri Duplicate URI
591  *
592  * Creates a modifiable copy of a URI.
593  */
594 struct uri * uri_dup ( const struct uri *uri ) {
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 }
617 
618 /**
619  * Resolve base+relative path
620  *
621  * @v base_uri Base path
622  * @v relative_uri Relative path
623  * @ret resolved_uri Resolved path, or NULL on failure
624  *
625  * Takes a base path (e.g. "/var/lib/tftpboot/vmlinuz" and a relative
626  * path (e.g. "initrd.gz") and produces a new path
627  * (e.g. "/var/lib/tftpboot/initrd.gz"). Note that any non-directory
628  * portion of the base path will automatically be stripped; this
629  * matches the semantics used when resolving the path component of
630  * URIs.
631  */
632 char * resolve_path ( const char *base_path,
633  const char *relative_path ) {
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 }
682 
683 /**
684  * Resolve base+relative URI
685  *
686  * @v base_uri Base URI, or NULL
687  * @v relative_uri Relative URI
688  * @ret resolved_uri Resolved URI, or NULL on failure
689  *
690  * Takes a base URI (e.g. "http://ipxe.org/kernels/vmlinuz" and a
691  * relative URI (e.g. "../initrds/initrd.gz") and produces a new URI
692  * (e.g. "http://ipxe.org/initrds/initrd.gz").
693  */
694 struct uri * resolve_uri ( const struct uri *base_uri,
695  struct uri *relative_uri ) {
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 }
745 
746 /**
747  * Construct TFTP URI from server address and filename
748  *
749  * @v sa_server Server address
750  * @v filename Filename
751  * @ret uri URI, or NULL on failure
752  */
753 static struct uri * tftp_uri ( struct sockaddr *sa_server,
754  const char *filename ) {
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 }
795 
796 /**
797  * Construct URI from server address and filename
798  *
799  * @v sa_server Server address
800  * @v filename Filename
801  * @ret uri URI, or NULL on failure
802  *
803  * PXE TFTP filenames specified via the DHCP next-server field often
804  * contain characters such as ':' or '#' which would confuse the
805  * generic URI parser. We provide a mechanism for directly
806  * constructing a TFTP URI from the next-server and filename.
807  */
808 struct uri * pxe_uri ( struct sockaddr *sa_server, const char *filename ) {
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 }
Definition: uri.h:116
const char * equery
Query (with original URI encoding)
Definition: uri.h:84
TCP/IP socket address.
Definition: tcpip.h:75
static const void * src
Definition: string.h:47
static __always_inline void off_t int c
Definition: librm.h:173
static void uri_put(struct uri *uri)
Decrement URI reference count.
Definition: uri.h:205
unsigned long strtoul(const char *string, char **endp, int base)
Convert string to numeric value.
Definition: string.c:484
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 struct uri * uri_get(struct uri *uri)
Increment URI reference count.
Definition: uri.h:194
static void uri_dump(const struct uri *uri)
Dump URI for debugging.
Definition: uri.c:246
static int uri_is_absolute(const struct uri *uri)
URI is an absolute URI.
Definition: uri.h:135
char * strrchr(const char *src, int character)
Find rightmost character within a string.
Definition: string.c:289
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:808
A request 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 int isalpha(int character)
Check if character is alphabetic.
Definition: ctype.h:75
Definition: uri.h:117
Character types.
Uniform Resource Identifiers.
struct parameters * find_parameters(const char *name)
Find request 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
static size_t uri_copy_fields(const struct uri *src, struct uri *dest)
Copy URI fields.
Definition: uri.c:558
static int isprint(int character)
Check if character is printable.
Definition: ctype.h:97
A reference counter.
Definition: refcnt.h:26
const char * port
Port number.
Definition: uri.h:78
int ssnprintf(char *buf, ssize_t ssize, const char *fmt,...)
Version of vsnprintf() that accepts a signed buffer size.
Definition: vsprintf.c:420
unsigned long tmp
Definition: linux_pci.h:63
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
Definition: uri.h:118
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
Request parameters.
#define container_of(ptr, type, field)
Get containing structure.
Definition: stddef.h:35
const char * path
Path (after URI decoding)
Definition: uri.h:80
__be32 out[4]
Definition: CIB_PRM.h:36
Transport-network layer interface.
uint16_t count
Number of entries.
Definition: ena.h:22
size_t format_uri(const struct uri *uri, char *buf, size_t len)
Format URI.
Definition: uri.c:471
char * strcpy(char *dest, const char *src)
Copy string.
Definition: string.c:346
FILE_LICENCE(GPL2_OR_LATER_OR_UBDL)
char * format_uri_alloc(const struct uri *uri)
Format URI.
Definition: uri.c:540
char * resolve_path(const char *base_path, const char *relative_path)
Resolve base+relative path.
Definition: uri.c:632
struct parameters * params
Request 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:53
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:106
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
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
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:393
size_t strlen(const char *src)
Get length of string.
Definition: string.c:243
unsigned char uint8_t
Definition: stdint.h:10
Definition: uri.h:114
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:753
void * malloc(size_t size)
Allocate memory.
Definition: malloc.c:583
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 * sock_ntoa(struct sockaddr *sa)
Transcribe socket address.
Definition: socket.c:42
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
unsigned int uri_port(const struct uri *uri, unsigned int default_port)
Get port from URI.
Definition: uri.c:455
if(len >=6 *4) __asm__ __volatile__("movsl" if(len >=5 *4) __asm__ __volatile__("movsl" if(len >=4 *4) __asm__ __volatile__("movsl" if(len >=3 *4) __asm__ __volatile__("movsl" if(len >=2 *4) __asm__ __volatile__("movsl" if(len >=1 *4) __asm__ __volatile__("movsl" if((len % 4) >=2) __asm__ __volatile__("movsw" if((len % 2) >=1) __asm__ __volatile__("movsb" return dest
Definition: string.h:150
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
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
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:694
uint32_t len
Length.
Definition: ena.h:14
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
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:296
void * memset(void *dest, int character, size_t len) __nonnull