Commit | Line | Data |
---|---|---|
3ba5e96c FT |
1 | import time |
2 | ||
5ef9e488 | 3 | statusinfo = { |
001ec99e FT |
4 | 400: ("Bad Request", "Invalid HTTP request."), |
5 | 401: ("Unauthorized", "Authentication must be provided for the requested resource."), | |
6 | 403: ("Forbidden", "You are not authorized to request the requested resource."), | |
5ef9e488 | 7 | 404: ("Not Found", "The requested resource was not found."), |
001ec99e FT |
8 | 405: ("Method Not Allowed", "The request method is not recognized or permitted by the requested resource."), |
9 | 500: ("Server Error", "An internal error occurred."), | |
10 | 501: ("Not Implemented", "The requested functionality has not been implemented."), | |
11 | 503: ("Service Unavailable", "Service is being denied at this time."), | |
5ef9e488 FT |
12 | } |
13 | ||
14 | def httpdate(ts): | |
15 | return time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(ts)) | |
16 | ||
17 | def phttpdate(dstr): | |
18 | tz = dstr[-6:] | |
19 | dstr = dstr[:-6] | |
20 | if tz[0] != " " or (tz[1] != "+" and tz[1] != "-") or not tz[2:].isdigit(): | |
21 | return None | |
22 | tz = int(tz[1:]) | |
23 | tz = (((tz / 100) * 60) + (tz % 100)) * 60 | |
24 | return time.mktime(time.strptime(dstr, "%a, %d %b %Y %H:%M:%S")) - tz - time.altzone | |
25 | ||
eed3cf12 FT |
26 | def pmimehead(hstr): |
27 | def pws(p): | |
28 | while p < len(hstr) and hstr[p].isspace(): | |
29 | p += 1 | |
30 | return p | |
31 | def token(p, sep): | |
32 | buf = "" | |
33 | p = pws(p) | |
34 | if p >= len(hstr): | |
35 | return "", p | |
36 | if hstr[p] == '"': | |
37 | p += 1 | |
38 | while p < len(hstr): | |
39 | if hstr[p] == '\\': | |
40 | p += 1 | |
41 | if p < len(hstr): | |
42 | buf += hstr[p] | |
43 | p += 1 | |
44 | else: | |
45 | break | |
46 | elif hstr[p] == '"': | |
47 | p += 1 | |
48 | break | |
49 | else: | |
50 | buf += hstr[p] | |
51 | p += 1 | |
52 | return buf, pws(p) | |
53 | else: | |
54 | while p < len(hstr): | |
55 | if hstr[p] in sep: | |
56 | break | |
57 | buf += hstr[p] | |
58 | p += 1 | |
59 | return buf.strip(), pws(p) | |
60 | p = 0 | |
61 | val, p = token(p, ";") | |
62 | pars = {} | |
63 | while p < len(hstr): | |
64 | if hstr[p] != ';': | |
65 | break | |
66 | p += 1 | |
67 | k, p = token(p, "=") | |
68 | if k == "" or hstr[p:p + 1] != '=': | |
69 | break | |
70 | p += 1 | |
71 | v, p = token(p, ';') | |
ea18777a | 72 | pars[k.lower()] = v |
eed3cf12 FT |
73 | return val, pars |
74 | ||
5ef9e488 FT |
75 | def htmlq(html): |
76 | ret = "" | |
77 | for c in html: | |
78 | if c == "&": | |
79 | ret += "&" | |
80 | elif c == "<": | |
81 | ret += "<" | |
82 | elif c == ">": | |
83 | ret += ">" | |
84 | else: | |
85 | ret += c | |
86 | return ret | |
87 | ||
d740aa68 FT |
88 | def simpleerror(env, startreq, code, title, msg): |
89 | buf = """<?xml version="1.0" encoding="US-ASCII"?> | |
90 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> | |
91 | <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en-US"> | |
92 | <head> | |
93 | <title>%s</title> | |
94 | </head> | |
95 | <body> | |
96 | <h1>%s</h1> | |
97 | <p>%s</p> | |
98 | </body> | |
99 | </html> | |
100 | """ % (title, title, htmlq(msg)) | |
101 | startreq("%i %s" % (code, title), [("Content-Type", "text/html"), ("Content-Length", str(len(buf)))]) | |
102 | return [buf] | |
103 | ||
5ef9e488 | 104 | def urlq(url): |
cbb90a8d FT |
105 | if isinstance(url, unicode): |
106 | url = url.encode("utf-8") | |
5ef9e488 | 107 | ret = "" |
3985f4bb | 108 | invalid = "&=#?/\"'" |
5ef9e488 | 109 | for c in url: |
cbb90a8d | 110 | if c in invalid or (ord(c) <= 32) or (ord(c) >= 128): |
5ef9e488 FT |
111 | ret += "%%%02X" % ord(c) |
112 | else: | |
113 | ret += c | |
114 | return ret | |
115 | ||
bb80acbd FT |
116 | class urlerror(ValueError): |
117 | pass | |
118 | ||
119 | def parseurl(url): | |
120 | p = url.find("://") | |
121 | if p < 0: | |
122 | raise urlerror("Protocol not found in absolute URL `%s'" % url) | |
123 | proto = url[:p] | |
124 | l = url.find("/", p + 3) | |
125 | if l < 0: | |
126 | raise urlerror("Local part not found in absolute URL `%s'" % url) | |
127 | host = url[p + 3:l] | |
128 | local = url[l:] | |
129 | q = local.find("?") | |
130 | if q < 0: | |
131 | query = "" | |
132 | else: | |
133 | query = local[q + 1:] | |
134 | local = local[:q] | |
135 | return proto, host, local, query | |
136 | ||
e21c4382 | 137 | def consurl(proto, host, local, query=""): |
bb80acbd FT |
138 | if len(local) < 1 and local[0] != '/': |
139 | raise urlerror("Local part of URL must begin with a slash") | |
140 | ret = "%s://%s%s" % (proto, host, local) | |
141 | if len(query) > 0: | |
142 | ret += "?" + query | |
143 | return ret | |
144 | ||
145 | def appendurl(url, other): | |
146 | if "://" in other: | |
147 | return other | |
148 | proto, host, local, query = parseurl(url) | |
149 | if len(other) > 0 and other[0] == '/': | |
150 | return consurl(proto, host, other) | |
151 | else: | |
152 | p = local.rfind('/') | |
153 | return consurl(proto, host, local[:p + 1] + other) | |
154 | ||
31d48e69 | 155 | def siteurl(req): |
bb80acbd FT |
156 | host = req.ihead.get("Host", None) |
157 | if host is None: | |
158 | raise Exception("Could not reconstruct URL because no Host header was sent") | |
159 | proto = "http" | |
160 | if req.https: | |
161 | proto = "https" | |
31d48e69 FT |
162 | return "%s://%s/" % (proto, host) |
163 | ||
164 | def scripturl(req): | |
165 | s = siteurl(req) | |
166 | if req.uriname[0] != '/': | |
167 | raise Exception("Malformed local part when reconstructing URL") | |
168 | return siteurl(req) + req.uriname[1:] | |
169 | ||
170 | def requrl(req): | |
171 | s = siteurl(req) | |
bb80acbd FT |
172 | if req.uri[0] != '/': |
173 | raise Exception("Malformed local part when reconstructing URL") | |
31d48e69 | 174 | return siteurl(req) + req.uri[1:] |
bb80acbd | 175 | |
e21c4382 | 176 | def parstring(pars={}, **augment): |
5ef9e488 FT |
177 | buf = "" |
178 | for key in pars: | |
179 | if key in augment: | |
180 | val = augment[key] | |
181 | del augment[key] | |
182 | else: | |
183 | val = pars[key] | |
184 | if buf != "": buf += "&" | |
185 | buf += urlq(key) + "=" + urlq(str(val)) | |
186 | for key in augment: | |
187 | if buf != "": buf += "&" | |
188 | buf += urlq(key) + "=" + urlq(str(augment[key])) | |
189 | return buf | |
08a4b741 | 190 | |
e21c4382 | 191 | def parurl(url, pars={}, **augment): |
08a4b741 FT |
192 | qs = parstring(pars, **augment) |
193 | if qs != "": | |
194 | return url + "?" + qs | |
195 | else: | |
196 | return url |