8aa20a7f9c0ba348f99c4b0ab8fa4c3b2fc633e3 galt Fri Dec 13 13:12:33 2013 -0800 fixes #12337. better way to allow colons in urls by splitting htmlExpandUrl into two functions. the new one is called expandUrlOnBase and includes ftp support as well as http(s). diff --git src/lib/htmlPage.c src/lib/htmlPage.c index 74f9cf9..7f7be68 100644 --- src/lib/htmlPage.c +++ src/lib/htmlPage.c @@ -1086,58 +1086,39 @@ { code = '?'; } in = e; in++; *out++ = code; } } else *out++ = c; } *out++ = 0; } -char *htmlExpandUrl(char *base, char *url) -/* Expand URL that is relative to base to stand on its own. - * Return NULL if it's not http or https. */ +char *expandUrlOnBase(char *base, char *url) +/* Figure out first character past host name. Load up + * return string with protocol (if any) and host name. + * It is assumed that url is relative to base and does not contain a protocol.*/ { struct dyString *dy = NULL; char *hostName, *pastHostName; - -/* some mailto: have SGML char encoding, e.g a to hide from spambots */ -url = cloneString(url); /* Clone because asciiEntityDecode may modify it. */ -asciiEntityDecode(url, url, strlen(url)); - -/* In easiest case URL is actually absolute and begins with - * protocol. Just return clone of url. */ -if (startsWith("http:", url) || startsWith("https:", url)) - return url; - -/* If it's got a colon, but no http or https, then it's some - * protocol we don't understand, like a mailto. Just return NULL. */ -if (strchr(url, ':') != NULL) - { - freez(&url); - return NULL; - } - -/* Figure out first character past host name. Load up - * return string with protocol (if any) and host name. */ dy = dyStringNew(256); -if (startsWith("http:", base) || startsWith("https:", base)) +if (startsWith("http:", base) || startsWith("https:", base) || startsWith("ftp:", base)) hostName = (strchr(base, ':') + 3); else hostName = base; pastHostName = strchr(hostName, '/'); if (pastHostName == NULL) pastHostName = hostName + strlen(hostName); dyStringAppendN(dy, base, pastHostName - base); /* Add url to return string after host name. */ if (startsWith("/", url)) /* New URL is absolute, just append to hostName */ { dyStringAppend(dy, url); } else { @@ -1156,34 +1137,59 @@ if (path != NULL) { dyStringAppend(dy, path); } freez(&dir); freez(&path); } else { dyStringAppendN(dy, curDir, endDir-curDir); if (lastChar(dy->string) != '/') dyStringAppendC(dy, '/'); dyStringAppend(dy, url); } } -freez(&url); return dyStringCannibalize(&dy); } +char *htmlExpandUrl(char *base, char *url) +/* Expand URL that is relative to base to stand on its own. + * Return NULL if it's not http or https. */ +{ + +/* some mailto: have SGML char encoding, e.g a to hide from spambots */ +url = cloneString(url); /* Clone because asciiEntityDecode may modify it. */ +asciiEntityDecode(url, url, strlen(url)); + +/* In easiest case URL is actually absolute and begins with + * protocol. Just return clone of url. */ +if (startsWith("http:", url) || startsWith("https:", url)) + return url; + +/* If it's got a colon, but no http or https, then it's some + * protocol we don't understand, like a mailto. Just return NULL. */ +if (strchr(url, ':') != NULL) + { + freez(&url); + return NULL; + } +char *result = expandUrlOnBase(base, url); +freez(&url); +return result; +} + static void appendCgiVar(struct dyString *dy, char *name, char *value) /* Append cgiVar with cgi-encoded value to dy. */ { char *enc = NULL; if (value == NULL) value = ""; enc = cgiEncode(value); if (dy->stringSize != 0) dyStringAppendC(dy, '&'); dyStringAppend(dy, name); dyStringAppendC(dy, '='); dyStringAppend(dy, enc); freez(&enc); }