aboutsummaryrefslogtreecommitdiffstats
path: root/url.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--url.c233
1 files changed, 144 insertions, 89 deletions
diff --git a/url.c b/url.c
index 9fe6f32..d0abe2f 100644
--- a/url.c
+++ b/url.c
@@ -571,6 +571,7 @@ parseURL(char *url, ParsedURL * p_url, ParsedURL * current)
p_url->is_nocache = 0;
p_url->file = NULL;
p_url->real_file = NULL;
+ p_url->query = NULL;
p_url->label = NULL;
if (*url == '#') { /* label only */
@@ -593,29 +594,33 @@ parseURL(char *url, ParsedURL * p_url, ParsedURL * current)
#endif /* SUPPORT_DOS_DRIVE_PREFIX */
/* search for scheme */
p_url->scheme = getURLScheme(&p);
- if (p_url->scheme == SCM_MISSING) { /* scheme not found */
+ if (p_url->scheme == SCM_MISSING) {
+ /* scheme part is not found in the url. This means either
+ (a) the url is relative to the current or (b) the url
+ denotes a filename (therefore the scheme is SCM_LOCAL).
+ */
if (current) {
- copyParsedURL(p_url, current);
- if (p_url->scheme == SCM_LOCAL_CGI)
- p_url->scheme = SCM_LOCAL;
+ copyParsedURL(p_url, current);
+ if (p_url->scheme == SCM_LOCAL_CGI)
+ p_url->scheme = SCM_LOCAL;
+ /* label part and query part don't inherit */
+ p_url->label = NULL;
+ p_url->query = NULL;
} else
- p_url->scheme = SCM_LOCAL;
- p = url;
+ p_url->scheme = SCM_LOCAL;
+ p = url;
if (!strncmp(p,"//",2)) {
/* URL begins with // */
/* it means that 'scheme:' is abbreviated */
-#ifdef __CYGWIN__
- /* in CYGWIN, '//host/share' doesn't means 'http://host/share' */
- p_url->scheme = SCM_LOCAL;
- goto analyze_file;
-#endif /* __CYGWIN__ */
p += 2;
goto analyze_url;
}
- goto analyze_file;
+ /* the url doesn't begin with '//' */
+ goto analyze_file;
}
+ /* scheme part has been found */
/* get host and port */
- if (p[0] != '/' || p[1] != '/') { /* scheme:foo or * scheme:/foo */
+ if (p[0] != '/' || p[1] != '/') { /* scheme:foo or scheme:/foo */
p_url->host = NULL;
if (p_url->scheme != SCM_UNKNOWN)
p_url->port = DefaultPort[p_url->scheme];
@@ -623,27 +628,29 @@ parseURL(char *url, ParsedURL * p_url, ParsedURL * current)
p_url->port = 0;
goto analyze_file;
}
+ /* after here, p begins with // */
if (p_url->scheme == SCM_LOCAL) { /* file://foo */
#ifdef __EMX__
p += 2;
goto analyze_file;
#else
- if (p[2] == '/' || p[2] == '~') { /* file:///foo */
- p += 2; /* file://~user */
+ if (p[2] == '/' || p[2] == '~'
+ /* <A HREF="file:///foo">file:///foo</A> or <A HREF="file://~user">file://~user</A> */
+#ifdef SUPPORT_DOS_DRIVE_PREFIX
+ || (IS_ALPHA(p[2]) && (p[3] == ':' || p[3] == '|'))
+ /* <A HREF="file://DRIVE/foo">file://DRIVE/foo</A> */
+#endif /* SUPPORT_DOS_DRIVE_PREFIX */
+ ) {
+ p += 2;
goto analyze_file;
}
-#endif
-#if defined( __CYGWIN__ ) && defined( SUPPORT_DOS_DRIVE_PREFIX )
- if (IS_ALPHA(p[2]) && (p[3] == ':' || p[3] == '|'))
- p += 2;
- goto analyze_file; /* file://DRIVE/foo or
- file://machine/share/foo */
-#endif /* __CYGWIN__ && SUPPORT_DOS_DRIVE_PREFIX */
+#endif /* __EMX__ */
}
p += 2; /* scheme://foo */
+ /* ^p is here */
analyze_url:
q = p;
- while (*p && *p != ':' && *p != '/' && *p != '@' && *p != '?') {
+ while (*p && strchr(":/@?#",*p) == NULL) {
#ifdef INET6
if (*p == '[') { /* rfc2732 compliance */
char *p_colon = NULL;
@@ -665,46 +672,53 @@ parseURL(char *url, ParsedURL * p_url, ParsedURL * current)
p++;
}
switch (*p) {
- case '\0': /* scheme://host */
- /* scheme://user@host */
- /* scheme://user:pass@host */
+ case '\0':
+ /* scheme://host */
p_url->host = copyPath(q, -1, COPYPATH_SPC_IGNORE);
p_url->port = DefaultPort[p_url->scheme];
- goto analyze_file;
+ p_url->file = DefaultFile(p_url->scheme);
+ return;
case ':':
+ /* scheme://user:pass@host or
+ scheme://host:port
+ */
p_url->host = copyPath(q, p - q, COPYPATH_SPC_IGNORE);
q = ++p;
- while (*p && *p != '/' && *p != '@')
+ while (*p && strchr("@/?#",*p) == NULL)
p++;
- if (*p == '@') { /* scheme://user:pass@... */
+ if (*p == '@') {
+ /* scheme://user:pass@... */
p_url->pass = copyPath(q, p - q, COPYPATH_SPC_ALLOW);
q = ++p;
p_url->user = p_url->host;
p_url->host = NULL;
goto analyze_url;
}
+ /* scheme://host:port/ */
tmp = Strnew_charp_n(q, p - q);
p_url->port = atoi(tmp->ptr);
- if (*p == '\0') { /* scheme://host:port */
+ if (*p == '\0') {
/* scheme://user@host:port */
/* scheme://user:pass@host:port */
p_url->file = DefaultFile(p_url->scheme);
p_url->label = NULL;
return;
}
+ /* *p is one of ['/', '?', '#'] */
break;
- case '@': /* scheme://user@... */
+ case '@':
+ /* scheme://user@... */
p_url->user = copyPath(q, p - q, COPYPATH_SPC_IGNORE);
q = ++p;
goto analyze_url;
- case '/': /* scheme://host/... */
+ case '/':
case '?':
- /* scheme://user@host/... */
- /* scheme://user:pass@host/... */
+ case '#':
p_url->host = copyPath(q, p - q, COPYPATH_SPC_IGNORE);
p_url->port = DefaultPort[p_url->scheme];
break;
}
+ analyze_file:
#ifdef INET6
/* rfc2732 compliance */
if (p_url->host != NULL && p_url->host[0] == '[' &&
@@ -713,10 +727,18 @@ parseURL(char *url, ParsedURL * p_url, ParsedURL * current)
++(p_url->host);
}
#endif
- analyze_file:
-#ifndef __CYGWIN__
+#ifndef SUPPORT_NETBIOS_SHARE
if (p_url->scheme == SCM_LOCAL && p_url->user == NULL &&
p_url->host != NULL && strcmp(p_url->host, "localhost")) {
+ /*
+ In the environments other than CYGWIN, a URL like
+ file://host/file is regarded as ftp://host/file.
+ On the other hand, file://host/file on CYGWIN is
+ regarded as local access to the file //host/file.
+ `host' is a netbios-hostname, drive, or any other
+ name; It is CYGWIN system call who interprets that.
+ */
+
p_url->scheme = SCM_FTP; /* ftp://host/... */
if (p_url->port == 0)
p_url->port = DefaultPort[SCM_FTP];
@@ -729,11 +751,11 @@ parseURL(char *url, ParsedURL * p_url, ParsedURL * current)
q++;
if (IS_ALPHA(q[0]) && (q[1] == ':' || q[1] == '|')) {
if (q[1] == '|') {
- p = allocStr(q, 0);
- p[1] = ':';
+ p = allocStr(q, 0);
+ p[1] = ':';
}
else
- p = q;
+ p = q;
}
}
#endif
@@ -771,7 +793,7 @@ parseURL(char *url, ParsedURL * p_url, ParsedURL * current)
{
char *cgi = strchr(p, '?');
again:
- while (*p && *p != '#')
+ while (*p && *p != '#' && p != cgi)
p++;
if (*p == '#' && p_url->scheme == SCM_LOCAL) {
/*
@@ -803,7 +825,14 @@ parseURL(char *url, ParsedURL * p_url, ParsedURL * current)
else
p_url->file = copyPath(q, p - q, COPYPATH_SPC_IGNORE);
}
- do_label:
+ do_query:
+ if (*p == '?') {
+ q = ++p;
+ while (*p && *p != '#')
+ p++;
+ p_url->query = copyPath(q,p-q,COPYPATH_SPC_ALLOW);
+ }
+ do_label:
if (p_url->scheme == SCM_MISSING) {
p_url->scheme = SCM_LOCAL;
p_url->file = allocStr(p, 0);
@@ -816,6 +845,7 @@ parseURL(char *url, ParsedURL * p_url, ParsedURL * current)
}
#define initParsedURL(p) bzero(p,sizeof(ParsedURL))
+#define ALLOC_STR(s) ((s)==NULL?NULL:allocStr(s,0))
void
copyParsedURL(ParsedURL * p, ParsedURL * q)
@@ -823,30 +853,13 @@ copyParsedURL(ParsedURL * p, ParsedURL * q)
p->scheme = q->scheme;
p->port = q->port;
p->is_nocache = q->is_nocache;
- if (q->user)
- p->user = allocStr(q->user, 0);
- else
- p->user = NULL;
- if (q->pass)
- p->pass = allocStr(q->pass, 0);
- else
- p->pass = NULL;
- if (q->host)
- p->host = allocStr(q->host, 0);
- else
- p->host = NULL;
- if (q->file)
- p->file = allocStr(q->file, 0);
- else
- p->file = NULL;
- if (q->real_file)
- p->real_file = allocStr(q->real_file, 0);
- else
- p->real_file = NULL;
- if (q->label)
- p->label = allocStr(q->label, 0);
- else
- p->label = NULL;
+ p->user = ALLOC_STR(q->user);
+ p->pass = ALLOC_STR(q->pass);
+ p->host = ALLOC_STR(q->host);
+ p->file = ALLOC_STR(q->file);
+ p->real_file = ALLOC_STR(q->real_file);
+ p->label = ALLOC_STR(q->label);
+ p->query = ALLOC_STR(q->query);
}
void
@@ -854,6 +867,7 @@ parseURL2(char *url, ParsedURL * pu, ParsedURL * current)
{
char *p, *q;
Str tmp;
+ int relative_uri = FALSE;
parseURL(url, pu, current);
if (pu->scheme == SCM_MAILTO)
@@ -863,6 +877,7 @@ parseURL2(char *url, ParsedURL * pu, ParsedURL * current)
pu->file = expandName(pu->file);
if (current && pu->scheme == current->scheme) {
+ /* Copy omitted element from the current URL */
if (pu->user == NULL) {
pu->user = current->user;
}
@@ -885,18 +900,18 @@ parseURL2(char *url, ParsedURL * pu, ParsedURL * current)
&& !(pu->scheme == SCM_LOCAL && IS_ALPHA(pu->file[0]) && pu->file[1] == ':')
#endif
) {
+ /* file is relative [process 1]*/
p = pu->file;
if (current->file) {
tmp = Strnew_charp(current->file);
- if ((q = strchr(tmp->ptr, '?')) != NULL)
- Strshrink(tmp, (tmp->ptr + tmp->length) - q);
while (tmp->length > 0) {
if (Strlastchar(tmp) == '/')
break;
Strshrink(tmp, 1);
}
Strcat_charp(tmp, p);
- pu->file = allocStr(tmp->ptr, 0);
+ pu->file = tmp->ptr;
+ relative_uri = TRUE;
}
}
#ifdef USE_GOPHER
@@ -911,6 +926,8 @@ parseURL2(char *url, ParsedURL * pu, ParsedURL * current)
/* pu has only label */
pu->file = current->file;
}
+ /* comment: query part need not to be completed
+ from the current URL. */
}
if (pu->file) {
#ifdef __EMX__
@@ -932,10 +949,11 @@ parseURL2(char *url, ParsedURL * pu, ParsedURL * current)
}
#else
if (pu->scheme == SCM_LOCAL && pu->file[0] != '/' &&
-#if defined( __CYGWIN__ ) && defined( SUPPORT_DOS_DRIVE_PREFIX ) /* for 'drive:' */
+#ifdef SUPPORT_DOS_DRIVE_PREFIX /* for 'drive:' */
! (IS_ALPHA(pu->file[0]) && pu->file[1] == ':') &&
#endif
strcmp(pu->file, "-")) {
+ /* local file, relative path */
tmp = Strnew_charp(CurrentDir);
if (Strlastchar(tmp) != '/')
Strcat_char(tmp, '/');
@@ -943,15 +961,21 @@ parseURL2(char *url, ParsedURL * pu, ParsedURL * current)
pu->file = cleanupName(tmp->ptr);
}
#endif
- else if ((pu->scheme == SCM_HTTP
+ else if (pu->scheme == SCM_HTTP
#ifdef USE_SSL
|| pu->scheme == SCM_HTTPS
#endif
- ) && pu->file[0] == '/') {
- char *p = &pu->file[1];
- int s = getURLScheme(&p);
- if (s == SCM_MISSING || s == SCM_UNKNOWN)
- pu->file = cleanupName(pu->file);
+ ) {
+ if (relative_uri) {
+ /* In this case, pu->file is created by [process 1] above.
+ pu->file may contain relative path (for example,
+ "/foo/../bar/./baz.html"), cleanupName() must be applied.
+ When the entire abs_path is given, it still may contain
+ elements like `//', `..' or `.' in the pu->file. It is
+ server's responsibility to canonicalize such path.
+ */
+ pu->file = cleanupName(pu->file);
+ }
} else if (
#ifdef USE_GOPHER
pu->scheme != SCM_GOPHER &&
@@ -960,10 +984,27 @@ parseURL2(char *url, ParsedURL * pu, ParsedURL * current)
pu->scheme != SCM_NEWS &&
#endif /* USE_NNTP */
pu->file[0] == '/') {
+ /*
+ this happens on the following conditions:
+ (1) ftp scheme (2) local, looks like absolute path.
+ In both case, there must be no side effect with
+ cleanupName(). (I hope so...)
+ */
pu->file = cleanupName(pu->file);
}
- if (pu->scheme == SCM_LOCAL)
- pu->real_file = cleanupName2(file_unquote(pu->file), FALSE);
+ if (pu->scheme == SCM_LOCAL) {
+#ifdef SUPPORT_NETBIOS_SHARE
+ if (pu->host && strcmp(pu->host,"localhost") != 0) {
+ Str tmp = Strnew_charp("//");
+ Strcat_m_charp(tmp, pu->host,
+ cleanupName(file_unquote(pu->file)),
+ NULL);
+ pu->real_file = tmp->ptr;
+ }
+ else
+#endif
+ pu->real_file = cleanupName(file_unquote(pu->file));
+ }
}
}
@@ -1025,13 +1066,17 @@ _parsedURL2Str(ParsedURL * pu, int pass)
#ifdef USE_NNTP
pu->scheme != SCM_NEWS &&
#endif /* USE_NNTP */
+ (pu->file == NULL || (pu->file[0] != '/'
#ifdef SUPPORT_DOS_DRIVE_PREFIX
- (pu->file == NULL || (pu->file[0] != '/' && pu->file[1] != ':')))
-#else
- (pu->file == NULL || pu->file[0] != '/'))
+ && !(IS_ALPHA(pu->file[0]) && pu->file[1] == ':' && pu->host == NULL)
#endif
+ )))
Strcat_char(tmp, '/');
Strcat_charp(tmp, pu->file);
+ if (pu->query) {
+ Strcat_char(tmp,'?');
+ Strcat_charp(tmp,pu->query);
+ }
if (pu->label) {
Strcat_char(tmp, '#');
Strcat_charp(tmp, pu->label);
@@ -1149,6 +1194,10 @@ HTTPrequest(ParsedURL * pu, ParsedURL * current, HRequest * hr, TextList * extra
}
else if (hr->flag & HR_FLAG_LOCAL) {
Strcat_charp(tmp, pu->file);
+ if (pu->query) {
+ Strcat_char(tmp,'?');
+ Strcat_charp(tmp,pu->query);
+ }
}
else {
Strcat(tmp, _parsedURL2Str(pu, TRUE));
@@ -1261,7 +1310,7 @@ openURL(char *url, ParsedURL * pu, ParsedURL * current,
Str tmp2 = Strnew_charp("#");
Strcat_charp(tmp2, pu->label);
pu->file = tmp2->ptr;
- pu->real_file = cleanupName2(file_unquote(pu->file), FALSE);
+ pu->real_file = cleanupName(file_unquote(pu->file));
pu->label = NULL;
}
else {
@@ -1287,18 +1336,24 @@ openURL(char *url, ParsedURL * pu, ParsedURL * current,
case SCM_LOCAL_CGI:
if (request && request->body) {
/* local CGI: POST */
- uf.stream = newFileStream(localcgi_post(pu->real_file, request,
- option->referer), (void (*)()) pclose);
+ if ((q = strchr(pu->file, '?')) != NULL) {
+ p = Strnew_charp_n(pu->file, (int)(q - pu->file))->ptr;
+ pu->real_file = cleanupName(file_unquote(p));
+ q++;
+ }
+ uf.stream = newFileStream(localcgi_post(pu->real_file,
+ pu->query,
+ request,
+ option->referer),
+ (void (*)()) pclose);
if (uf.stream == NULL)
goto ordinary_local_file;
uf.is_cgi = TRUE;
uf.scheme = pu->scheme = SCM_LOCAL_CGI;
}
- else if ((q = strchr(pu->file, '?')) != NULL) {
+ else if (pu->query != NULL) {
/* lodal CGI: GET */
- p = Strnew_charp_n(pu->file, (int)(q - pu->file))->ptr;
- pu->real_file = cleanupName2(file_unquote(p), FALSE);
- uf.stream = newFileStream(localcgi_get(pu->real_file, q + 1,
+ uf.stream = newFileStream(localcgi_get(pu->real_file, pu->query,
option->referer), (void (*)()) pclose);
if (uf.stream == NULL) {
pu->file = p;
@@ -1338,7 +1393,7 @@ openURL(char *url, ParsedURL * pu, ParsedURL * current,
Strcat_char(tmp, '/');
Strcat_charp(tmp, pu->file);
p = cleanupName(tmp->ptr);
- q = cleanupName2(file_unquote(p), FALSE);
+ q = cleanupName(file_unquote(p));
if (dir_exist(q)) {
pu->file = p;
pu->real_file = q;
@@ -1622,7 +1677,7 @@ add_index_file(ParsedURL * pu, URLFile *uf)
}
p = Strnew_m_charp(pu->file, "/", file_quote(index_file), NULL)->ptr;
p = cleanupName(p);
- q = cleanupName2(file_unquote(p), FALSE);
+ q = cleanupName(file_unquote(p));
examineFile(q, uf);
if (uf->stream == NULL)
return;