瀏覽代碼

Add facility for resolving base+relative URIs (and paths).

tags/v0.9.3
Michael Brown 17 年之前
父節點
當前提交
a6f0a098da
共有 2 個檔案被更改,包括 227 行新增20 行删除
  1. 220
    19
      src/core/uri.c
  2. 7
    1
      src/include/gpxe/uri.h

+ 220
- 19
src/core/uri.c 查看文件

@@ -25,8 +25,36 @@
25 25
 #include <stdint.h>
26 26
 #include <stdlib.h>
27 27
 #include <string.h>
28
+#include <libgen.h>
29
+#include <gpxe/vsprintf.h>
28 30
 #include <gpxe/uri.h>
29 31
 
32
+/**
33
+ * Dump URI for debugging
34
+ *
35
+ * @v uri		URI
36
+ */
37
+static void dump_uri ( struct uri *uri ) {
38
+	if ( uri->scheme )
39
+		DBG ( " scheme \"%s\"", uri->scheme );
40
+	if ( uri->opaque )
41
+		DBG ( " opaque \"%s\"", uri->opaque );
42
+	if ( uri->user )
43
+		DBG ( " user \"%s\"", uri->user );
44
+	if ( uri->password )
45
+		DBG ( " password \"%s\"", uri->password );
46
+	if ( uri->host )
47
+		DBG ( " host \"%s\"", uri->host );
48
+	if ( uri->port )
49
+		DBG ( " port \"%s\"", uri->port );
50
+	if ( uri->path )
51
+		DBG ( " path \"%s\"", uri->path );
52
+	if ( uri->query )
53
+		DBG ( " query \"%s\"", uri->query );
54
+	if ( uri->fragment )
55
+		DBG ( " fragment \"%s\"", uri->fragment );
56
+}
57
+
30 58
 /**
31 59
  * Parse URI
32 60
  *
@@ -136,25 +164,8 @@ struct uri * parse_uri ( const char *uri_string ) {
136 164
 	}
137 165
 
138 166
  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 );
167
+	DBG ( "URI \"%s\" split into", uri_string );
168
+	dump_uri ( uri );
158 169
 	DBG ( "\n" );
159 170
 
160 171
 	return uri;
@@ -170,3 +181,193 @@ struct uri * parse_uri ( const char *uri_string ) {
170 181
 unsigned int uri_port ( struct uri *uri, unsigned int default_port ) {
171 182
 	return ( uri->port ? strtoul ( uri->port, NULL, 0 ) : default_port );
172 183
 }
184
+
185
+/**
186
+ * Unparse URI
187
+ *
188
+ * @v buf		Buffer to fill with URI string
189
+ * @v size		Size of buffer
190
+ * @v uri		URI to write into buffer
191
+ * @ret len		Length of URI string
192
+ */
193
+int unparse_uri ( char *buf, size_t size, struct uri *uri ) {
194
+	int used = 0;
195
+
196
+	DBG ( "URI unparsing" );
197
+	dump_uri ( uri );
198
+	DBG ( "\n" );
199
+
200
+	/* Special-case opaque URIs */
201
+	if ( uri->opaque ) {
202
+		return ssnprintf ( ( buf + used ), ( size - used ),
203
+				   "%s:%s", uri->scheme, uri->opaque );
204
+	}
205
+
206
+	/* scheme:// */
207
+	if ( uri->scheme ) {
208
+		used += ssnprintf ( ( buf + used ), ( size - used ),
209
+				    "%s://", uri->scheme );
210
+	}
211
+
212
+	/* [user[:password]@]host[:port] */
213
+	if ( uri->host ) {
214
+		if ( uri->user ) {
215
+			used += ssnprintf ( ( buf + used ), ( size - used ),
216
+					    "%s", uri->user );
217
+			if ( uri->password ) {
218
+				used += ssnprintf ( ( buf + used ),
219
+						    ( size - used ),
220
+						    ":%s", uri->password );
221
+			}
222
+			used += ssnprintf ( ( buf + used ), ( size - used ),
223
+					    "@" );
224
+		}
225
+		used += ssnprintf ( ( buf + used ), ( size - used ), "%s",
226
+				    uri->host );
227
+		if ( uri->port ) {
228
+			used += ssnprintf ( ( buf + used ), ( size - used ),
229
+					    ":%s", uri->port );
230
+		}
231
+	}
232
+
233
+	/* /path */
234
+	if ( uri->path ) {
235
+		used += ssnprintf ( ( buf + used ), ( size - used ),
236
+				    "%s", uri->path );
237
+	}
238
+
239
+	/* ?query */
240
+	if ( uri->query ) {
241
+		used += ssnprintf ( ( buf + used ), ( size - used ),
242
+				    "?%s", uri->query );
243
+	}
244
+
245
+	/* #fragment */
246
+	if ( uri->fragment ) {
247
+		used += ssnprintf ( ( buf + used ), ( size - used ),
248
+				    "#%s", uri->fragment );
249
+	}
250
+
251
+	return used;
252
+}
253
+
254
+/**
255
+ * Duplicate URI
256
+ *
257
+ * @v uri		URI
258
+ * @ret uri		Duplicate URI
259
+ *
260
+ * Creates a modifiable copy of a URI.
261
+ */
262
+struct uri * uri_dup ( struct uri *uri ) {
263
+	size_t len = ( unparse_uri ( NULL, 0, uri ) + 1 );
264
+	char buf[len];
265
+
266
+	unparse_uri ( buf, len, uri );
267
+	return parse_uri ( buf );
268
+}
269
+
270
+/**
271
+ * Resolve base+relative path
272
+ *
273
+ * @v base_uri		Base path
274
+ * @v relative_uri	Relative path
275
+ * @ret resolved_uri	Resolved path
276
+ *
277
+ * Takes a base path (e.g. "/var/lib/tftpboot/vmlinuz" and a relative
278
+ * path (e.g. "initrd.gz") and produces a new path
279
+ * (e.g. "/var/lib/tftpboot/initrd.gz").  Note that any non-directory
280
+ * portion of the base path will automatically be stripped; this
281
+ * matches the semantics used when resolving the path component of
282
+ * URIs.
283
+ */
284
+char * resolve_path ( const char *base_path,
285
+		      const char *relative_path ) {
286
+	size_t base_len = ( strlen ( base_path ) + 1 );
287
+	char base_path_copy[base_len];
288
+	char *base_tmp = base_path_copy;
289
+	char *resolved;
290
+
291
+	/* If relative path is absolute, just re-use it */
292
+	if ( relative_path[0] == '/' )
293
+		return strdup ( relative_path );
294
+
295
+	/* Create modifiable copy of path for dirname() */
296
+	memcpy ( base_tmp, base_path, base_len );
297
+	base_tmp = dirname ( base_tmp );
298
+
299
+	/* Process "./" and "../" elements */
300
+	while ( *relative_path == '.' ) {
301
+		relative_path++;
302
+		if ( *relative_path == 0 ) {
303
+			/* Do nothing */
304
+		} else if ( *relative_path == '/' ) {
305
+			relative_path++;
306
+		} else if ( *relative_path == '.' ) {
307
+			relative_path++;
308
+			if ( *relative_path == 0 ) {
309
+				base_tmp = dirname ( base_tmp );
310
+			} else if ( *relative_path == '/' ) {
311
+				base_tmp = dirname ( base_tmp );
312
+				relative_path++;
313
+			} else {
314
+				relative_path -= 2;
315
+				break;
316
+			}
317
+		} else {
318
+			relative_path--;
319
+			break;
320
+		}
321
+	}
322
+
323
+	/* Create and return new path */
324
+	if ( asprintf ( &resolved, "%s%s%s", base_tmp,
325
+			( ( base_tmp[ strlen ( base_tmp ) - 1 ] == '/' ) ?
326
+			  "" : "/" ), relative_path ) < 0 )
327
+		return NULL;
328
+
329
+	return resolved;
330
+}
331
+
332
+/**
333
+ * Resolve base+relative URI
334
+ *
335
+ * @v base_uri		Base URI
336
+ * @v relative_uri	Relative URI
337
+ * @ret resolved_uri	Resolved URI
338
+ *
339
+ * Takes a base URI (e.g. "http://etherboot.org/kernels/vmlinuz" and a
340
+ * relative URI (e.g. "../initrds/initrd.gz") and produces a new URI
341
+ * (e.g. "http://etherboot.org/initrds/initrd.gz").
342
+ */
343
+struct uri * resolve_uri ( struct uri *base_uri,
344
+			   struct uri *relative_uri ) {
345
+	struct uri tmp_uri;
346
+	char *tmp_path = NULL;
347
+	struct uri *new_uri;
348
+
349
+	/* If relative URI is absolute, just re-use it */
350
+	if ( uri_is_absolute ( relative_uri ) )
351
+		return uri_get ( relative_uri );
352
+
353
+	/* Mangle URI */
354
+	memcpy ( &tmp_uri, base_uri, sizeof ( tmp_uri ) );
355
+	if ( relative_uri->path ) {
356
+		tmp_path = resolve_path ( ( base_uri->path ?
357
+					    base_uri->path : "/" ),
358
+					  relative_uri->path );
359
+		tmp_uri.path = tmp_path;
360
+		tmp_uri.query = relative_uri->query;
361
+		tmp_uri.fragment = relative_uri->fragment;
362
+	} else if ( relative_uri->query ) {
363
+		tmp_uri.query = relative_uri->query;
364
+		tmp_uri.fragment = relative_uri->fragment;
365
+	} else if ( relative_uri->fragment ) {
366
+		tmp_uri.fragment = relative_uri->fragment;
367
+	}
368
+
369
+	/* Create demangled URI */
370
+	new_uri = uri_dup ( &tmp_uri );
371
+	free ( tmp_path );
372
+	return new_uri;
373
+}

+ 7
- 1
src/include/gpxe/uri.h 查看文件

@@ -125,6 +125,12 @@ uri_put ( struct uri *uri ) {
125 125
 }
126 126
 
127 127
 extern struct uri * parse_uri ( const char *uri_string );
128
-unsigned int uri_port ( struct uri *uri, unsigned int default_port );
128
+extern unsigned int uri_port ( struct uri *uri, unsigned int default_port );
129
+extern int unparse_uri ( char *buf, size_t size, struct uri *uri );
130
+extern struct uri * uri_dup ( struct uri *uri );
131
+extern char * resolve_path ( const char *base_path,
132
+			     const char *relative_path );
133
+extern struct uri * resolve_uri ( struct uri *base_uri,
134
+				  struct uri *relative_uri );
129 135
 
130 136
 #endif /* _GPXE_URI_H */

Loading…
取消
儲存