pywsgi.py 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509
  1. # Copyright (c) 2005-2009, eventlet contributors
  2. # Copyright (c) 2009-2015, gevent contributors
  3. """
  4. A pure-Python, gevent-friendly WSGI server.
  5. The server is provided in :class:`WSGIServer`, but most of the actual
  6. WSGI work is handled by :class:`WSGIHandler` --- a new instance is
  7. created for each request. The server can be customized to use
  8. different subclasses of :class:`WSGIHandler`.
  9. """
  10. # FIXME: Can we refactor to make smallor?
  11. # pylint:disable=too-many-lines
  12. import errno
  13. from io import BytesIO
  14. import string
  15. import sys
  16. import time
  17. import traceback
  18. from datetime import datetime
  19. try:
  20. from urllib import unquote
  21. except ImportError:
  22. from urllib.parse import unquote # python 2 pylint:disable=import-error,no-name-in-module
  23. from gevent import socket
  24. import gevent
  25. from gevent.server import StreamServer
  26. from gevent.hub import GreenletExit
  27. from gevent._compat import PY3, reraise
  28. from functools import partial
  29. if PY3:
  30. unquote_latin1 = partial(unquote, encoding='latin-1')
  31. else:
  32. unquote_latin1 = unquote
  33. _no_undoc_members = True # Don't put undocumented things into sphinx
  34. __all__ = [
  35. 'WSGIServer',
  36. 'WSGIHandler',
  37. 'LoggingLogAdapter',
  38. 'Environ',
  39. 'SecureEnviron',
  40. 'WSGISecureEnviron',
  41. ]
  42. MAX_REQUEST_LINE = 8192
  43. # Weekday and month names for HTTP date/time formatting; always English!
  44. _WEEKDAYNAME = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"]
  45. _MONTHNAME = [None, # Dummy so we can use 1-based month numbers
  46. "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  47. "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
  48. # The contents of the "HEX" grammar rule for HTTP, upper and lowercase A-F plus digits,
  49. # in byte form for comparing to the network.
  50. _HEX = string.hexdigits.encode('ascii')
  51. # Errors
  52. _ERRORS = dict()
  53. _INTERNAL_ERROR_STATUS = '500 Internal Server Error'
  54. _INTERNAL_ERROR_BODY = b'Internal Server Error'
  55. _INTERNAL_ERROR_HEADERS = [('Content-Type', 'text/plain'),
  56. ('Connection', 'close'),
  57. ('Content-Length', str(len(_INTERNAL_ERROR_BODY)))]
  58. _ERRORS[500] = (_INTERNAL_ERROR_STATUS, _INTERNAL_ERROR_HEADERS, _INTERNAL_ERROR_BODY)
  59. _BAD_REQUEST_STATUS = '400 Bad Request'
  60. _BAD_REQUEST_BODY = ''
  61. _BAD_REQUEST_HEADERS = [('Content-Type', 'text/plain'),
  62. ('Connection', 'close'),
  63. ('Content-Length', str(len(_BAD_REQUEST_BODY)))]
  64. _ERRORS[400] = (_BAD_REQUEST_STATUS, _BAD_REQUEST_HEADERS, _BAD_REQUEST_BODY)
  65. _REQUEST_TOO_LONG_RESPONSE = b"HTTP/1.1 414 Request URI Too Long\r\nConnection: close\r\nContent-length: 0\r\n\r\n"
  66. _BAD_REQUEST_RESPONSE = b"HTTP/1.1 400 Bad Request\r\nConnection: close\r\nContent-length: 0\r\n\r\n"
  67. _CONTINUE_RESPONSE = b"HTTP/1.1 100 Continue\r\n\r\n"
  68. def format_date_time(timestamp):
  69. # Return a byte-string of the date and time in HTTP format
  70. # .. versionchanged:: 1.1b5
  71. # Return a byte string, not a native string
  72. year, month, day, hh, mm, ss, wd, _y, _z = time.gmtime(timestamp)
  73. value = "%s, %02d %3s %4d %02d:%02d:%02d GMT" % (_WEEKDAYNAME[wd], day, _MONTHNAME[month], year, hh, mm, ss)
  74. if PY3:
  75. value = value.encode("latin-1")
  76. return value
  77. class _InvalidClientInput(IOError):
  78. # Internal exception raised by Input indicating that the client
  79. # sent invalid data at the lowest level of the stream. The result
  80. # *should* be a HTTP 400 error.
  81. pass
  82. class _InvalidClientRequest(ValueError):
  83. # Internal exception raised by WSGIHandler.read_request
  84. # indicating that the client sent an HTTP request that cannot
  85. # be parsed (e.g., invalid grammar). The result *should* be an
  86. # HTTP 400 error
  87. pass
  88. class Input(object):
  89. __slots__ = ('rfile', 'content_length', 'socket', 'position',
  90. 'chunked_input', 'chunk_length', '_chunked_input_error')
  91. def __init__(self, rfile, content_length, socket=None, chunked_input=False):
  92. # pylint:disable=redefined-outer-name
  93. self.rfile = rfile
  94. self.content_length = content_length
  95. self.socket = socket
  96. self.position = 0
  97. self.chunked_input = chunked_input
  98. self.chunk_length = -1
  99. self._chunked_input_error = False
  100. def _discard(self):
  101. if self._chunked_input_error:
  102. # We are in an unknown state, so we can't necessarily discard
  103. # the body (e.g., if the client keeps the socket open, we could hang
  104. # here forever).
  105. # In this case, we've raised an exception and the user of this object
  106. # is going to close the socket, so we don't have to discard
  107. return
  108. if self.socket is None and (self.position < (self.content_length or 0) or self.chunked_input):
  109. # ## Read and discard body
  110. while 1:
  111. d = self.read(16384)
  112. if not d:
  113. break
  114. def _send_100_continue(self):
  115. if self.socket is not None:
  116. self.socket.sendall(_CONTINUE_RESPONSE)
  117. self.socket = None
  118. def _do_read(self, length=None, use_readline=False):
  119. if use_readline:
  120. reader = self.rfile.readline
  121. else:
  122. reader = self.rfile.read
  123. content_length = self.content_length
  124. if content_length is None:
  125. # Either Content-Length or "Transfer-Encoding: chunked" must be present in a request with a body
  126. # if it was chunked, then this function would have not been called
  127. return b''
  128. self._send_100_continue()
  129. left = content_length - self.position
  130. if length is None:
  131. length = left
  132. elif length > left:
  133. length = left
  134. if not length:
  135. return b''
  136. # On Python 2, self.rfile is usually socket.makefile(), which
  137. # uses cStringIO.StringIO. If *length* is greater than the C
  138. # sizeof(int) (typically 32 bits signed), parsing the argument to
  139. # readline raises OverflowError. StringIO.read(), OTOH, uses
  140. # PySize_t, typically a long (64 bits). In a bare readline()
  141. # case, because the header lines we're trying to read with
  142. # readline are typically expected to be small, we can correct
  143. # that failure by simply doing a smaller call to readline and
  144. # appending; failures in read we let propagate.
  145. try:
  146. read = reader(length)
  147. except OverflowError:
  148. if not use_readline:
  149. # Expecting to read more than 64 bits of data. Ouch!
  150. raise
  151. # We could loop on calls to smaller readline(), appending them
  152. # until we actually get a newline. For uses in this module,
  153. # we expect the actual length to be small, but WSGI applications
  154. # are allowed to pass in an arbitrary length. (This loop isn't optimal,
  155. # but even client applications *probably* have short lines.)
  156. read = b''
  157. while len(read) < length and not read.endswith(b'\n'):
  158. read += reader(MAX_REQUEST_LINE)
  159. self.position += len(read)
  160. if len(read) < length:
  161. if (use_readline and not read.endswith(b"\n")) or not use_readline:
  162. raise IOError("unexpected end of file while reading request at position %s" % (self.position,))
  163. return read
  164. def __read_chunk_length(self, rfile):
  165. # Read and return the next integer chunk length. If no
  166. # chunk length can be read, raises _InvalidClientInput.
  167. # Here's the production for a chunk:
  168. # (http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html)
  169. # chunk = chunk-size [ chunk-extension ] CRLF
  170. # chunk-data CRLF
  171. # chunk-size = 1*HEX
  172. # chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
  173. # chunk-ext-name = token
  174. # chunk-ext-val = token | quoted-string
  175. # To cope with malicious or broken clients that fail to send valid
  176. # chunk lines, the strategy is to read character by character until we either reach
  177. # a ; or newline. If at any time we read a non-HEX digit, we bail. If we hit a
  178. # ;, indicating an chunk-extension, we'll read up to the next
  179. # MAX_REQUEST_LINE characters
  180. # looking for the CRLF, and if we don't find it, we bail. If we read more than 16 hex characters,
  181. # (the number needed to represent a 64-bit chunk size), we bail (this protects us from
  182. # a client that sends an infinite stream of `F`, for example).
  183. buf = BytesIO()
  184. while 1:
  185. char = rfile.read(1)
  186. if not char:
  187. self._chunked_input_error = True
  188. raise _InvalidClientInput("EOF before chunk end reached")
  189. if char == b'\r':
  190. break
  191. if char == b';':
  192. break
  193. if char not in _HEX:
  194. self._chunked_input_error = True
  195. raise _InvalidClientInput("Non-hex data", char)
  196. buf.write(char)
  197. if buf.tell() > 16:
  198. self._chunked_input_error = True
  199. raise _InvalidClientInput("Chunk-size too large.")
  200. if char == b';':
  201. i = 0
  202. while i < MAX_REQUEST_LINE:
  203. char = rfile.read(1)
  204. if char == b'\r':
  205. break
  206. i += 1
  207. else:
  208. # we read more than MAX_REQUEST_LINE without
  209. # hitting CR
  210. self._chunked_input_error = True
  211. raise _InvalidClientInput("Too large chunk extension")
  212. if char == b'\r':
  213. # We either got here from the main loop or from the
  214. # end of an extension
  215. char = rfile.read(1)
  216. if char != b'\n':
  217. self._chunked_input_error = True
  218. raise _InvalidClientInput("Line didn't end in CRLF")
  219. return int(buf.getvalue(), 16)
  220. def _chunked_read(self, length=None, use_readline=False):
  221. # pylint:disable=too-many-branches
  222. rfile = self.rfile
  223. self._send_100_continue()
  224. if length == 0:
  225. return b""
  226. if length is not None and length < 0:
  227. length = None
  228. if use_readline:
  229. reader = self.rfile.readline
  230. else:
  231. reader = self.rfile.read
  232. response = []
  233. while self.chunk_length != 0:
  234. maxreadlen = self.chunk_length - self.position
  235. if length is not None and length < maxreadlen:
  236. maxreadlen = length
  237. if maxreadlen > 0:
  238. data = reader(maxreadlen)
  239. if not data:
  240. self.chunk_length = 0
  241. self._chunked_input_error = True
  242. raise IOError("unexpected end of file while parsing chunked data")
  243. datalen = len(data)
  244. response.append(data)
  245. self.position += datalen
  246. if self.chunk_length == self.position:
  247. rfile.readline()
  248. if length is not None:
  249. length -= datalen
  250. if length == 0:
  251. break
  252. if use_readline and data[-1] == b"\n"[0]:
  253. break
  254. else:
  255. # We're at the beginning of a chunk, so we need to
  256. # determine the next size to read
  257. self.chunk_length = self.__read_chunk_length(rfile)
  258. self.position = 0
  259. if self.chunk_length == 0:
  260. # Last chunk. Terminates with a CRLF.
  261. rfile.readline()
  262. return b''.join(response)
  263. def read(self, length=None):
  264. if self.chunked_input:
  265. return self._chunked_read(length)
  266. return self._do_read(length)
  267. def readline(self, size=None):
  268. if self.chunked_input:
  269. return self._chunked_read(size, True)
  270. return self._do_read(size, use_readline=True)
  271. def readlines(self, hint=None):
  272. # pylint:disable=unused-argument
  273. return list(self)
  274. def __iter__(self):
  275. return self
  276. def next(self):
  277. line = self.readline()
  278. if not line:
  279. raise StopIteration
  280. return line
  281. __next__ = next
  282. try:
  283. import mimetools
  284. headers_factory = mimetools.Message
  285. except ImportError:
  286. # adapt Python 3 HTTP headers to old API
  287. from http import client # pylint:disable=import-error
  288. class OldMessage(client.HTTPMessage):
  289. def __init__(self, **kwargs):
  290. super(client.HTTPMessage, self).__init__(**kwargs) # pylint:disable=bad-super-call
  291. self.status = ''
  292. def getheader(self, name, default=None):
  293. return self.get(name, default)
  294. @property
  295. def headers(self):
  296. for key, value in self._headers:
  297. yield '%s: %s\r\n' % (key, value)
  298. @property
  299. def typeheader(self):
  300. return self.get('content-type')
  301. def headers_factory(fp, *args): # pylint:disable=unused-argument
  302. try:
  303. ret = client.parse_headers(fp, _class=OldMessage)
  304. except client.LineTooLong:
  305. ret = OldMessage()
  306. ret.status = 'Line too long'
  307. return ret
  308. class WSGIHandler(object):
  309. """
  310. Handles HTTP requests from a socket, creates the WSGI environment, and
  311. interacts with the WSGI application.
  312. This is the default value of :attr:`WSGIServer.handler_class`.
  313. This class may be subclassed carefully, and that class set on a
  314. :class:`WSGIServer` instance through a keyword argument at
  315. construction time.
  316. Instances are constructed with the same arguments as passed to the
  317. server's :meth:`WSGIServer.handle` method followed by the server
  318. itself. The application and environment are obtained from the server.
  319. """
  320. # pylint:disable=too-many-instance-attributes
  321. protocol_version = 'HTTP/1.1'
  322. if PY3:
  323. # if we do like Py2, then headers_factory unconditionally
  324. # becomes a bound method, meaning the fp argument becomes WSGIHandler
  325. def MessageClass(self, *args):
  326. return headers_factory(*args)
  327. else:
  328. MessageClass = headers_factory
  329. # Attributes reset at various times for each request; not public
  330. # documented. Class attributes to keep the constructor fast
  331. # (but not make lint tools complain)
  332. status = None # byte string: b'200 OK'
  333. _orig_status = None # native string: '200 OK'
  334. response_headers = None # list of tuples (b'name', b'value')
  335. code = None # Integer parsed from status
  336. provided_date = None
  337. provided_content_length = None
  338. close_connection = False
  339. time_start = 0 # time.time() when begin handling request
  340. time_finish = 0 # time.time() when done handling request
  341. headers_sent = False # Have we already sent headers?
  342. response_use_chunked = False # Write with transfer-encoding chunked
  343. environ = None # Dict from self.get_environ
  344. application = None # application callable from self.server.application
  345. requestline = None # native str 'GET / HTTP/1.1'
  346. response_length = 0 # How much data we sent
  347. result = None # The return value of the WSGI application
  348. wsgi_input = None # Instance of Input()
  349. content_length = 0 # From application-provided headers Incoming
  350. # request headers, instance of MessageClass (gunicorn uses hasattr
  351. # on this so the default value needs to be compatible with the
  352. # API)
  353. headers = headers_factory(BytesIO())
  354. request_version = None # str: 'HTTP 1.1'
  355. command = None # str: 'GET'
  356. path = None # str: '/'
  357. def __init__(self, sock, address, server, rfile=None):
  358. # Deprecation: The rfile kwarg was introduced in 1.0a1 as part
  359. # of a refactoring. It was never documented or used. It is
  360. # considered DEPRECATED and may be removed in the future. Its
  361. # use is not supported.
  362. self.socket = sock
  363. self.client_address = address
  364. self.server = server
  365. if rfile is None:
  366. self.rfile = sock.makefile('rb', -1)
  367. else:
  368. self.rfile = rfile
  369. def handle(self):
  370. """
  371. The main request handling method, called by the server.
  372. This method runs a request handling loop, calling
  373. :meth:`handle_one_request` until all requests on the
  374. connection have been handled (that is, it implements
  375. keep-alive).
  376. """
  377. try:
  378. while self.socket is not None:
  379. self.time_start = time.time()
  380. self.time_finish = 0
  381. result = self.handle_one_request()
  382. if result is None:
  383. break
  384. if result is True:
  385. continue
  386. self.status, response_body = result
  387. self.socket.sendall(response_body)
  388. if self.time_finish == 0:
  389. self.time_finish = time.time()
  390. self.log_request()
  391. break
  392. finally:
  393. if self.socket is not None:
  394. _sock = getattr(self.socket, '_sock', None) # Python 3
  395. try:
  396. # read out request data to prevent error: [Errno 104] Connection reset by peer
  397. if _sock:
  398. try:
  399. # socket.recv would hang
  400. _sock.recv(16384)
  401. finally:
  402. _sock.close()
  403. self.socket.close()
  404. except socket.error:
  405. pass
  406. self.__dict__.pop('socket', None)
  407. self.__dict__.pop('rfile', None)
  408. def _check_http_version(self):
  409. version_str = self.request_version
  410. if not version_str.startswith("HTTP/"):
  411. return False
  412. version = tuple(int(x) for x in version_str[5:].split(".")) # "HTTP/"
  413. if version[1] < 0 or version < (0, 9) or version >= (2, 0):
  414. return False
  415. return True
  416. def read_request(self, raw_requestline):
  417. """
  418. Parse the incoming request.
  419. Parses various headers into ``self.headers`` using
  420. :attr:`MessageClass`. Other attributes that are set upon a successful
  421. return of this method include ``self.content_length`` and ``self.close_connection``.
  422. :param str raw_requestline: A native :class:`str` representing
  423. the request line. A processed version of this will be stored
  424. into ``self.requestline``.
  425. :raises ValueError: If the request is invalid. This error will
  426. not be logged as a traceback (because it's a client issue, not a server problem).
  427. :return: A boolean value indicating whether the request was successfully parsed.
  428. This method should either return a true value or have raised a ValueError
  429. with details about the parsing error.
  430. .. versionchanged:: 1.1b6
  431. Raise the previously documented :exc:`ValueError` in more cases instead of returning a
  432. false value; this allows subclasses more opportunity to customize behaviour.
  433. """
  434. # pylint:disable=too-many-branches
  435. self.requestline = raw_requestline.rstrip()
  436. words = self.requestline.split()
  437. if len(words) == 3:
  438. self.command, self.path, self.request_version = words
  439. if not self._check_http_version():
  440. raise _InvalidClientRequest('Invalid http version: %r', raw_requestline)
  441. elif len(words) == 2:
  442. self.command, self.path = words
  443. if self.command != "GET":
  444. raise _InvalidClientRequest('Expected GET method: %r', raw_requestline)
  445. self.request_version = "HTTP/0.9"
  446. # QQQ I'm pretty sure we can drop support for HTTP/0.9
  447. else:
  448. raise _InvalidClientRequest('Invalid HTTP method: %r', raw_requestline)
  449. self.headers = self.MessageClass(self.rfile, 0)
  450. if self.headers.status:
  451. raise _InvalidClientRequest('Invalid headers status: %r', self.headers.status)
  452. if self.headers.get("transfer-encoding", "").lower() == "chunked":
  453. try:
  454. del self.headers["content-length"]
  455. except KeyError:
  456. pass
  457. content_length = self.headers.get("content-length")
  458. if content_length is not None:
  459. content_length = int(content_length)
  460. if content_length < 0:
  461. raise _InvalidClientRequest('Invalid Content-Length: %r', content_length)
  462. if content_length and self.command in ('HEAD', ):
  463. raise _InvalidClientRequest('Unexpected Content-Length')
  464. self.content_length = content_length
  465. if self.request_version == "HTTP/1.1":
  466. conntype = self.headers.get("Connection", "").lower()
  467. self.close_connection = (conntype == 'close')
  468. else:
  469. self.close_connection = True
  470. return True
  471. def log_error(self, msg, *args):
  472. try:
  473. message = msg % args
  474. except Exception: # pylint:disable=broad-except
  475. traceback.print_exc()
  476. message = '%r %r' % (msg, args)
  477. try:
  478. message = '%s: %s' % (self.socket, message)
  479. except Exception: # pylint:disable=broad-except
  480. pass
  481. try:
  482. self.server.error_log.write(message + '\n')
  483. except Exception: # pylint:disable=broad-except
  484. traceback.print_exc()
  485. def read_requestline(self):
  486. """
  487. Read and return the HTTP request line.
  488. Under both Python 2 and 3, this should return the native
  489. ``str`` type; under Python 3, this probably means the bytes read
  490. from the network need to be decoded (using the ISO-8859-1 charset, aka
  491. latin-1).
  492. """
  493. line = self.rfile.readline(MAX_REQUEST_LINE)
  494. if PY3:
  495. line = line.decode('latin-1')
  496. return line
  497. def handle_one_request(self):
  498. """
  499. Handles one HTTP request using ``self.socket`` and ``self.rfile``.
  500. Each invocation of this method will do several things, including (but not limited to):
  501. - Read the request line using :meth:`read_requestline`;
  502. - Read the rest of the request, including headers, with :meth:`read_request`;
  503. - Construct a new WSGI environment in ``self.environ`` using :meth:`get_environ`;
  504. - Store the application in ``self.application``, retrieving it from the server;
  505. - Handle the remainder of the request, including invoking the application,
  506. with :meth:`handle_one_response`
  507. There are several possible return values to indicate the state
  508. of the client connection:
  509. - ``None``
  510. The client connection is already closed or should
  511. be closed because the WSGI application or client set the
  512. ``Connection: close`` header. The request handling
  513. loop should terminate and perform cleanup steps.
  514. - (status, body)
  515. An HTTP status and body tuple. The request was in error,
  516. as detailed by the status and body. The request handling
  517. loop should terminate, close the connection, and perform
  518. cleanup steps. Note that the ``body`` is the complete contents
  519. to send to the client, including all headers and the initial
  520. status line.
  521. - ``True``
  522. The literal ``True`` value. The request was successfully handled
  523. and the response sent to the client by :meth:`handle_one_response`.
  524. The connection remains open to process more requests and the connection
  525. handling loop should call this method again. This is the typical return
  526. value.
  527. .. seealso:: :meth:`handle`
  528. .. versionchanged:: 1.1b6
  529. Funnel exceptions having to do with invalid HTTP requests through
  530. :meth:`_handle_client_error` to allow subclasses to customize. Note that
  531. this is experimental and may change in the future.
  532. """
  533. # pylint:disable=too-many-return-statements
  534. if self.rfile.closed:
  535. return
  536. try:
  537. self.requestline = self.read_requestline()
  538. # Account for old subclasses that haven't done this
  539. if PY3 and isinstance(self.requestline, bytes):
  540. self.requestline = self.requestline.decode('latin-1')
  541. except socket.error:
  542. # "Connection reset by peer" or other socket errors aren't interesting here
  543. return
  544. if not self.requestline:
  545. return
  546. self.response_length = 0
  547. if len(self.requestline) >= MAX_REQUEST_LINE:
  548. return ('414', _REQUEST_TOO_LONG_RESPONSE)
  549. try:
  550. # for compatibility with older versions of pywsgi, we pass self.requestline as an argument there
  551. # NOTE: read_request is supposed to raise ValueError on invalid input; allow old
  552. # subclasses that return a False value instead.
  553. # NOTE: This can mutate the value of self.headers, so self.get_environ() must not be
  554. # called until AFTER this call is done.
  555. if not self.read_request(self.requestline):
  556. return ('400', _BAD_REQUEST_RESPONSE)
  557. except Exception as ex: # pylint:disable=broad-except
  558. # Notice we don't use self.handle_error because it reports
  559. # a 500 error to the client, and this is almost certainly
  560. # a client error.
  561. # Provide a hook for subclasses.
  562. return self._handle_client_error(ex)
  563. self.environ = self.get_environ()
  564. self.application = self.server.application
  565. self.handle_one_response()
  566. if self.close_connection:
  567. return
  568. if self.rfile.closed:
  569. return
  570. return True # read more requests
  571. def finalize_headers(self):
  572. if self.provided_date is None:
  573. self.response_headers.append((b'Date', format_date_time(time.time())))
  574. if self.code not in (304, 204):
  575. # the reply will include message-body; make sure we have either Content-Length or chunked
  576. if self.provided_content_length is None:
  577. if hasattr(self.result, '__len__'):
  578. total_len = sum(len(chunk) for chunk in self.result)
  579. total_len_str = str(total_len)
  580. if PY3:
  581. total_len_str = total_len_str.encode("latin-1")
  582. self.response_headers.append((b'Content-Length', total_len_str))
  583. else:
  584. if self.request_version != 'HTTP/1.0':
  585. self.response_use_chunked = True
  586. self.response_headers.append((b'Transfer-Encoding', b'chunked'))
  587. def _sendall(self, data):
  588. try:
  589. self.socket.sendall(data)
  590. except socket.error as ex:
  591. self.status = 'socket error: %s' % ex
  592. if self.code > 0:
  593. self.code = -self.code
  594. raise
  595. self.response_length += len(data)
  596. def _write(self, data):
  597. if not data:
  598. # The application/middleware are allowed to yield
  599. # empty bytestrings.
  600. return
  601. if self.response_use_chunked:
  602. ## Write the chunked encoding
  603. header = ("%x\r\n" % len(data)).encode('ascii')
  604. # socket.sendall will slice these small strings, as [0:],
  605. # but that's special cased to return the original string.
  606. # They're small enough we probably expect them to go down to the network
  607. # buffers in one go anyway.
  608. self._sendall(header)
  609. self._sendall(data)
  610. self._sendall(b'\r\n') # trailer
  611. else:
  612. self._sendall(data)
  613. def write(self, data):
  614. # The write() callable we return from start_response.
  615. # https://www.python.org/dev/peps/pep-3333/#the-write-callable
  616. # Supposed to do pretty much the same thing as yielding values
  617. # from the application's return.
  618. if self.code in (304, 204) and data:
  619. raise AssertionError('The %s response must have no body' % self.code)
  620. if self.headers_sent:
  621. self._write(data)
  622. else:
  623. if not self.status:
  624. raise AssertionError("The application did not call start_response()")
  625. self._write_with_headers(data)
  626. def _write_with_headers(self, data):
  627. towrite = bytearray()
  628. self.headers_sent = True
  629. self.finalize_headers()
  630. # self.response_headers and self.status are already in latin-1, as encoded by self.start_response
  631. towrite.extend(b'HTTP/1.1 ')
  632. towrite.extend(self.status)
  633. towrite.extend(b'\r\n')
  634. for header, value in self.response_headers:
  635. towrite.extend(header)
  636. towrite.extend(b': ')
  637. towrite.extend(value)
  638. towrite.extend(b"\r\n")
  639. towrite.extend(b'\r\n')
  640. self._sendall(towrite)
  641. # No need to copy the data into towrite; we may make an extra syscall
  642. # but the copy time could be substantial too, and it reduces the chances
  643. # of sendall being able to send everything in one go
  644. self._write(data)
  645. def start_response(self, status, headers, exc_info=None):
  646. """
  647. .. versionchanged:: 1.2a1
  648. Avoid HTTP header injection by raising a :exc:`ValueError`
  649. if *status* or any *header* name or value contains a carriage
  650. return or newline.
  651. .. versionchanged:: 1.1b5
  652. Pro-actively handle checking the encoding of the status line
  653. and headers during this method. On Python 2, avoid some
  654. extra encodings.
  655. """
  656. # pylint:disable=too-many-branches,too-many-statements
  657. if exc_info:
  658. try:
  659. if self.headers_sent:
  660. # Re-raise original exception if headers sent
  661. reraise(*exc_info)
  662. finally:
  663. # Avoid dangling circular ref
  664. exc_info = None
  665. # Pep 3333, "The start_response callable":
  666. # https://www.python.org/dev/peps/pep-3333/#the-start-response-callable
  667. # "Servers should check for errors in the headers at the time
  668. # start_response is called, so that an error can be raised
  669. # while the application is still running." Here, we check the encoding.
  670. # This aids debugging: headers especially are generated programatically
  671. # and an encoding error in a loop or list comprehension yields an opaque
  672. # UnicodeError without any clue which header was wrong.
  673. # Note that this results in copying the header list at this point, not modifying it,
  674. # although we are allowed to do so if needed. This slightly increases memory usage.
  675. # We also check for HTTP Response Splitting vulnerabilities
  676. response_headers = []
  677. header = None
  678. value = None
  679. try:
  680. for header, value in headers:
  681. if not isinstance(header, str):
  682. raise UnicodeError("The header must be a native string", header, value)
  683. if not isinstance(value, str):
  684. raise UnicodeError("The value must be a native string", header, value)
  685. if '\r' in header or '\n' in header:
  686. raise ValueError('carriage return or newline in header name', header)
  687. if '\r' in value or '\n' in value:
  688. raise ValueError('carriage return or newline in header value', value)
  689. # Either we're on Python 2, in which case bytes is correct, or
  690. # we're on Python 3 and the user screwed up (because it should be a native
  691. # string). In either case, make sure that this is latin-1 compatible. Under
  692. # Python 2, bytes.encode() will take a round-trip through the system encoding,
  693. # which may be ascii, which is not really what we want. However, the latin-1 encoding
  694. # can encode everything except control characters and the block from 0x7F to 0x9F, so
  695. # explicitly round-tripping bytes through the encoding is unlikely to be of much
  696. # benefit, so we go for speed (the WSGI spec specifically calls out allowing the range
  697. # from 0x00 to 0xFF, although the HTTP spec forbids the control characters).
  698. # Note: Some Python 2 implementations, like Jython, may allow non-octet (above 255) values
  699. # in their str implementation; this is mentioned in the WSGI spec, but we don't
  700. # run on any platform like that so we can assume that a str value is pure bytes.
  701. response_headers.append((header if not PY3 else header.encode("latin-1"),
  702. value if not PY3 else value.encode("latin-1")))
  703. except UnicodeEncodeError:
  704. # If we get here, we're guaranteed to have a header and value
  705. raise UnicodeError("Non-latin1 header", repr(header), repr(value))
  706. # Same as above
  707. if not isinstance(status, str):
  708. raise UnicodeError("The status string must be a native string")
  709. if '\r' in status or '\n' in status:
  710. raise ValueError("carriage return or newline in status", status)
  711. # don't assign to anything until the validation is complete, including parsing the
  712. # code
  713. code = int(status.split(' ', 1)[0])
  714. self.status = status if not PY3 else status.encode("latin-1")
  715. self._orig_status = status # Preserve the native string for logging
  716. self.response_headers = response_headers
  717. self.code = code
  718. provided_connection = None
  719. self.provided_date = None
  720. self.provided_content_length = None
  721. for header, value in headers:
  722. header = header.lower()
  723. if header == 'connection':
  724. provided_connection = value
  725. elif header == 'date':
  726. self.provided_date = value
  727. elif header == 'content-length':
  728. self.provided_content_length = value
  729. if self.request_version == 'HTTP/1.0' and provided_connection is None:
  730. response_headers.append((b'Connection', b'close'))
  731. self.close_connection = True
  732. elif provided_connection == 'close':
  733. self.close_connection = True
  734. if self.code in (304, 204):
  735. if self.provided_content_length is not None and self.provided_content_length != '0':
  736. msg = 'Invalid Content-Length for %s response: %r (must be absent or zero)' % (self.code, self.provided_content_length)
  737. if PY3:
  738. msg = msg.encode('latin-1')
  739. raise AssertionError(msg)
  740. return self.write
  741. def log_request(self):
  742. self.server.log.write(self.format_request() + '\n')
  743. def format_request(self):
  744. now = datetime.now().replace(microsecond=0)
  745. length = self.response_length or '-'
  746. if self.time_finish:
  747. delta = '%.6f' % (self.time_finish - self.time_start)
  748. else:
  749. delta = '-'
  750. client_address = self.client_address[0] if isinstance(self.client_address, tuple) else self.client_address
  751. return '%s - - [%s] "%s" %s %s %s' % (
  752. client_address or '-',
  753. now,
  754. self.requestline or '',
  755. # Use the native string version of the status, saved so we don't have to
  756. # decode. But fallback to the encoded 'status' in case of subclasses
  757. # (Is that really necessary? At least there's no overhead.)
  758. (self._orig_status or self.status or '000').split()[0],
  759. length,
  760. delta)
  761. def process_result(self):
  762. for data in self.result:
  763. if data:
  764. self.write(data)
  765. if self.status and not self.headers_sent:
  766. # In other words, the application returned an empty
  767. # result iterable (and did not use the write callable)
  768. # Trigger the flush of the headers.
  769. self.write(b'')
  770. if self.response_use_chunked:
  771. self.socket.sendall(b'0\r\n\r\n')
  772. self.response_length += 5
  773. def run_application(self):
  774. assert self.result is None
  775. try:
  776. self.result = self.application(self.environ, self.start_response)
  777. self.process_result()
  778. finally:
  779. close = getattr(self.result, 'close', None)
  780. try:
  781. if close is not None:
  782. close()
  783. finally:
  784. # Discard the result. If it's a generator this can
  785. # free a lot of hidden resources (if we failed to iterate
  786. # all the way through it---the frames are automatically
  787. # cleaned up when StopIteration is raised); but other cases
  788. # could still free up resources sooner than otherwise.
  789. close = None
  790. self.result = None
  791. def handle_one_response(self):
  792. self.time_start = time.time()
  793. self.status = None
  794. self.headers_sent = False
  795. self.result = None
  796. self.response_use_chunked = False
  797. self.response_length = 0
  798. try:
  799. try:
  800. self.run_application()
  801. finally:
  802. try:
  803. self.wsgi_input._discard()
  804. except (socket.error, IOError):
  805. # Don't let exceptions during discarding
  806. # input override any exception that may have been
  807. # raised by the application, such as our own _InvalidClientInput.
  808. # In the general case, these aren't even worth logging (see the comment
  809. # just below)
  810. pass
  811. except _InvalidClientInput:
  812. self._send_error_response_if_possible(400)
  813. except socket.error as ex:
  814. if ex.args[0] in (errno.EPIPE, errno.ECONNRESET):
  815. # Broken pipe, connection reset by peer.
  816. # Swallow these silently to avoid spewing
  817. # useless info on normal operating conditions,
  818. # bloating logfiles. See https://github.com/gevent/gevent/pull/377
  819. # and https://github.com/gevent/gevent/issues/136.
  820. if not PY3:
  821. sys.exc_clear()
  822. self.close_connection = True
  823. else:
  824. self.handle_error(*sys.exc_info())
  825. except: # pylint:disable=bare-except
  826. self.handle_error(*sys.exc_info())
  827. finally:
  828. self.time_finish = time.time()
  829. self.log_request()
  830. def _send_error_response_if_possible(self, error_code):
  831. if self.response_length:
  832. self.close_connection = True
  833. else:
  834. status, headers, body = _ERRORS[error_code]
  835. try:
  836. self.start_response(status, headers[:])
  837. self.write(body)
  838. except socket.error:
  839. if not PY3:
  840. sys.exc_clear()
  841. self.close_connection = True
  842. def _log_error(self, t, v, tb):
  843. # TODO: Shouldn't we dump this to wsgi.errors? If we did that now, it would
  844. # wind up getting logged twice
  845. if not issubclass(t, GreenletExit):
  846. context = self.environ
  847. if not isinstance(context, self.server.secure_environ_class):
  848. context = self.server.secure_environ_class(context)
  849. self.server.loop.handle_error(context, t, v, tb)
  850. def handle_error(self, t, v, tb):
  851. # Called for internal, unexpected errors, NOT invalid client input
  852. self._log_error(t, v, tb)
  853. del tb
  854. self._send_error_response_if_possible(500)
  855. def _handle_client_error(self, ex):
  856. # Called for invalid client input
  857. # Returns the appropriate error response.
  858. if not isinstance(ex, ValueError):
  859. # XXX: Why not self._log_error to send it through the loop's
  860. # handle_error method?
  861. traceback.print_exc()
  862. if isinstance(ex, _InvalidClientRequest):
  863. # These come with good error messages, and we want to let
  864. # log_error deal with the formatting, especially to handle encoding
  865. self.log_error(*ex.args)
  866. else:
  867. self.log_error('Invalid request: %s', str(ex) or ex.__class__.__name__)
  868. return ('400', _BAD_REQUEST_RESPONSE)
  869. def _headers(self):
  870. key = None
  871. value = None
  872. IGNORED_KEYS = (None, 'CONTENT_TYPE', 'CONTENT_LENGTH')
  873. for header in self.headers.headers:
  874. if key is not None and header[:1] in " \t":
  875. value += header
  876. continue
  877. if key not in IGNORED_KEYS:
  878. yield 'HTTP_' + key, value.strip()
  879. key, value = header.split(':', 1)
  880. if '_' in key:
  881. # strip incoming bad veaders
  882. key = None
  883. else:
  884. key = key.replace('-', '_').upper()
  885. if key not in IGNORED_KEYS:
  886. yield 'HTTP_' + key, value.strip()
  887. def get_environ(self):
  888. """
  889. Construct and return a new WSGI environment dictionary for a specific request.
  890. This should begin with asking the server for the base environment
  891. using :meth:`WSGIServer.get_environ`, and then proceed to add the
  892. request specific values.
  893. By the time this method is invoked the request line and request shall have
  894. been parsed and ``self.headers`` shall be populated.
  895. """
  896. env = self.server.get_environ()
  897. env['REQUEST_METHOD'] = self.command
  898. env['SCRIPT_NAME'] = ''
  899. if '?' in self.path:
  900. path, query = self.path.split('?', 1)
  901. else:
  902. path, query = self.path, ''
  903. # Note that self.path contains the original str object; if it contains
  904. # encoded escapes, it will NOT match PATH_INFO.
  905. env['PATH_INFO'] = unquote_latin1(path)
  906. env['QUERY_STRING'] = query
  907. if self.headers.typeheader is not None:
  908. env['CONTENT_TYPE'] = self.headers.typeheader
  909. length = self.headers.getheader('content-length')
  910. if length:
  911. env['CONTENT_LENGTH'] = length
  912. env['SERVER_PROTOCOL'] = self.request_version
  913. client_address = self.client_address
  914. if isinstance(client_address, tuple):
  915. env['REMOTE_ADDR'] = str(client_address[0])
  916. env['REMOTE_PORT'] = str(client_address[1])
  917. for key, value in self._headers():
  918. if key in env:
  919. if 'COOKIE' in key:
  920. env[key] += '; ' + value
  921. else:
  922. env[key] += ',' + value
  923. else:
  924. env[key] = value
  925. if env.get('HTTP_EXPECT') == '100-continue':
  926. sock = self.socket
  927. else:
  928. sock = None
  929. chunked = env.get('HTTP_TRANSFER_ENCODING', '').lower() == 'chunked'
  930. self.wsgi_input = Input(self.rfile, self.content_length, socket=sock, chunked_input=chunked)
  931. env['wsgi.input'] = self.wsgi_input
  932. return env
  933. class _NoopLog(object):
  934. # Does nothing; implements just enough file-like methods
  935. # to pass the WSGI validator
  936. def write(self, *args, **kwargs):
  937. # pylint:disable=unused-argument
  938. return
  939. def flush(self):
  940. pass
  941. def writelines(self, *args, **kwargs):
  942. pass
  943. class LoggingLogAdapter(object):
  944. """
  945. An adapter for :class:`logging.Logger` instances
  946. to let them be used with :class:`WSGIServer`.
  947. .. warning:: Unless the entire process is monkey-patched at a very
  948. early part of the lifecycle (before logging is configured),
  949. loggers are likely to not be gevent-cooperative. For example,
  950. the socket and syslog handlers use the socket module in a way
  951. that can block, and most handlers acquire threading locks.
  952. .. warning:: It *may* be possible for the logging functions to be
  953. called in the :class:`gevent.Hub` greenlet. Code running in the
  954. hub greenlet cannot use any gevent blocking functions without triggering
  955. a ``LoopExit``.
  956. .. versionadded:: 1.1a3
  957. .. versionchanged:: 1.1b6
  958. Attributes not present on this object are proxied to the underlying
  959. logger instance. This permits using custom :class:`~logging.Logger`
  960. subclasses (or indeed, even duck-typed objects).
  961. .. versionchanged:: 1.1
  962. Strip trailing newline characters on the message passed to :meth:`write`
  963. because log handlers will usually add one themselves.
  964. """
  965. # gevent avoids importing and using logging because importing it and
  966. # creating loggers creates native locks unless monkey-patched.
  967. __slots__ = ('_logger', '_level')
  968. def __init__(self, logger, level=20):
  969. """
  970. Write information to the *logger* at the given *level* (default to INFO).
  971. """
  972. self._logger = logger
  973. self._level = level
  974. def write(self, msg):
  975. if msg and msg.endswith('\n'):
  976. msg = msg[:-1]
  977. self._logger.log(self._level, msg)
  978. def flush(self):
  979. "No-op; required to be a file-like object"
  980. pass
  981. def writelines(self, lines):
  982. for line in lines:
  983. self.write(line)
  984. def __getattr__(self, name):
  985. return getattr(self._logger, name)
  986. def __setattr__(self, name, value):
  987. if name not in LoggingLogAdapter.__slots__:
  988. setattr(self._logger, name, value)
  989. else:
  990. object.__setattr__(self, name, value)
  991. def __delattr__(self, name):
  992. delattr(self._logger, name)
  993. ####
  994. ## Environ classes.
  995. # These subclass dict. They could subclass collections.UserDict on
  996. # 3.3+ and proxy to the underlying real dict to avoid a copy if we
  997. # have to print them (on 2.7 it's slightly more complicated to be an
  998. # instance of collections.MutableMapping; UserDict.UserDict isn't.)
  999. # Then we could have either the WSGIHandler.get_environ or the
  1000. # WSGIServer.get_environ return one of these proxies, and
  1001. # WSGIHandler.run_application would know to access the `environ.data`
  1002. # attribute to be able to pass the *real* dict to the application
  1003. # (because PEP3333 requires no subclasses, only actual dict objects;
  1004. # wsgiref.validator and webob.Request both enforce this). This has the
  1005. # advantage of not being fragile if anybody else tries to print/log
  1006. # self.environ (and not requiring a copy). However, if there are any
  1007. # subclasses of Handler or Server, this could break if they don't know
  1008. # to return this type.
  1009. ####
  1010. class Environ(dict):
  1011. """
  1012. A base class that can be used for WSGI environment objects.
  1013. Provisional API.
  1014. .. versionadded:: 1.2a1
  1015. """
  1016. __slots__ = () # add no ivars or weakref ability
  1017. def copy(self):
  1018. return self.__class__(self)
  1019. if not hasattr(dict, 'iteritems'):
  1020. # Python 3
  1021. def iteritems(self):
  1022. return self.items()
  1023. def __reduce_ex__(self, proto):
  1024. return (dict, (), None, None, iter(self.iteritems()))
  1025. class SecureEnviron(Environ):
  1026. """
  1027. An environment that does not print its keys and values
  1028. by default.
  1029. Provisional API.
  1030. This is intended to keep potentially sensitive information like
  1031. HTTP authorization and cookies from being inadvertently printed
  1032. or logged.
  1033. For debugging, each instance can have its *secure_repr* attribute
  1034. set to ``False``, which will cause it to print like a normal dict.
  1035. When *secure_repr* is ``True`` (the default), then the value of
  1036. the *whitelist_keys* attribute is consulted; if this value is
  1037. true-ish, it should be a container (something that responds to
  1038. ``in``) of key names (typically a list or set). Keys and values in
  1039. this dictionary that are in *whitelist_keys* will then be printed,
  1040. while all other values will be masked. These values may be
  1041. customized on the class by setting the *default_secure_repr* and
  1042. *default_whitelist_keys*, respectively::
  1043. >>> environ = SecureEnviron(key='value')
  1044. >>> environ # doctest: +ELLIPSIS
  1045. <pywsgi.SecureEnviron dict (keys: 1) at ...
  1046. If we whitelist the key, it gets printed::
  1047. >>> environ.whitelist_keys = {'key'}
  1048. >>> environ
  1049. {'key': 'value'}
  1050. A non-whitelisted key (*only*, to avoid doctest issues) is masked::
  1051. >>> environ['secure'] = 'secret'; del environ['key']
  1052. >>> environ
  1053. {'secure': '<MASKED>'}
  1054. We can turn it off entirely for the instance::
  1055. >>> environ.secure_repr = False
  1056. >>> environ
  1057. {'secure': 'secret'}
  1058. We can also customize it at the class level (here we use a new
  1059. class to be explicit and to avoid polluting the true default
  1060. values; we would set this class to be the ``environ_class`` of the
  1061. server)::
  1062. >>> class MyEnviron(SecureEnviron):
  1063. ... default_whitelist_keys = ('key',)
  1064. ...
  1065. >>> environ = MyEnviron({'key': 'value'})
  1066. >>> environ
  1067. {'key': 'value'}
  1068. .. versionadded:: 1.2a1
  1069. """
  1070. default_secure_repr = True
  1071. default_whitelist_keys = ()
  1072. default_print_masked_keys = True
  1073. # Allow instances to override the class values,
  1074. # but inherit from the class if not present. Keeps instances
  1075. # small since we can't combine __slots__ with class attributes
  1076. # of the same name.
  1077. __slots__ = ('secure_repr', 'whitelist_keys', 'print_masked_keys')
  1078. def __getattr__(self, name):
  1079. if name in SecureEnviron.__slots__:
  1080. return getattr(type(self), 'default_' + name)
  1081. raise AttributeError(name)
  1082. def __repr__(self):
  1083. if self.secure_repr:
  1084. whitelist = self.whitelist_keys
  1085. print_masked = self.print_masked_keys
  1086. if whitelist:
  1087. safe = {k: self[k] if k in whitelist else "<MASKED>"
  1088. for k in self
  1089. if k in whitelist or print_masked}
  1090. safe_repr = repr(safe)
  1091. if not print_masked and len(safe) != len(self):
  1092. safe_repr = safe_repr[:-1] + ", (hidden keys: %d)}" % (len(self) - len(safe))
  1093. return safe_repr
  1094. return "<pywsgi.SecureEnviron dict (keys: %d) at %s>" % (len(self), id(self))
  1095. return Environ.__repr__(self)
  1096. __str__ = __repr__
  1097. class WSGISecureEnviron(SecureEnviron):
  1098. """
  1099. Specializes the default list of whitelisted keys to a few
  1100. common WSGI variables.
  1101. Example::
  1102. >>> environ = WSGISecureEnviron(REMOTE_ADDR='::1', HTTP_AUTHORIZATION='secret')
  1103. >>> environ
  1104. {'REMOTE_ADDR': '::1', (hidden keys: 1)}
  1105. >>> import pprint
  1106. >>> pprint.pprint(environ)
  1107. {'REMOTE_ADDR': '::1', (hidden keys: 1)}
  1108. >>> print(pprint.pformat(environ))
  1109. {'REMOTE_ADDR': '::1', (hidden keys: 1)}
  1110. """
  1111. default_whitelist_keys = ('REMOTE_ADDR', 'REMOTE_PORT', 'HTTP_HOST')
  1112. default_print_masked_keys = False
  1113. class WSGIServer(StreamServer):
  1114. """
  1115. A WSGI server based on :class:`StreamServer` that supports HTTPS.
  1116. :keyword log: If given, an object with a ``write`` method to which
  1117. request (access) logs will be written. If not given, defaults
  1118. to :obj:`sys.stderr`. You may pass ``None`` to disable request
  1119. logging. You may use a wrapper, around e.g., :mod:`logging`,
  1120. to support objects that don't implement a ``write`` method.
  1121. (If you pass a :class:`~logging.Logger` instance, or in
  1122. general something that provides a ``log`` method but not a
  1123. ``write`` method, such a wrapper will automatically be created
  1124. and it will be logged to at the :data:`~logging.INFO` level.)
  1125. :keyword error_log: If given, a file-like object with ``write``,
  1126. ``writelines`` and ``flush`` methods to which error logs will
  1127. be written. If not given, defaults to :obj:`sys.stderr`. You
  1128. may pass ``None`` to disable error logging (not recommended).
  1129. You may use a wrapper, around e.g., :mod:`logging`, to support
  1130. objects that don't implement the proper methods. This
  1131. parameter will become the value for ``wsgi.errors`` in the
  1132. WSGI environment (if not already set). (As with *log*,
  1133. wrappers for :class:`~logging.Logger` instances and the like
  1134. will be created automatically and logged to at the :data:`~logging.ERROR`
  1135. level.)
  1136. .. seealso::
  1137. :class:`LoggingLogAdapter`
  1138. See important warnings before attempting to use :mod:`logging`.
  1139. .. versionchanged:: 1.1a3
  1140. Added the ``error_log`` parameter, and set ``wsgi.errors`` in the WSGI
  1141. environment to this value.
  1142. .. versionchanged:: 1.1a3
  1143. Add support for passing :class:`logging.Logger` objects to the ``log`` and
  1144. ``error_log`` arguments.
  1145. """
  1146. #: A callable taking three arguments: (socket, address, server) and returning
  1147. #: an object with a ``handle()`` method. The callable is called once for
  1148. #: each incoming socket request, as is its handle method. The handle method should not
  1149. #: return until all use of the socket is complete.
  1150. #:
  1151. #: This class uses the :class:`WSGIHandler` object as the default value. You may
  1152. #: subclass this class and set a different default value, or you may pass
  1153. #: a value to use in the ``handler_class`` keyword constructor argument.
  1154. handler_class = WSGIHandler
  1155. #: The object to which request logs will be written.
  1156. #: It must never be None. Initialized from the ``log`` constructor
  1157. #: parameter.
  1158. log = None
  1159. #: The object to which error logs will be written.
  1160. #: It must never be None. Initialized from the ``error_log`` constructor
  1161. #: parameter.
  1162. error_log = None
  1163. #: The class of environ objects passed to the handlers.
  1164. #: Must be a dict subclass. For compliance with :pep:`3333`
  1165. #: and libraries like WebOb, this is simply :class:`dict`
  1166. #: but this can be customized in a subclass or per-instance
  1167. #: (probably to :class:`WSGISecureEnviron`).
  1168. #:
  1169. #: .. versionadded:: 1.2a1
  1170. environ_class = dict
  1171. # Undocumented internal detail: the class that WSGIHandler._log_error
  1172. # will cast to before passing to the loop.
  1173. secure_environ_class = WSGISecureEnviron
  1174. base_env = {'GATEWAY_INTERFACE': 'CGI/1.1',
  1175. 'SERVER_SOFTWARE': 'gevent/%d.%d Python/%d.%d' % (gevent.version_info[:2] + sys.version_info[:2]),
  1176. 'SCRIPT_NAME': '',
  1177. 'wsgi.version': (1, 0),
  1178. 'wsgi.multithread': False, # XXX: Aren't we really, though?
  1179. 'wsgi.multiprocess': False,
  1180. 'wsgi.run_once': False}
  1181. def __init__(self, listener, application=None, backlog=None, spawn='default',
  1182. log='default', error_log='default',
  1183. handler_class=None,
  1184. environ=None, **ssl_args):
  1185. StreamServer.__init__(self, listener, backlog=backlog, spawn=spawn, **ssl_args)
  1186. if application is not None:
  1187. self.application = application
  1188. if handler_class is not None:
  1189. self.handler_class = handler_class
  1190. # Note that we can't initialize these as class variables:
  1191. # sys.stderr might get monkey patched at runtime.
  1192. def _make_log(l, level=20):
  1193. if l == 'default':
  1194. return sys.stderr
  1195. if l is None:
  1196. return _NoopLog()
  1197. if not hasattr(l, 'write') and hasattr(l, 'log'):
  1198. return LoggingLogAdapter(l, level)
  1199. return l
  1200. self.log = _make_log(log)
  1201. self.error_log = _make_log(error_log, 40) # logging.ERROR
  1202. self.set_environ(environ)
  1203. self.set_max_accept()
  1204. def set_environ(self, environ=None):
  1205. if environ is not None:
  1206. self.environ = environ
  1207. environ_update = getattr(self, 'environ', None)
  1208. self.environ = self.environ_class(self.base_env)
  1209. if self.ssl_enabled:
  1210. self.environ['wsgi.url_scheme'] = 'https'
  1211. else:
  1212. self.environ['wsgi.url_scheme'] = 'http'
  1213. if environ_update is not None:
  1214. self.environ.update(environ_update)
  1215. if self.environ.get('wsgi.errors') is None:
  1216. self.environ['wsgi.errors'] = self.error_log
  1217. def set_max_accept(self):
  1218. if self.environ.get('wsgi.multiprocess'):
  1219. self.max_accept = 1
  1220. def get_environ(self):
  1221. return self.environ_class(self.environ)
  1222. def init_socket(self):
  1223. StreamServer.init_socket(self)
  1224. self.update_environ()
  1225. def update_environ(self):
  1226. """
  1227. Called before the first request is handled to fill in WSGI environment values.
  1228. This includes getting the correct server name and port.
  1229. """
  1230. address = self.address
  1231. if isinstance(address, tuple):
  1232. if 'SERVER_NAME' not in self.environ:
  1233. try:
  1234. name = socket.getfqdn(address[0])
  1235. except socket.error:
  1236. name = str(address[0])
  1237. if PY3 and not isinstance(name, str):
  1238. name = name.decode('ascii')
  1239. self.environ['SERVER_NAME'] = name
  1240. self.environ.setdefault('SERVER_PORT', str(address[1]))
  1241. else:
  1242. self.environ.setdefault('SERVER_NAME', '')
  1243. self.environ.setdefault('SERVER_PORT', '')
  1244. def handle(self, sock, address):
  1245. """
  1246. Create an instance of :attr:`handler_class` to handle the request.
  1247. This method blocks until the handler returns.
  1248. """
  1249. # pylint:disable=method-hidden
  1250. handler = self.handler_class(sock, address, self)
  1251. handler.handle()
  1252. def _main():
  1253. # Provisional main handler, for quick tests, not production
  1254. # usage.
  1255. from gevent import monkey; monkey.patch_all()
  1256. import argparse
  1257. import importlib
  1258. parser = argparse.ArgumentParser()
  1259. parser.add_argument("app", help="dotted name of WSGI app callable [module:callable]")
  1260. parser.add_argument("-b", "--bind",
  1261. help="The socket to bind",
  1262. default=":8080")
  1263. args = parser.parse_args()
  1264. module_name, app_name = args.app.split(':')
  1265. module = importlib.import_module(module_name)
  1266. app = getattr(module, app_name)
  1267. bind = args.bind
  1268. server = WSGIServer(bind, app)
  1269. server.serve_forever()
  1270. if __name__ == '__main__':
  1271. _main()