xref: /inferno-os/appl/lib/url.b (revision 9b29ac7ea714507a9c0690620c02c8ca5ab25f90)
137da2899SCharles.Forsythimplement Url;
237da2899SCharles.Forsyth
337da2899SCharles.Forsythinclude "sys.m";
437da2899SCharles.Forsyth	sys: Sys;
537da2899SCharles.Forsyth
637da2899SCharles.Forsythinclude "string.m";
737da2899SCharles.Forsyth	S: String;
837da2899SCharles.Forsyth
937da2899SCharles.Forsythinclude "url.m";
1037da2899SCharles.Forsyth
1137da2899SCharles.Forsythschemes = array[] of {
1237da2899SCharles.Forsyth	NOSCHEME => "",
1337da2899SCharles.Forsyth	HTTP => "http",
1437da2899SCharles.Forsyth	HTTPS => "https",
1537da2899SCharles.Forsyth	FTP => "ftp",
1637da2899SCharles.Forsyth	FILE => "file",
1737da2899SCharles.Forsyth	GOPHER => "gopher",
1837da2899SCharles.Forsyth	MAILTO => "mailto",
1937da2899SCharles.Forsyth	NEWS => "news",
2037da2899SCharles.Forsyth	NNTP => "nntp",
2137da2899SCharles.Forsyth	TELNET => "telnet",
2237da2899SCharles.Forsyth	WAIS => "wais",
2337da2899SCharles.Forsyth	PROSPERO => "prospero",
2437da2899SCharles.Forsyth	JAVASCRIPT => "javascript",
2537da2899SCharles.Forsyth	UNKNOWN => "unknown"
2637da2899SCharles.Forsyth};
2737da2899SCharles.Forsyth
2837da2899SCharles.Forsythinit()
2937da2899SCharles.Forsyth{
3037da2899SCharles.Forsyth	sys = load Sys Sys->PATH;
3137da2899SCharles.Forsyth	S = load String String->PATH;
3237da2899SCharles.Forsyth}
3337da2899SCharles.Forsyth
3437da2899SCharles.Forsyth# To allow relative urls, only fill in specified pieces (don't apply defaults)
3537da2899SCharles.Forsyth#  general syntax: <scheme>:<scheme-specific>
3637da2899SCharles.Forsyth#  for IP schemes, <scheme-specific> is
3737da2899SCharles.Forsyth#      //<user>:<passwd>@<host>:<port>/<path>?<query>#<fragment>
3837da2899SCharles.Forsythmakeurl(surl: string): ref ParsedUrl
3937da2899SCharles.Forsyth{
4037da2899SCharles.Forsyth	scheme := NOSCHEME;
4137da2899SCharles.Forsyth	user := "";
4237da2899SCharles.Forsyth	passwd := "";
4337da2899SCharles.Forsyth	host := "";
4437da2899SCharles.Forsyth	port := "";
4537da2899SCharles.Forsyth	pstart := "";
4637da2899SCharles.Forsyth	path := "";
4737da2899SCharles.Forsyth	query := "";
4837da2899SCharles.Forsyth	frag := "";
4937da2899SCharles.Forsyth
5037da2899SCharles.Forsyth	(sch, url) := split(surl, ":");
5137da2899SCharles.Forsyth	if(url == "") {
5237da2899SCharles.Forsyth		url = sch;
5337da2899SCharles.Forsyth		sch = "";
5437da2899SCharles.Forsyth	}
5537da2899SCharles.Forsyth	else {
5637da2899SCharles.Forsyth		(nil, x) := S->splitl(sch, "^-a-zA-Z0-9.+");
5737da2899SCharles.Forsyth		if(x != nil) {
5837da2899SCharles.Forsyth			url = surl;
5937da2899SCharles.Forsyth			sch = "";
6037da2899SCharles.Forsyth		}
6137da2899SCharles.Forsyth		else {
6237da2899SCharles.Forsyth			scheme = UNKNOWN;
6337da2899SCharles.Forsyth			sch = S->tolower(sch);
6437da2899SCharles.Forsyth			for(i := 0; i < len schemes; i++)
6537da2899SCharles.Forsyth				if(schemes[i] == sch) {
6637da2899SCharles.Forsyth					scheme = i;
6737da2899SCharles.Forsyth					break;
6837da2899SCharles.Forsyth				}
6937da2899SCharles.Forsyth		}
7037da2899SCharles.Forsyth	}
7137da2899SCharles.Forsyth	if(scheme == MAILTO)
7237da2899SCharles.Forsyth		path = url;
7337da2899SCharles.Forsyth	else if (scheme == JAVASCRIPT)
7437da2899SCharles.Forsyth		path = url;
7537da2899SCharles.Forsyth	else {
7637da2899SCharles.Forsyth		if(S->prefix("//", url)) {
7737da2899SCharles.Forsyth			netloc: string;
7837da2899SCharles.Forsyth			(netloc, path) = S->splitl(url[2:], "/");
7937da2899SCharles.Forsyth			if(path != "")
8037da2899SCharles.Forsyth				path = path[1:];
8137da2899SCharles.Forsyth			pstart = "/";
8237da2899SCharles.Forsyth			if(scheme == FILE)
8337da2899SCharles.Forsyth				host = netloc;
8437da2899SCharles.Forsyth			else {
8537da2899SCharles.Forsyth				(up,hp) := split(netloc, "@");
8637da2899SCharles.Forsyth				if(hp == "")
8737da2899SCharles.Forsyth					hp = up;
8837da2899SCharles.Forsyth				else
8937da2899SCharles.Forsyth					(user, passwd) = split(up, ":");
9037da2899SCharles.Forsyth				(host, port) = split(hp, ":");
9137da2899SCharles.Forsyth			}
9237da2899SCharles.Forsyth		}
9337da2899SCharles.Forsyth		else {
9437da2899SCharles.Forsyth			if(S->prefix("/", url)) {
9537da2899SCharles.Forsyth				pstart = "/";
9637da2899SCharles.Forsyth				path = url[1:];
9737da2899SCharles.Forsyth			}
9837da2899SCharles.Forsyth			else
9937da2899SCharles.Forsyth				path = url;
10037da2899SCharles.Forsyth		}
10137da2899SCharles.Forsyth		if(scheme == FILE) {
10237da2899SCharles.Forsyth			if(host == "")
10337da2899SCharles.Forsyth				host = "localhost";
10437da2899SCharles.Forsyth		}
10537da2899SCharles.Forsyth		else {
10637da2899SCharles.Forsyth			(path, frag) = split(path, "#");
10737da2899SCharles.Forsyth			(path, query) = split(path, "?");
10837da2899SCharles.Forsyth		}
10937da2899SCharles.Forsyth	}
11037da2899SCharles.Forsyth
11137da2899SCharles.Forsyth	return ref ParsedUrl(scheme, 1, user, passwd, host, port, pstart, path, query, frag);
11237da2899SCharles.Forsyth}
11337da2899SCharles.Forsyth
11437da2899SCharles.ForsythParsedUrl.tostring(u: self ref ParsedUrl) : string
11537da2899SCharles.Forsyth{
11637da2899SCharles.Forsyth	if (u == nil)
11737da2899SCharles.Forsyth		return nil;
11837da2899SCharles.Forsyth
11937da2899SCharles.Forsyth	ans := "";
12037da2899SCharles.Forsyth	if(u.scheme > 0 && u.scheme < len schemes)
12137da2899SCharles.Forsyth		ans = schemes[u.scheme] + ":";
12237da2899SCharles.Forsyth	if(u.host != "") {
12337da2899SCharles.Forsyth		ans = ans + "//";
12437da2899SCharles.Forsyth		if(u.user != "") {
12537da2899SCharles.Forsyth			ans = ans + u.user;
12637da2899SCharles.Forsyth			if(u.passwd != "")
12737da2899SCharles.Forsyth				ans = ans + ":" + u.passwd;
12837da2899SCharles.Forsyth			ans = ans + "@";
12937da2899SCharles.Forsyth		}
13037da2899SCharles.Forsyth		ans = ans + u.host;
13137da2899SCharles.Forsyth		if(u.port != "")
13237da2899SCharles.Forsyth			ans = ans + ":" + u.port;
13337da2899SCharles.Forsyth	}
13437da2899SCharles.Forsyth	ans = ans + u.pstart + u.path;
13537da2899SCharles.Forsyth	if(u.query != "")
13637da2899SCharles.Forsyth		ans = ans + "?" + u.query;
13737da2899SCharles.Forsyth	if(u.frag != "")
13837da2899SCharles.Forsyth		ans = ans + "#" + u.frag;
13937da2899SCharles.Forsyth	return ans;
14037da2899SCharles.Forsyth}
14137da2899SCharles.Forsyth
14237da2899SCharles.ForsythParsedUrl.makeabsolute(u: self ref ParsedUrl, b: ref ParsedUrl)
14337da2899SCharles.Forsyth{
14437da2899SCharles.Forsyth#	The following is correct according to RFC 1808, but is violated
14537da2899SCharles.Forsyth#	by various extant web pages.
14637da2899SCharles.Forsyth
14737da2899SCharles.Forsyth	if(u.scheme != NOSCHEME && u.scheme != HTTP)
14837da2899SCharles.Forsyth		return;
14937da2899SCharles.Forsyth
15037da2899SCharles.Forsyth	if(u.host == "" && u.path == "" && u.pstart == "" && u.query == "" && u.frag == "") {
15137da2899SCharles.Forsyth		u.scheme = b.scheme;
15237da2899SCharles.Forsyth		u.user = b.user;
15337da2899SCharles.Forsyth		u.passwd = b.passwd;
15437da2899SCharles.Forsyth		u.host = b.host;
15537da2899SCharles.Forsyth		u.port = b.port;
15637da2899SCharles.Forsyth		u.path = b.path;
15737da2899SCharles.Forsyth		u.pstart = b.pstart;
15837da2899SCharles.Forsyth		u.query = b.query;
15937da2899SCharles.Forsyth		u.frag = b.frag;
16037da2899SCharles.Forsyth		return;
16137da2899SCharles.Forsyth	}
16237da2899SCharles.Forsyth	if(u.scheme == NOSCHEME)
16337da2899SCharles.Forsyth		u.scheme = b.scheme;
16437da2899SCharles.Forsyth	if(u.host != "")
16537da2899SCharles.Forsyth		return;
16637da2899SCharles.Forsyth	u.user = b.user;
16737da2899SCharles.Forsyth	u.passwd = b.passwd;
16837da2899SCharles.Forsyth	u.host = b.host;
16937da2899SCharles.Forsyth	u.port = b.port;
17037da2899SCharles.Forsyth	if(u.pstart == "/")
17137da2899SCharles.Forsyth		return;
17237da2899SCharles.Forsyth	u.pstart = "/";
17337da2899SCharles.Forsyth	if(u.path == "") {
17437da2899SCharles.Forsyth		u.path = b.path;
17537da2899SCharles.Forsyth		if(u.query == "")
17637da2899SCharles.Forsyth			u.query = b.query;
17737da2899SCharles.Forsyth	}
17837da2899SCharles.Forsyth	else {
17937da2899SCharles.Forsyth		(p1,nil) := S->splitr(b.path, "/");
18037da2899SCharles.Forsyth		u.path = canonize(p1 + u.path);
18137da2899SCharles.Forsyth	}
18237da2899SCharles.Forsyth}
18337da2899SCharles.Forsyth
18437da2899SCharles.Forsyth# Like splitl, but assume one char match, and omit that from second part.
18537da2899SCharles.Forsyth# If c doesn't appear in s, the return is (s, "").
18637da2899SCharles.Forsythsplit(s, c: string) : (string, string)
18737da2899SCharles.Forsyth{
18837da2899SCharles.Forsyth	(a,b) := S->splitl(s, c);
18937da2899SCharles.Forsyth	if(b != "")
19037da2899SCharles.Forsyth		b = b[1:];
19137da2899SCharles.Forsyth	return (a,b);
19237da2899SCharles.Forsyth}
19337da2899SCharles.Forsyth
19437da2899SCharles.Forsyth# remove ./ and ../ from s
19537da2899SCharles.Forsythcanonize(s: string): string
19637da2899SCharles.Forsyth{
19737da2899SCharles.Forsyth	(base, file) := S->splitr(s, "/");
198*9b29ac7eSCharles.Forsyth	(nil, path) := sys->tokenize(base, "/");
19937da2899SCharles.Forsyth	revpath : list of string = nil;
20037da2899SCharles.Forsyth	for(p := path; p != nil; p = tl p) {
20137da2899SCharles.Forsyth		if(hd p == "..") {
20237da2899SCharles.Forsyth			if(revpath != nil)
20337da2899SCharles.Forsyth				revpath = tl revpath;
20437da2899SCharles.Forsyth		}
20537da2899SCharles.Forsyth		else if(hd p != ".")
20637da2899SCharles.Forsyth			revpath = (hd p) :: revpath;
20737da2899SCharles.Forsyth	}
20837da2899SCharles.Forsyth	while(revpath != nil && hd revpath == "..")
20937da2899SCharles.Forsyth		revpath = tl revpath;
21037da2899SCharles.Forsyth	ans := "";
21137da2899SCharles.Forsyth	if(revpath != nil) {
21237da2899SCharles.Forsyth		ans = hd revpath;
21337da2899SCharles.Forsyth		revpath = tl revpath;
21437da2899SCharles.Forsyth		while(revpath != nil) {
21537da2899SCharles.Forsyth			ans = (hd revpath) + "/" + ans;
21637da2899SCharles.Forsyth			revpath = tl revpath;
21737da2899SCharles.Forsyth		}
21837da2899SCharles.Forsyth	}
21937da2899SCharles.Forsyth	if (ans != nil)
22037da2899SCharles.Forsyth		ans += "/";
22137da2899SCharles.Forsyth	ans += file;
22237da2899SCharles.Forsyth	return ans;
22337da2899SCharles.Forsyth}
22437da2899SCharles.Forsyth
225