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