mercurial/hgweb/request.py
changeset 36876 97f44b0720e2
parent 36875 16499427f6de
child 36878 ccb70a77f746
equal deleted inserted replaced
36875:16499427f6de 36876:97f44b0720e2
   349         self.status = None
   349         self.status = None
   350         self.headers = wsgiheaders.Headers([])
   350         self.headers = wsgiheaders.Headers([])
   351 
   351 
   352         self._bodybytes = None
   352         self._bodybytes = None
   353         self._bodygen = None
   353         self._bodygen = None
       
   354         self._bodywillwrite = False
   354         self._started = False
   355         self._started = False
       
   356         self._bodywritefn = None
       
   357 
       
   358     def _verifybody(self):
       
   359         if (self._bodybytes is not None or self._bodygen is not None
       
   360             or self._bodywillwrite):
       
   361             raise error.ProgrammingError('cannot define body multiple times')
   355 
   362 
   356     def setbodybytes(self, b):
   363     def setbodybytes(self, b):
   357         """Define the response body as static bytes."""
   364         """Define the response body as static bytes."""
   358         if self._bodybytes is not None or self._bodygen is not None:
   365         self._verifybody()
   359             raise error.ProgrammingError('cannot define body multiple times')
       
   360 
       
   361         self._bodybytes = b
   366         self._bodybytes = b
   362         self.headers['Content-Length'] = '%d' % len(b)
   367         self.headers['Content-Length'] = '%d' % len(b)
   363 
   368 
   364     def setbodygen(self, gen):
   369     def setbodygen(self, gen):
   365         """Define the response body as a generator of bytes."""
   370         """Define the response body as a generator of bytes."""
   366         if self._bodybytes is not None or self._bodygen is not None:
   371         self._verifybody()
   367             raise error.ProgrammingError('cannot define body multiple times')
       
   368 
       
   369         self._bodygen = gen
   372         self._bodygen = gen
       
   373 
       
   374     def setbodywillwrite(self):
       
   375         """Signal an intent to use write() to emit the response body.
       
   376 
       
   377         **This is the least preferred way to send a body.**
       
   378 
       
   379         It is preferred for WSGI applications to emit a generator of chunks
       
   380         constituting the response body. However, some consumers can't emit
       
   381         data this way. So, WSGI provides a way to obtain a ``write(data)``
       
   382         function that can be used to synchronously perform an unbuffered
       
   383         write.
       
   384 
       
   385         Calling this function signals an intent to produce the body in this
       
   386         manner.
       
   387         """
       
   388         self._verifybody()
       
   389         self._bodywillwrite = True
   370 
   390 
   371     def sendresponse(self):
   391     def sendresponse(self):
   372         """Send the generated response to the client.
   392         """Send the generated response to the client.
   373 
   393 
   374         Before this is called, ``status`` must be set and one of
   394         Before this is called, ``status`` must be set and one of
   382         self._started = True
   402         self._started = True
   383 
   403 
   384         if not self.status:
   404         if not self.status:
   385             raise error.ProgrammingError('status line not defined')
   405             raise error.ProgrammingError('status line not defined')
   386 
   406 
   387         if self._bodybytes is None and self._bodygen is None:
   407         if (self._bodybytes is None and self._bodygen is None
       
   408             and not self._bodywillwrite):
   388             raise error.ProgrammingError('response body not defined')
   409             raise error.ProgrammingError('response body not defined')
   389 
   410 
   390         # Various HTTP clients (notably httplib) won't read the HTTP response
   411         # Various HTTP clients (notably httplib) won't read the HTTP response
   391         # until the HTTP request has been sent in full. If servers (us) send a
   412         # until the HTTP request has been sent in full. If servers (us) send a
   392         # response before the HTTP request has been fully sent, the connection
   413         # response before the HTTP request has been fully sent, the connection
   432             while True:
   453             while True:
   433                 chunk = self._req.bodyfh.read(32768)
   454                 chunk = self._req.bodyfh.read(32768)
   434                 if not chunk:
   455                 if not chunk:
   435                     break
   456                     break
   436 
   457 
   437         self._startresponse(pycompat.sysstr(self.status), self.headers.items())
   458         write = self._startresponse(pycompat.sysstr(self.status),
       
   459                                     self.headers.items())
       
   460 
   438         if self._bodybytes:
   461         if self._bodybytes:
   439             yield self._bodybytes
   462             yield self._bodybytes
   440         elif self._bodygen:
   463         elif self._bodygen:
   441             for chunk in self._bodygen:
   464             for chunk in self._bodygen:
   442                 yield chunk
   465                 yield chunk
       
   466         elif self._bodywillwrite:
       
   467             self._bodywritefn = write
   443         else:
   468         else:
   444             error.ProgrammingError('do not know how to send body')
   469             error.ProgrammingError('do not know how to send body')
       
   470 
       
   471     def getbodyfile(self):
       
   472         """Obtain a file object like object representing the response body.
       
   473 
       
   474         For this to work, you must call ``setbodywillwrite()`` and then
       
   475         ``sendresponse()`` first. ``sendresponse()`` is a generator and the
       
   476         function won't run to completion unless the generator is advanced. The
       
   477         generator yields not items. The easiest way to consume it is with
       
   478         ``list(res.sendresponse())``, which should resolve to an empty list -
       
   479         ``[]``.
       
   480         """
       
   481         if not self._bodywillwrite:
       
   482             raise error.ProgrammingError('must call setbodywillwrite() first')
       
   483 
       
   484         if not self._started:
       
   485             raise error.ProgrammingError('must call sendresponse() first; did '
       
   486                                          'you remember to consume it since it '
       
   487                                          'is a generator?')
       
   488 
       
   489         assert self._bodywritefn
       
   490         return offsettrackingwriter(self._bodywritefn)
   445 
   491 
   446 class wsgirequest(object):
   492 class wsgirequest(object):
   447     """Higher-level API for a WSGI request.
   493     """Higher-level API for a WSGI request.
   448 
   494 
   449     WSGI applications are invoked with 2 arguments. They are used to
   495     WSGI applications are invoked with 2 arguments. They are used to