5 class headdict(object):
9 def __getitem__(self, key):
10 return self.dict[key.lower()][1]
12 def __setitem__(self, key, val):
13 self.dict[key.lower()] = [key, val]
15 def __contains__(self, key):
16 return key.lower() in self.dict
18 def __delitem__(self, key):
19 del self.dict[key.lower()]
22 return iter((list[0] for list in self.dict.values()))
24 def get(self, key, default=""):
25 if key.lower() in self.dict:
26 return self.dict[key.lower()][1]
29 def getlist(self, key):
30 return self.dict.setdefault(key.lower(), [key])[1:]
32 def add(self, key, val):
33 self.dict.setdefault(key.lower(), [key]).append(val)
36 return repr(self.dict)
47 str = str[:i] + str[i].upper() + str[i + 1:]
54 class shortinput(IOError, EOFError):
56 super().__init__("Unexpected EOF")
58 class limitreader(object):
59 def __init__(self, back, limit):
63 self.buf = bytearray()
68 def read(self, size=-1):
69 ra = self.limit - self.rb
72 while len(self.buf) < ra:
73 ret = self.bk.read(ra - len(self.buf))
78 ret = bytes(self.buf[:ra])
79 self.buf = self.buf[ra:]
82 def readline(self, size=-1):
85 p = self.buf.find(b'\n', off)
87 ret = bytes(self.buf[:p + 1])
88 self.buf = self.buf[p + 1:]
91 if size >= 0 and len(self.buf) >= size:
92 ret = bytes(self.buf[:size])
93 self.buf = self.buf[size:]
95 if self.rb == self.limit:
97 self.buf = bytearray()
99 ra = self.limit - self.rb
103 ret = self.bk.read(ra)
109 def readlines(self, hint=None):
113 class lineiter(object):
119 raise StopIteration()
123 class request(object):
125 return copyrequest(self)
129 new.uriname = self.uriname + self.pathinfo[:n]
130 new.pathinfo = self.pathinfo[n:]
133 class origrequest(request):
134 def __init__(self, env):
136 self.method = env["REQUEST_METHOD"].upper()
137 self.uriname = env["SCRIPT_NAME"]
138 self.filename = env.get("SCRIPT_FILENAME")
139 self.uri = env["REQUEST_URI"]
140 self.pathinfo = env["PATH_INFO"]
141 self.query = env["QUERY_STRING"]
142 self.remoteaddr = env["REMOTE_ADDR"]
143 self.serverport = env["SERVER_PORT"]
144 self.servername = env["SERVER_NAME"]
145 self.https = "HTTPS" in env
146 self.ihead = headdict()
147 if "CONTENT_TYPE" in env:
148 self.ihead["Content-Type"] = env["CONTENT_TYPE"]
149 if "CONTENT_LENGTH" in env:
150 clen = self.ihead["Content-Length"] = env["CONTENT_LENGTH"]
152 self.input = limitreader(env["wsgi.input"], int(clen))
155 self.input = io.BytesIO(b"")
157 # Assume input is chunked and read until ordinary EOF.
158 self.input = env["wsgi.input"]
161 self.ohead = headdict()
162 for k, v in env.items():
164 self.ihead.add(fixcase(k[5:].replace("_", "-")), v)
166 self.statuscode = (200, "OK")
167 self.ohead["Content-Type"] = "text/html"
168 self.resources = set()
172 def status(self, code, msg):
173 self.statuscode = code, msg
177 return self.items[id]
178 self.items[id] = new = id(self)
179 if hasattr(new, "__enter__") and hasattr(new, "__exit__"):
183 def withres(self, res):
184 if res not in self.resources:
188 self.resources.add(res)
189 self.clean.add(res.__exit__)
193 res.__exit__(None, None, None)
194 self.resources.discard(res)
203 clean1(list(self.clean))
205 def oncommit(self, fn):
206 if fn not in self.commitfuns:
207 self.commitfuns.append(fn)
209 def commit(self, startreq):
210 for fun in reversed(self.commitfuns):
213 for nm in self.ohead:
214 for val in self.ohead.getlist(nm):
215 hdrs.append((nm, val))
216 startreq("%s %s" % self.statuscode, hdrs)
221 class copyrequest(request):
222 def __init__(self, p):
224 self.top = p.topreq()
226 self.method = p.method
227 self.uriname = p.uriname
228 self.filename = p.filename
230 self.pathinfo = p.pathinfo
232 self.remoteaddr = p.remoteaddr
233 self.serverport = p.serverport
239 def status(self, code, msg):
240 return self.parent.status(code, msg)
243 return self.top.item(id)
245 def withres(self, res):
246 return self.top.withres(res)
248 def oncommit(self, fn):
249 return self.top.oncommit(fn)
252 return self.parent.topreq()