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