diff options
Diffstat (limited to 'net/libfetch/files/fetch.c')
-rw-r--r-- | net/libfetch/files/fetch.c | 90 |
1 files changed, 58 insertions, 32 deletions
diff --git a/net/libfetch/files/fetch.c b/net/libfetch/files/fetch.c index a9e0fddea8e..8f9a7b022ad 100644 --- a/net/libfetch/files/fetch.c +++ b/net/libfetch/files/fetch.c @@ -1,4 +1,4 @@ -/* $NetBSD: fetch.c,v 1.7 2008/04/24 07:55:00 joerg Exp $ */ +/* $NetBSD: fetch.c,v 1.8 2008/04/24 10:21:33 joerg Exp $ */ /*- * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav * All rights reserved. @@ -366,6 +366,7 @@ fetchParseURL(const char *URL) const char *p, *q; struct url *u; size_t i, count; + int pre_quoted; /* allocate struct url */ if ((u = calloc(1, sizeof(*u))) == NULL) { @@ -374,11 +375,13 @@ fetchParseURL(const char *URL) } if (*URL == '/') { + pre_quoted = 0; strcpy(u->scheme, SCHEME_FILE); p = URL; goto quote_doc; } if (strncmp(URL, "file:", 5) == 0) { + pre_quoted = 1; strcpy(u->scheme, SCHEME_FILE); URL += 5; if (URL[0] != '/' || URL[1] != '/' || URL[2] != '/') { @@ -390,6 +393,7 @@ fetchParseURL(const char *URL) } if (strncmp(URL, "http:", 5) == 0 || strncmp(URL, "https:", 6) == 0) { + pre_quoted = 1; if (URL[4] == ':') { strcpy(u->scheme, SCHEME_HTTP); URL += 5; @@ -407,6 +411,7 @@ fetchParseURL(const char *URL) goto find_hostname; } if (strncmp(URL, "ftp:", 4) == 0) { + pre_quoted = 1; strcpy(u->scheme, SCHEME_FTP); URL += 4; if (URL[0] != '/' || URL[1] != '/') { @@ -476,16 +481,21 @@ find_hostname: quote_doc: count = 1; - for (i = 0; p[i] != '\0'; ++i) - count += fetch_urlpath_safe(p[i]) ? 1 : 3; + for (i = 0; p[i] != '\0'; ++i) { + if ((!pre_quoted && p[i] == '%') || + !fetch_urlpath_safe(p[i])) + count += 3; + else + ++count; + } + if ((u->doc = malloc(count)) == NULL) { fetch_syserr(); goto ouch; } for (i = 0; *p != '\0'; ++p) { - if (fetch_urlpath_safe(*p)) - u->doc[i++] = *p; - else { + if ((!pre_quoted && *p == '%') || + !fetch_urlpath_safe(*p)) { u->doc[i++] = '%'; if ((unsigned char)*p < 160) u->doc[i++] = '0' + ((unsigned char)*p) / 16; @@ -495,7 +505,8 @@ quote_doc: u->doc[i++] = '0' + ((unsigned char)*p) % 16; else u->doc[i++] = 'a' - 10 + ((unsigned char)*p) % 16; - } + } else + u->doc[i++] = *p; } u->doc[i] = '\0'; @@ -529,37 +540,52 @@ xdigit2digit(char digit) } /* - * Extract the file name component of a URL. - */ + * Unquote whole URL. + * Skips optional parts like query or fragment identifier. + */ char * -fetch_extract_filename(struct url *url) +fetch_unquote_doc(struct url *url) { - char *name, *name_iter; - const char *last_slash, *iter; + char *unquoted; + const char *iter; + size_t i; + + if ((unquoted = malloc(strlen(url->doc) + 1)) == NULL) + return NULL; - last_slash = url->doc; - if (*last_slash == '\0') - return strdup(""); - for (iter = last_slash + 1; *iter; ++iter) { + for (i = 0, iter = url->doc; *iter != '\0'; ++iter) { if (*iter == '#' || *iter == '?') break; - if (*iter == '/') - last_slash = iter; - } - if (last_slash + 1 == iter) - return strdup(""); - name_iter = name = malloc(iter - last_slash); - while (++last_slash < iter) { - if (*last_slash != '%' || - !isxdigit((unsigned char)last_slash[1]) || - !isxdigit((unsigned char)last_slash[2])) { - *name_iter++ = *last_slash; + if (iter[0] != '%' || + !isxdigit((unsigned char)iter[1]) || + !isxdigit((unsigned char)iter[2])) { + unquoted[i++] = *iter; continue; } - *name_iter++ = xdigit2digit(last_slash[1]) * 16 + - xdigit2digit(last_slash[2]); - last_slash += 2; + unquoted[i++] = xdigit2digit(iter[1]) * 16 + + xdigit2digit(iter[2]); + iter += 2; } - *name_iter = '\0'; - return name; + unquoted[i] = '\0'; + return unquoted; +} + + +/* + * Extract the file name component of a URL. + */ +char * +fetch_extract_filename(struct url *url) +{ + char *unquoted, *filename; + const char *last_slash; + + if ((unquoted = fetch_unquote_doc(url)) == NULL) + return NULL; + + if ((last_slash = strrchr(unquoted, '/')) == NULL) + return unquoted; + filename = strdup(last_slash + 1); + free(unquoted); + return filename; } |