Commit | Line | Data |
---|---|---|
5ef9e488 | 1 | statusinfo = { |
001ec99e FT |
2 | 400: ("Bad Request", "Invalid HTTP request."), |
3 | 401: ("Unauthorized", "Authentication must be provided for the requested resource."), | |
4 | 403: ("Forbidden", "You are not authorized to request the requested resource."), | |
5ef9e488 | 5 | 404: ("Not Found", "The requested resource was not found."), |
001ec99e FT |
6 | 405: ("Method Not Allowed", "The request method is not recognized or permitted by the requested resource."), |
7 | 500: ("Server Error", "An internal error occurred."), | |
8 | 501: ("Not Implemented", "The requested functionality has not been implemented."), | |
9 | 503: ("Service Unavailable", "Service is being denied at this time."), | |
5ef9e488 FT |
10 | } |
11 | ||
12 | def httpdate(ts): | |
13 | return time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime(ts)) | |
14 | ||
15 | def phttpdate(dstr): | |
16 | tz = dstr[-6:] | |
17 | dstr = dstr[:-6] | |
18 | if tz[0] != " " or (tz[1] != "+" and tz[1] != "-") or not tz[2:].isdigit(): | |
19 | return None | |
20 | tz = int(tz[1:]) | |
21 | tz = (((tz / 100) * 60) + (tz % 100)) * 60 | |
22 | return time.mktime(time.strptime(dstr, "%a, %d %b %Y %H:%M:%S")) - tz - time.altzone | |
23 | ||
eed3cf12 FT |
24 | def pmimehead(hstr): |
25 | def pws(p): | |
26 | while p < len(hstr) and hstr[p].isspace(): | |
27 | p += 1 | |
28 | return p | |
29 | def token(p, sep): | |
30 | buf = "" | |
31 | p = pws(p) | |
32 | if p >= len(hstr): | |
33 | return "", p | |
34 | if hstr[p] == '"': | |
35 | p += 1 | |
36 | while p < len(hstr): | |
37 | if hstr[p] == '\\': | |
38 | p += 1 | |
39 | if p < len(hstr): | |
40 | buf += hstr[p] | |
41 | p += 1 | |
42 | else: | |
43 | break | |
44 | elif hstr[p] == '"': | |
45 | p += 1 | |
46 | break | |
47 | else: | |
48 | buf += hstr[p] | |
49 | p += 1 | |
50 | return buf, pws(p) | |
51 | else: | |
52 | while p < len(hstr): | |
53 | if hstr[p] in sep: | |
54 | break | |
55 | buf += hstr[p] | |
56 | p += 1 | |
57 | return buf.strip(), pws(p) | |
58 | p = 0 | |
59 | val, p = token(p, ";") | |
60 | pars = {} | |
61 | while p < len(hstr): | |
62 | if hstr[p] != ';': | |
63 | break | |
64 | p += 1 | |
65 | k, p = token(p, "=") | |
66 | if k == "" or hstr[p:p + 1] != '=': | |
67 | break | |
68 | p += 1 | |
69 | v, p = token(p, ';') | |
ea18777a | 70 | pars[k.lower()] = v |
eed3cf12 FT |
71 | return val, pars |
72 | ||
5ef9e488 FT |
73 | def htmlq(html): |
74 | ret = "" | |
75 | for c in html: | |
76 | if c == "&": | |
77 | ret += "&" | |
78 | elif c == "<": | |
79 | ret += "<" | |
80 | elif c == ">": | |
81 | ret += ">" | |
82 | else: | |
83 | ret += c | |
84 | return ret | |
85 | ||
86 | def urlq(url): | |
87 | ret = "" | |
88 | for c in url: | |
89 | if c == "&" or c == "=" or c == "#" or c == "?" or c == "/" or (ord(c) <= 32): | |
90 | ret += "%%%02X" % ord(c) | |
91 | else: | |
92 | ret += c | |
93 | return ret | |
94 | ||
bb80acbd FT |
95 | class urlerror(ValueError): |
96 | pass | |
97 | ||
98 | def parseurl(url): | |
99 | p = url.find("://") | |
100 | if p < 0: | |
101 | raise urlerror("Protocol not found in absolute URL `%s'" % url) | |
102 | proto = url[:p] | |
103 | l = url.find("/", p + 3) | |
104 | if l < 0: | |
105 | raise urlerror("Local part not found in absolute URL `%s'" % url) | |
106 | host = url[p + 3:l] | |
107 | local = url[l:] | |
108 | q = local.find("?") | |
109 | if q < 0: | |
110 | query = "" | |
111 | else: | |
112 | query = local[q + 1:] | |
113 | local = local[:q] | |
114 | return proto, host, local, query | |
115 | ||
116 | def consurl(proto, host, local, query = ""): | |
117 | if len(local) < 1 and local[0] != '/': | |
118 | raise urlerror("Local part of URL must begin with a slash") | |
119 | ret = "%s://%s%s" % (proto, host, local) | |
120 | if len(query) > 0: | |
121 | ret += "?" + query | |
122 | return ret | |
123 | ||
124 | def appendurl(url, other): | |
125 | if "://" in other: | |
126 | return other | |
127 | proto, host, local, query = parseurl(url) | |
128 | if len(other) > 0 and other[0] == '/': | |
129 | return consurl(proto, host, other) | |
130 | else: | |
131 | p = local.rfind('/') | |
132 | return consurl(proto, host, local[:p + 1] + other) | |
133 | ||
134 | def requrl(req): | |
135 | host = req.ihead.get("Host", None) | |
136 | if host is None: | |
137 | raise Exception("Could not reconstruct URL because no Host header was sent") | |
138 | proto = "http" | |
139 | if req.https: | |
140 | proto = "https" | |
141 | if req.uri[0] != '/': | |
142 | raise Exception("Malformed local part when reconstructing URL") | |
143 | return "%s://%s%s" % (proto, host, req.uri) | |
144 | ||
5ef9e488 FT |
145 | def parstring(pars = {}, **augment): |
146 | buf = "" | |
147 | for key in pars: | |
148 | if key in augment: | |
149 | val = augment[key] | |
150 | del augment[key] | |
151 | else: | |
152 | val = pars[key] | |
153 | if buf != "": buf += "&" | |
154 | buf += urlq(key) + "=" + urlq(str(val)) | |
155 | for key in augment: | |
156 | if buf != "": buf += "&" | |
157 | buf += urlq(key) + "=" + urlq(str(augment[key])) | |
158 | return buf |