def handle_one_request(self):
        self.raw_requestline = self.rfile.readline()
        if not self.raw_requestline:
            self.close_connection = 1
            return
        if not self.parse_request():  # An error code has been sent, just exit
            return

        for prefix in self.server.wsgi_mods:
            if self.path.startswith(prefix):
                logger.debug('before wsgi SimpleHandler')
                try:
                    handler = SimpleHandler(self.rfile, self.wfile,
                                            self.get_stderr(),
                                            self.get_environ(prefix))
                    handler.request_handler = self
                    handler.run(self.server.wsgi_mods[prefix])
                except Exception as e:
                    logger.exception(e)
                logger.debug('after wsgi SimpleHandler')
                return

        mname = 'do_' + self.command
        if not hasattr(self, mname):
            self.send_error(501, "Unsupported method (%r)" % self.command)
            return
        method = getattr(self, mname)
        method()
Esempio n. 2
0
 def close(self):
     try:
         self.request_handler.log_request(
             self.status.split(' ',1)[0], self.bytes_sent
         )
     finally:
         SimpleHandler.close(self)
Esempio n. 3
0
    def close(self):
        # M:
        # S.split([sep [,maxsplit]]) -> list of strings
        # >>> status
        # '200 OK'
        # >>> status.split(' ', 0)
        # ['200 OK']
        # >>> status.split(' ', 1)
        # ['200', 'OK']
        # >>> status.split(' ', 2)
        # ['200', 'OK']

        # In WSGIRequestHandler.handle
        # handler.request_handler = self

        # WSGIRequestHandler.log_request
        # -> BaseHTTPRequestHandler.log_request
        # -> BaseHTTPRequestHandler.log_message
        # -> sys.stderr.write

        # SimpleHandler.close
        # -> BaseHandler.close

        try:
            self.request_handler.log_request(
                self.status.split(' ', 1)[0], self.bytes_sent)
        finally:
            SimpleHandler.close(self)
Esempio n. 4
0
    def finish_response(self):
        """
        Completes the response and performs the following tasks:

        - Remove the `'ws4py.socket'` and `'ws4py.websocket'`
          environ keys.
        - Attach the returned websocket, if any, to the WSGI server
          using its ``link_websocket_to_server`` method.
        """
        # force execution of the result iterator until first actual content
        rest = iter(self.result)
        first = list(itertools.islice(rest, 1))
        self.result = itertools.chain(first, rest)
        # now it's safe to look if environ was modified
        ws = None
        if self.environ:
            self.environ.pop('ws4py.socket', None)
            ws = self.environ.pop('ws4py.websocket', None)

        try:
            SimpleHandler.finish_response(self)
        except:
            if ws:
                ws.close(1011, reason='Something broke')
            raise
        else:
            if ws:
                self.request_handler.server.link_websocket_to_server(ws)
Esempio n. 5
0
    def testPartialWrite(self):
        written = bytearray()

        class PartialWriter:
            def write(self, b):
                partial = b[:7]
                written.extend(partial)
                return len(partial)

            def flush(self):
                pass

        environ = {"SERVER_PROTOCOL": "HTTP/1.0"}
        h = SimpleHandler(BytesIO(), PartialWriter(), sys.stderr, environ)
        msg = "should not do partial writes"
        with self.assertWarnsRegex(DeprecationWarning, msg):
            h.run(hello_app)
        self.assertEqual(
            b"HTTP/1.0 200 OK\r\n"
            b"Content-Type: text/plain\r\n"
            b"Date: Mon, 05 Jun 2006 18:49:54 GMT\r\n"
            b"Content-Length: 13\r\n"
            b"\r\n"
            b"Hello, world!",
            written,
        )
Esempio n. 6
0
    def close(self):
        # M:
        # S.split([sep [,maxsplit]]) -> list of strings
        # >>> status
        # '200 OK'
        # >>> status.split(' ', 0)
        # ['200 OK']
        # >>> status.split(' ', 1)
        # ['200', 'OK']
        # >>> status.split(' ', 2)
        # ['200', 'OK']


        # In WSGIRequestHandler.handle
        # handler.request_handler = self

        # WSGIRequestHandler.log_request 
        # -> BaseHTTPRequestHandler.log_request
        # -> BaseHTTPRequestHandler.log_message
        # -> sys.stderr.write


        # SimpleHandler.close
        # -> BaseHandler.close

        try:
            self.request_handler.log_request(
                self.status.split(' ',1)[0], self.bytes_sent
            )
        finally:
            SimpleHandler.close(self)
Esempio n. 7
0
 def close(self):
     try:
         self.request_handler.log_request(
             self.status.split(' ',1)[0], self.bytes_sent
         )
     finally:
         SimpleHandler.close(self)
Esempio n. 8
0
    def finish_response(self):
        """
        Completes the response and performs the following tasks:

        - Remove the `'ws4py.socket'` and `'ws4py.websocket'`
          environ keys.
        - Attach the returned websocket, if any, to the WSGI server
          using its ``link_websocket_to_server`` method.
        """
        # force execution of the result iterator until first actual content
        rest = iter(self.result)
        first = list(itertools.islice(rest, 1))
        self.result = itertools.chain(first, rest)
        # now it's safe to look if environ was modified
        ws = None
        if self.environ:
            self.environ.pop('ws4py.socket', None)
            ws = self.environ.pop('ws4py.websocket', None)

        try:
            SimpleHandler.finish_response(self)
        except:
            if ws:
                ws.close(1011, reason='Something broke')
            raise
        else:
            if ws:
                self.request_handler.server.link_websocket_to_server(ws)
Esempio n. 9
0
 def setup_environ(self):
     """
     Setup the environ dictionary and add the
     `'ws4py.socket'` key. Its associated value
     is the real socket underlying socket.
     """
     SimpleHandler.setup_environ(self)
     self.environ['ws4py.socket'] = self.environ['wsgi.input']._sock
Esempio n. 10
0
 def setup_environ(self):
     """
     Setup the environ dictionary and add the
     `'ws4py.socket'` key. Its associated value
     is the real socket underlying socket.
     """
     SimpleHandler.setup_environ(self)
     self.environ['ws4py.socket'] = get_connection(self.environ['wsgi.input'])
     self.http_version = self.environ['SERVER_PROTOCOL'].rsplit('/')[-1]
Esempio n. 11
0
 def setup_environ(self):
     """
     Setup the environ dictionary and add the
     `'ws4py.socket'` key. Its associated value
     is the real socket underlying socket.
     """
     SimpleHandler.setup_environ(self)
     self.environ['ws4py.socket'] = get_connection(self.environ['wsgi.input'])
     self.http_version = self.environ['SERVER_PROTOCOL'].rsplit('/')[-1]
Esempio n. 12
0
	def handle(self):
		self.raw_requestline = self.rfile.readline()
		if not self.parse_request(): # An error code has been sent, just exit
			return

		handler = SimpleHandler(
			self.rfile, self.wfile, self.get_stderr(), self.get_environ()
		)
		handler.request_handler = self	  # backpointer for logging
		handler.run(self.server.get_app())
Esempio n. 13
0
 def get(self, path):
     """ get the content of a url as rendered by bottle """
     handler = SimpleHandler(sys.stdin, sys.stdout, sys.stderr, {})
     handler.setup_environ()
     env = handler.environ
     env.update({
         "PATH_INFO": "{0}/{1}".format(self.base_url, path),
         "REQUEST_METHOD": "GET",
     })
     out = b"".join(self.app(env, lambda *args: None))
     return out
Esempio n. 14
0
 def close(self):
     try:
         #self.request_handler.log_request(
         #    self.status.split(' ',1)[0], self.bytes_sent
         #)
         if self.status:
             self.request_handler.log_request(
                 self.status.split(' ', 1)[0], self.bytes_sent)
         else:
             pass
     finally:
         SimpleHandler.close(self)
Esempio n. 15
0
def do_request(env):
    handler = SimpleHandler(environ=env,
                            stdin=env['wsgi.input'],
                            stdout=env['wsgi.input'],
                            stderr=BytesIO())

    return app(env, handler.start_response)[0].decode().strip()
Esempio n. 16
0
    def testClientConnectionTerminations(self):
        environ = {"SERVER_PROTOCOL": "HTTP/1.0"}
        for exception in (
            ConnectionAbortedError,
            BrokenPipeError,
            ConnectionResetError,
        ):
            with self.subTest(exception=exception):
                class AbortingWriter:
                    def write(self, b):
                        raise exception

                stderr = StringIO()
                h = SimpleHandler(BytesIO(), AbortingWriter(), stderr, environ)
                h.run(hello_app)

                self.assertFalse(stderr.getvalue())
Esempio n. 17
0
    def handle(self):
        """Handle a single HTTP request"""
        self.raw_requestline = self.rfile.readline(65537)
        if len(self.raw_requestline) > 65536:
            self.requestline = ''
            self.request_version = ''
            self.command = ''
            self.send_error(414)
            return

        if not self.parse_request():  # An error code has been sent, just exit
            return

        handler = SimpleHandler(
            self.rfile, self.wfile, self.get_stderr(), self.get_environ()
        )
        handler.request_handler = self  # backpointer for logging
        handler.run(self.server.get_app())
Esempio n. 18
0
    def finish_response(self):
        """
        Completes the response and performs the following tasks:

        - Remove the `'ws4py.socket'` and `'ws4py.websocket'`
          environ keys.
        - Attach the returned websocket, if any, to the WSGI server
          using its ``link_websocket_to_server`` method.
        """
        ws = None
        if self.environ:
            self.environ.pop('ws4py.socket', None)
            ws = self.environ.pop('ws4py.websocket', None)

        try:
            SimpleHandler.finish_response(self)
        except:
            if ws:
                ws.close(1011, reason='Something broke')
            raise
        else:
            if ws:
                self.request_handler.server.link_websocket_to_server(ws)
Esempio n. 19
0
    def testDontResetInternalStateOnException(self):
        class CustomException(ValueError):
            pass

        # We are raising CustomException here to trigger an exception
        # during the execution of SimpleHandler.finish_response(), so
        # we can easily test that the internal state of the handler is
        # preserved in case of an exception.
        class AbortingWriter:
            def write(self, b):
                raise CustomException

        stderr = StringIO()
        environ = {"SERVER_PROTOCOL": "HTTP/1.0"}
        h = SimpleHandler(BytesIO(), AbortingWriter(), stderr, environ)
        h.run(hello_app)

        self.assertIn("CustomException", stderr.getvalue())

        # Test that the internal state of the handler is preserved.
        self.assertIsNotNone(h.result)
        self.assertIsNotNone(h.headers)
        self.assertIsNotNone(h.status)
        self.assertIsNotNone(h.environ)
Esempio n. 20
0
    def testPartialWrite(self):
        written = bytearray()

        class PartialWriter:
            def write(self, b):
                partial = b[:7]
                written.extend(partial)
                return len(partial)

            def flush(self):
                pass

        environ = {"SERVER_PROTOCOL": "HTTP/1.0"}
        h = SimpleHandler(BytesIO(), PartialWriter(), sys.stderr, environ)
        msg = "should not do partial writes"
        with self.assertWarnsRegex(DeprecationWarning, msg):
            h.run(hello_app)
        self.assertEqual(
            b"HTTP/1.0 200 OK\r\n"
            b"Content-Type: text/plain\r\n"
            b"Date: Mon, 05 Jun 2006 18:49:54 GMT\r\n"
            b"Content-Length: 13\r\n"
            b"\r\n"
            b"Hello, world!", written)
Esempio n. 21
0
 def cleanup_headers(self):
     SimpleHandler.cleanup_headers(self)
     self.headers["Connection"] = "Close"
Esempio n. 22
0
def test(app, environ={}, form={}, **kw):
    """Print the output of a WSGI app (e.g. for use in doctests)

    Runs `app` as a WSGI application and prints its output.  If an untrapped
    error occurs in `app`, it drops into the ``pdb`` debugger's post-mortem
    debug shell (using ``sys.__stdout__`` if ``sys.stdout`` has been replaced).

    Any keyword arguments are added to the environment used to run `app`.  If
    a keyword argument begins with ``wsgi_``, the ``_`` is replaced with a
    ``.``, so that you can set e.g. ``wsgi.multithread`` using a
    ``wsgi_multithread`` keyword argument.

    If a non-empty `form` dictionary is provided, it is treated as a collection
    of fields for a form ``POST``. The ``REQUEST_METHOD`` will default to
    ``POST``, and the default ``CONTENT_LENGTH``, ``CONTENT_TYPE``, and
    ``wsgi.input`` values will be appropriately set (but can still be
    overridden by explicit keyword arguments or the `environ` argument).

    Any `form` values that are not instances of ``basestring`` are assumed to
    be *sequences* of values, and will result in multiple name/value pairs
    being added to the encoded data sent to the application.

    Any WSGI-required variables that are not specified by `environ`, `form`, or
    keyword arguments, are initialized to default values using the
    ``wsgiref.util.setup_testing_defaults()`` function.
    """

    from wsgiref.handlers import SimpleHandler
    from StringIO import StringIO
    from urllib import quote_plus

    environ = environ.copy()
    for k, v in kw.items():
        if k.startswith('wsgi_'):
            environ[k.replace('_', '.', 1)] = v
        else:
            environ[k] = v

    if form:
        encoded = []
        for k, v in form.items():
            if isinstance(v, basestring):
                v = [v]
            for v in v:
                encoded.append('%s=%s' % (quote_plus(k), quote_plus(v)))
        encoded = '&'.join(encoded)
        environ.setdefault('wsgi.input', StringIO(encoded))
        environ.setdefault('CONTENT_LENGTH', str(len(encoded)))
        environ.setdefault('CONTENT_TYPE', 'application/x-www-form-urlencoded')
        environ.setdefault('REQUEST_METHOD', 'POST')

    setup_testing_defaults(environ)
    stdout = StringIO()
    stderr = environ['wsgi.errors']

    def wrapper(env, start):
        try:
            return app(env, start)
        except:
            stdout = sys.stdout
            try:
                if stdout is not sys.__stdout__:
                    sys.stdout = sys.__stdout__
                import pdb
                pdb.post_mortem(sys.exc_info()[2])
            finally:
                sys.stdout = stdout
            raise

    SimpleHandler(environ['wsgi.input'], stdout, stderr, environ,
                  environ['wsgi.multithread'],
                  environ['wsgi.multiprocess']).run(wrapper)
    print stdout.getvalue().replace('\r\n', '\n')
    if stderr.getvalue():
        print "--- Log Output ---"
        print stderr.getvalue().replace('\r\n', '\n')
Esempio n. 23
0
 def cleanup_headers(self):
     SimpleHandler.cleanup_headers(self)
     self.headers['Connection'] = 'Close'
Esempio n. 24
0
 def __init__(self, stdin, stdout, stderr):
     base_environ = dict(os.environ.items())
     base_environ['SERVER_PROTOCOL'] = 'HTTP/1.0'
     SimpleHandler.__init__(self, stdin, stdout, stderr, base_environ,
                            multithread=False, multiprocess=True)
Esempio n. 25
0
 def handleWSGI(stdin, stderr, stdout, environ):
     handler = SimpleHandler(stdin, stderr, stdout, environ.vars,
                             multithread, multiprocess)
     handler.run_once = run_once
     handler.server_software = environ.vars["SERVER_SOFTWARE"]
     handler.run(app)
Esempio n. 26
0
def mongrel2_handler(application, conn, debug=False):
    """
    Based on :
    https://github.com/berry/Mongrel2-WSGI-Handler/blob/master/wsgi-handler.py

    WSGI handler based on the Python wsgiref SimpleHandler.
    A WSGI application should return a iterable op StringTypes.
    Any encoding must be handled by the WSGI application itself.
    """
    from wsgiref.handlers import SimpleHandler
    try:
        import cStringIO as StringIO
    except:
        import StringIO

    # TODO - this wsgi handler executes the application and renders a page
    # in memory completely before returning it as a response to the client.
    # Thus, it does not "stream" the result back to the client. It should be
    # possible though. The SimpleHandler accepts file-like stream objects. So,
    # it should be just a matter of connecting 0MQ requests/response streams to
    # the SimpleHandler requests and response streams. However, the Python API
    # for Mongrel2 doesn't seem to support file-like stream objects for requests
    # and responses. Unless I have missed something.

    while True:
        if debug:
            print "WAITING FOR REQUEST"

        # receive a request
        req = conn.recv()
        if debug:
            print "REQUEST BODY: %r\n" % req.body

        if req.is_disconnect():
            if debug:
                print "DISCONNECT"
            continue  # effectively ignore the disconnect from the client

        # Set a couple of environment attributes a.k.a. header attributes
        # that are a must according to PEP 333
        environ = req.headers
        environ[
            'SERVER_PROTOCOL'] = 'HTTP/1.1'  # SimpleHandler expects a server_protocol, lets assume it is HTTP 1.1
        environ['REQUEST_METHOD'] = environ['METHOD']
        if ':' in environ['Host']:
            environ['SERVER_NAME'] = environ['Host'].split(':')[0]
            environ['SERVER_PORT'] = environ['Host'].split(':')[1]
        else:
            environ['SERVER_NAME'] = environ['Host']
            environ['SERVER_PORT'] = ''
        environ['SCRIPT_NAME'] = ''  # empty for now
        environ['PATH_INFO'] = urllib.unquote(environ['PATH'])
        if '?' in environ['URI']:
            environ['QUERY_STRING'] = environ['URI'].split('?')[1]
        else:
            environ['QUERY_STRING'] = ''
        if 'Content-Length' in environ:
            environ['CONTENT_LENGTH'] = environ[
                'Content-Length']  # necessary for POST to work with Django
        environ['wsgi.input'] = req.body

        if debug:
            print "ENVIRON: %r\n" % environ

        # SimpleHandler needs file-like stream objects for
        # requests, errors and responses
        reqIO = StringIO.StringIO(req.body)
        errIO = StringIO.StringIO()
        respIO = StringIO.StringIO()

        # execute the application
        handler = SimpleHandler(reqIO,
                                respIO,
                                errIO,
                                environ,
                                multithread=False,
                                multiprocess=False)
        handler.run(application)

        # Get the response and filter out the response (=data) itself,
        # the response headers,
        # the response status code and the response status description
        response = respIO.getvalue()
        response = response.split("\r\n")
        data = response[-1]
        headers = dict([r.split(": ") for r in response[1:-2]])
        code = response[0][9:12]
        status = response[0][13:]

        # strip BOM's from response data
        # Especially the WSGI handler from Django seems to generate them (2 actually, huh?)
        # a BOM isn't really necessary and cause HTML parsing errors in Chrome and Safari
        # See also: http://www.xs4all.nl/~mechiel/projects/bomstrip/
        # Although I still find this a ugly hack, it does work.
        data = data.replace('\xef\xbb\xbf', '')

        # Get the generated errors
        errors = errIO.getvalue()

        # return the response
        if debug:
            print "RESPONSE: %r\n" % response
        if errors:
            if debug:
                print "ERRORS: %r" % errors
            data = "%s\r\n\r\n%s" % (data, errors)
        conn.reply_http(req, data, code=code, status=status, headers=headers)
Esempio n. 27
0
 def cleanup_headers(self):
     SimpleHandler.cleanup_headers(self)
     self.headers['Connection'] = 'Close'
Esempio n. 28
0
def wsgi_server(application, conn):
    '''WSGI handler based on the Python wsgiref SimpleHandler.

    A WSGI application should return a iterable op StringTypes.
    Any encoding must be handled by the WSGI application itself.
    '''

    # TODO - this wsgi handler executes the application and renders a page in
    # memory completely before returning it as a response to the client.
    # Thus, it does not "stream" the result back to the client. It should be
    # possible though. The SimpleHandler accepts file-like stream objects. So,
    # it should be just a matter of connecting 0MQ requests/response streams
    # to the SimpleHandler requests and response streams. However, the Python
    # API for Mongrel2 doesn't seem to support file-like stream objects for
    # requests and responses. Unless I have missed something.

    # setup connection handler
    # sender_id is automatically generated
    # so that each handler instance is uniquely identified

    while True:
        debug("WAITING FOR REQUEST")

        # receive a request
        req = conn.recv()
        if DEBUG:
            debug("REQUEST HEADERS: %r\n" % req.headers)
            debug("REQUEST BODY: %r\n" % req.body)

        if req.is_disconnect():
            print("DISCONNECT")
            continue  # effectively ignore the disconnect from the client

        # json parsing gives us unicode instead of ascii.
        headers = dict((key.encode('ascii'), value.encode('ascii'))
                       for (key, value) in req.headers.items())

        env = {}

        add_request_metavariables(env, headers)
        add_http_variables(env, headers)

        debug("ENVIRON: %r\n" % env)

        # SimpleHandler needs file-like stream objects for
        # requests, errors and reponses
        reqIO = StringIO(req.body)
        errIO = StringIO()
        respIO = StringIO()

        # execute the application
        simple_handler = SimpleHandler(reqIO, respIO, errIO, env,
                                       multithread=False,
                                       multiprocess=False)
        simple_handler.run(application)

        response = respIO.getvalue()
        errors = errIO.getvalue()

        # return the response
        debug("RESPONSE: %r\n" % response)
        if errors:
            debug("ERRORS: %r" % errors)

        conn.reply(req, response)

        # Check if we should close the connection.

        respIO.seek(0)

        protocol = respIO.readline()[:8]
        msg = httplib.HTTPMessage(respIO, 0)
        http_1p1 = protocol == 'HTTP/1.1'

        conn_close = http_1p1 and msg.getheader("Connection") == "close"
        keep_alive = http_1p1 or msg.getheader("Connection") == "Keep-Alive"
        if conn_close or not keep_alive:
            debug("EXPLICITLY CLOSING CONNECTION")
            conn.reply(req, "")
Esempio n. 29
0
	def handle_wsgi_request(stdin, stdout, stderr, environ):
		handler = SimpleHandler(stdin.buffer, stdout.buffer, stderr, environ.vars, environ.server.multithread, environ.server.multiprocess)
		handler.run_once = not environ.server.multiconnection
		handler.server_software = environ.server.software
		handler.run(app)