cb1ac3bcb029e49ca46e74e88c9b446c7c8ed95e
[people/dverkamp/gpxe.git] / src / core / uri.c
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., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 /** @file
20  *
21  * Uniform Resource Identifiers
22  *
23  */
24
25 #include <stdint.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <gpxe/uri.h>
29
30 /**
31  * Parse URI
32  *
33  * @v uri_string        URI as a string
34  * @ret uri             URI
35  *
36  * Splits a URI into its component parts.  The return URI structure is
37  * dynamically allocated and must eventually be freed by calling
38  * free_uri().
39  */
40 struct uri * parse_uri ( const char *uri_string ) {
41         struct uri *uri;
42         char *raw;
43         char *tmp;
44         char *path = NULL;
45         char *authority = NULL;
46         size_t raw_len;
47
48         /* Allocate space for URI struct and a copy of the string */
49         raw_len = ( strlen ( uri_string ) + 1 /* NUL */ );
50         uri = malloc ( sizeof ( *uri ) + raw_len );
51         if ( ! uri )
52                 return NULL;
53         raw = ( ( ( char * ) uri ) + sizeof ( *uri ) );
54
55         /* Zero URI struct and copy in the raw string */
56         memset ( uri, 0, sizeof ( *uri ) );
57         memcpy ( raw, uri_string, raw_len );
58
59         /* Start by chopping off the fragment, if it exists */
60         if ( ( tmp = strchr ( raw, '#' ) ) ) {
61                 *(tmp++) = '\0';
62                 uri->fragment = tmp;
63         }
64
65         /* Identify absolute/relative URI */
66         if ( ( tmp = strchr ( raw, ':' ) ) ) {
67                 /* Absolute URI: identify hierarchical/opaque */
68                 uri->scheme = raw;
69                 *(tmp++) = '\0';
70                 if ( *tmp == '/' ) {
71                         /* Absolute URI with hierarchical part */
72                         path = tmp;
73                 } else {
74                         /* Absolute URI with opaque part */
75                         uri->opaque = tmp;
76                 }
77         } else {
78                 /* Relative URI */
79                 path = raw;
80         }
81
82         /* If we don't have a path (i.e. we have an absolute URI with
83          * an opaque portion, we're already finished processing
84          */
85         if ( ! path )
86                 goto done;
87
88         /* Chop off the query, if it exists */
89         if ( ( tmp = strchr ( path, '?' ) ) ) {
90                 *(tmp++) = '\0';
91                 uri->query = tmp;
92         }
93
94         /* Identify net/absolute/relative path */
95         if ( strncmp ( path, "//", 2 ) == 0 ) {
96                 /* Net path.  If this is terminated by the first '/'
97                  * of an absolute path, then we have no space for a
98                  * terminator after the authority field, so shuffle
99                  * the authority down by one byte, overwriting one of
100                  * the two slashes.
101                  */
102                 authority = ( path + 2 );
103                 if ( ( tmp = strchr ( authority, '/' ) ) ) {
104                         /* Shuffle down */
105                         uri->path = tmp;
106                         memmove ( ( authority - 1 ), authority,
107                                   ( tmp - authority ) );
108                         authority--;
109                         *(--tmp) = '\0';
110                 }
111         } else {
112                 /* Absolute/relative path */
113                 uri->path = path;
114         }
115
116         /* Split authority into user[:password] and host[:port] portions */
117         if ( ( tmp = strchr ( authority, '@' ) ) ) {
118                 /* Has user[:password] */
119                 *(tmp++) = '\0';
120                 uri->host = tmp;
121                 uri->user = authority;
122                 if ( ( tmp = strchr ( authority, ':' ) ) ) {
123                         /* Has password */
124                         *(tmp++) = '\0';
125                         uri->password = tmp;
126                 }
127         } else {
128                 /* No user:password */
129                 uri->host = authority;
130         }
131
132         /* Split host into host[:port] */
133         if ( ( tmp = strchr ( uri->host, ':' ) ) ) {
134                 *(tmp++) = '\0';
135                 uri->port = tmp;
136         }
137
138  done:
139         DBG ( "URI \"%s\" split into", raw );
140         if ( uri->scheme )
141                 DBG ( " scheme \"%s\"", uri->scheme );
142         if ( uri->opaque )
143                 DBG ( " opaque \"%s\"", uri->opaque );
144         if ( uri->user )
145                 DBG ( " user \"%s\"", uri->user );
146         if ( uri->password )
147                 DBG ( " password \"%s\"", uri->password );
148         if ( uri->host )
149                 DBG ( " host \"%s\"", uri->host );
150         if ( uri->port )
151                 DBG ( " port \"%s\"", uri->port );
152         if ( uri->path )
153                 DBG ( " path \"%s\"", uri->path );
154         if ( uri->query )
155                 DBG ( " query \"%s\"", uri->query );
156         if ( uri->fragment )
157                 DBG ( " fragment \"%s\"", uri->fragment );
158         DBG ( "\n" );
159
160         return uri;
161 }
162
163 /**
164  * Get port from URI
165  *
166  * @v uri               URI
167  * @v default_port      Default port to use if none specified in URI
168  * @ret port            Port
169  */
170 unsigned int uri_port ( struct uri *uri, unsigned int default_port ) {
171         return ( uri->port ? strtoul ( uri->port, NULL, 0 ) : default_port );
172 }