Ejemplo n.º 1
0
 def connection_ready(sock, fd, events):
     while True:
         try:
             connection, address = sock.accept()
         
         except socket.error:
             exc = exception().exception
             if exc.args[0] not in (errno.EWOULDBLOCK, errno.EAGAIN):
                 raise
             
             return
         
         connection.setblocking(0)
         stream = iostream.IOStream(connection)
         
         def read_request(stream, request):
             def write_chunk(stream, chunks_written=0):
                 if chunks_written == nchunks:
                     stream.close()
                     return
                 
                 stream.write(chunk, functools.partial(write_chunk, stream, chunks_written+1))
             
             stream.write(b"HTTP/1.0 200 OK\r\nContent-Length: %s\r\n\r\n" % (clength, ), functools.partial(write_chunk, stream))
         
         stream.read_bytes(82, functools.partial(read_request, stream))
Ejemplo n.º 2
0
    def __call__(self, request):
        """Parse the JSON body and dispatch."""

        if request.method != 'POST':
            raise HTTPMethodNotAllowed("POST required.")

        try:
            json = loads(request.body)
        except ValueError:
            raise HTTPBadRequest("Unable to parse JSON request.")

        for key in ('method', 'id'):
            if key not in json:
                raise HTTPBadRequest("Missing required JSON-RPC value: " + key)

        method = json['method']
        args = json.get('params', [])
        id_ = json['id']

        if not isinstance(args, list):
            raise HTTPBadRequest("Bad parameters, must be a list: {0!r}".format(args))

        log.debug("JSON-RPC Call: %s%r", method, args)

        func, parent = route(self, method, JSONRPCController)

        log.debug("Found method: %r", func)

        try:
            callback = getattr(parent, '__before__', None)
            if callback:
                args = callback(*args)

            result = func(*args)
            error = None

            callback = getattr(parent, '__after__', None)
            if callback:
                result = callback(result, *args)
        except:
            log.exception("Error calling RPC mechanism.")
            exc = exception()

            web.core.response.status_int = 500

            result = None
            error = dict(
                    name='JSONRPCError',
                    code=100,
                    message=str(exc.exception),
                    error="Not disclosed." if not web.core.config.get('debug', False) else exc.formatted
                )
        else:
            log.debug("Got result: %r", result)

        if id_ is not None:
            web.core.response.content_type = 'application/json'
            return 'json:', dict(result=result, error=error, id=id_)
Ejemplo n.º 3
0
 def read(self):
     """Emulate a file descriptors read method"""
     try:
         return self.reader.recv(1)
     except socket.error:
         ex = exception().exception
         if ex.args[0] == errno.EWOULDBLOCK:
             raise IOError
         raise
Ejemplo n.º 4
0
    def test_exception(self):
        try:
            1/0
        
        except:
            exc = compat.exception()
            
            self.assertEquals(exc.name, 'ZeroDivisionError')
            self.assertEquals(exc.cls, ZeroDivisionError)
            self.assertTrue('division or modulo by zero' in exc.args[0])
        
        try:
            raise Exception('foo', 1)

        except:
            exc = compat.exception()

            self.assertEquals(exc.name, 'Exception')
            self.assertEquals(exc.cls, Exception)
            self.assertEquals(exc.args, ('foo', 1))
Ejemplo n.º 5
0
    def test_exception(self):
        try:
            1 / 0

        except:
            exc = compat.exception()

            self.assertEquals(exc.name, 'ZeroDivisionError')
            self.assertEquals(exc.cls, ZeroDivisionError)
            self.assertTrue('division or modulo by zero' in exc.args[0])

        try:
            raise Exception('foo', 1)

        except:
            exc = compat.exception()

            self.assertEquals(exc.name, 'Exception')
            self.assertEquals(exc.cls, Exception)
            self.assertEquals(exc.args, ('foo', 1))
Ejemplo n.º 6
0
    def __init__(self):
        # Based on Zope async.py: http://svn.zope.org/zc.ngi/trunk/src/zc/ngi/async.py

        self.writer = socket.socket()
        # Disable buffering -- pulling the trigger sends 1 byte,
        # and we want that sent immediately, to wake up ASAP.
        self.writer.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)

        count = 0
        while 1:
            count += 1
            # Bind to a local port; for efficiency, let the OS pick
            # a free port for us.
            # Unfortunately, stress tests showed that we may not
            # be able to connect to that port ("Address already in
            # use") despite that the OS picked it.  This appears
            # to be a race bug in the Windows socket implementation.
            # So we loop until a connect() succeeds (almost always
            # on the first try).  See the long thread at
            # http://mail.zope.org/pipermail/zope/2005-July/160433.html
            # for hideous details.
            a = socket.socket()
            a.bind(("127.0.0.1", 0))
            connect_address = a.getsockname()  # assigned (host, port) pair
            a.listen(1)
            try:
                self.writer.connect(connect_address)
                break    # success
            except socket.error:
                detail = exception().exception
                if detail[0] != errno.WSAEADDRINUSE:
                    # "Address already in use" is the only error
                    # I've seen on two WinXP Pro SP2 boxes, under
                    # Pythons 2.3.5 and 2.4.1.
                    raise
                # (10048, 'Address already in use')
                # assert count <= 2 # never triggered in Tim's tests
                if count >= 10:  # I've never seen it go above 2
                    a.close()
                    self.writer.close()
                    raise socket.error("Cannot bind trigger!")
                # Close `a` and try again.  Note:  I originally put a short
                # sleep() here, but it didn't appear to help or hurt.
                a.close()

        self.reader, addr = a.accept()
        self.reader.setblocking(0)
        self.writer.setblocking(0)
        a.close()
        self.reader_fd = self.reader.fileno()
Ejemplo n.º 7
0
 def _do_ssl_handshake(self):
     # Based on code from test_ssl.py in the python stdlib
     try:
         self.socket.do_handshake()
     except ssl.SSLError:
         err = exception().exception
         if err.args[0] == ssl.SSL_ERROR_WANT_READ:
             self._add_io_state(self.io_loop.READ)
             return
         elif err.args[0] == ssl.SSL_ERROR_WANT_WRITE:
             self._add_io_state(self.io_loop.WRITE)
             return
         elif err.args[0] in (ssl.SSL_ERROR_EOF, ssl.SSL_ERROR_ZERO_RETURN):
             return self.close()
         elif err.args[0] == ssl.SSL_ERROR_SSL:
             self.close()
         raise
     except socket.error:
         err = exception().exception
         if err.args[0] == errno.ECONNABORTED:
             return self.close()
     else:
         self._ssl_accepting = False
Ejemplo n.º 8
0
    def _accept(self, sock, fd, events):
        # TODO: Move this into the Server class.
        # Work that needs to be done can be issued within the real accept method.

        try:
            connection, address = sock.accept()

        except socket.error:
            exc = exception().exception

            if exc.args[0] not in (errno.EWOULDBLOCK, errno.EAGAIN):
                raise

            return

        client = self.client(connection, io_loop=self.testing or None)

        self.accept(client)
Ejemplo n.º 9
0
 def _handle_read(self):
     try:
         chunk = self.socket.recv(self.read_chunk_size)
     
     except socket.error:
         e = exception().exception
         if e.args[0] in (errno.EWOULDBLOCK, errno.EAGAIN):
             return
         
         else:
             log.warning("Read error on %d: %s", self.socket.fileno(), e)
             self.close()
             return
     
     if not chunk:
         self.close()
         return
     
     self._read_buffer += chunk
     rblen = len(self._read_buffer)
     
     if rblen >= self.max_buffer_size:
         log.error("Connection %d reached maximum read buffer size.", self.socket.fileno())
         self.close()
         return
     
     if self._read_bytes:
         if rblen >= self._read_bytes:
             num_bytes = self._read_bytes
             callback = self._read_callback
             self._read_callback = None
             self._read_bytes = None
             self._run_callback(callback, self._consume(num_bytes))
     
     elif self._read_delimiter:
         loc = self._read_buffer.find(self._read_delimiter)
         
         if loc != -1:
             callback = self._read_callback
             delimiter_len = len(self._read_delimiter)
             self._read_callback = None
             self._read_delimiter = None
             self._run_callback(callback, self._consume(loc + delimiter_len))
Ejemplo n.º 10
0
 def __call__(self, environ, start_response=None):
     req = Request(environ)
     req.response = Response(req)
     
     try:
         resp = self.call(req, *self.args, **self.kw)
     
     except exc.HTTPException:
         resp = exception().exception
     
     if resp is None:
         return req.response(environ, start_response)
     
     # Handle None
     # Handle byte string
     # Handle unicode string
     # Handle file handle
     # Handle iterable
     # Handle exception
     # Handle response
     
     return resp(environ, start_response)
Ejemplo n.º 11
0
 def _handle_write(self):
     while self._write_buffer:
         try:
             num_bytes = self.socket.send(self._write_buffer[:128 * 1024])
             self._write_buffer = self._write_buffer[num_bytes:]
         
         except socket.error:
             e = exception().exception
             
             if e.args[0] in (errno.EWOULDBLOCK, errno.EAGAIN):
                 break
             
             else:
                 log.warning("Write error on %d: %s", self.socket.fileno(), e)
                 self.close()
                 return
     
     # TODO: Allow multiple callbacks.
     if not self._write_buffer and self._write_callback:
         callback = self._write_callback
         self._write_callback = None
         self._run_callback(callback)
Ejemplo n.º 12
0
 def start(self):
     """Starts the I/O loop.
     
     The loop will run until one of the I/O handlers calls stop(), which
     will make the loop stop after the current event iteration completes.
     """
     log.debug("IOLoop reactor starting.")
     
     if self._stopped:
         self._stopped = False
         return
     
     self._running = True
     
     while True:
         # log.debug("Starting reactor tick.")
         
         # Never use an infinite timeout here - it can stall epoll
         poll_timeout = 0.2
         
         # Prevent IO event starvation by delaying new callbacks
         # to the next iteration of the event loop.
         callbacks = list(self._callbacks)
         for callback in callbacks:
             # A callback can add or remove other callbacks
             if callback in self._callbacks:
                 self._callbacks.remove(callback)
                 self._run_callback(callback)
         
         if self._callbacks:
             # log.debug("Callbacks waiting, reducing timeout.")
             poll_timeout = 0.0
         
         if self._timeouts:
             # log.debug("Timeouts pending.")
             
             now = time()
             while self._timeouts and self._timeouts[0].deadline <= now:
                 timeout = self._timeouts.pop(0)
                 self._run_callback(timeout.callback)
             
             if self._timeouts:
                 milliseconds = self._timeouts[0].deadline - now
                 poll_timeout = min(milliseconds, poll_timeout)
         
         if not self._running:
             log.debug("IOLoop reactor exiting.")
             break
         
         if self._blocking_log_threshold is not None:
             # clear alarm so it doesn't fire while poll is waiting for events.
             signal.setitimer(signal.ITIMER_REAL, 0, 0)
         
         try:
             event_pairs = self._impl.poll(poll_timeout)
         
         except Exception:
             exc = exception().exception
             # Depending on python version and IOLoop implementation,
             # different exception types may be thrown and there are
             # two ways EINTR might be signaled:
             # * e.errno == errno.EINTR
             # * e.args is like (errno.EINTR, 'Interrupted system call')
             # TODO: Determine if this can be simplified to:
             # if e.args == (4, "Interrupted system call"):
             if (getattr(exc, 'errno', None) == errno.EINTR or
                 (isinstance(getattr(exc, 'args'), tuple) and
                  len(exc.args) == 2 and exc.args[0] == errno.EINTR)):
                 log.warning("Interrupted system call", exc_info=True)
                 continue
             
             else:
                 log.exception("Error polling.")
                 raise
         
         if self._blocking_log_threshold is not None:
             signal.setitimer(signal.ITIMER_REAL, self._blocking_log_threshold, 0)
         
         # Pop one fd at a time from the set of pending fds and run
         # its handler. Since that handler may perform actions on
         # other file descriptors, there may be reentrant calls to
         # this IOLoop that update self._events
         self._events.update(event_pairs)
         while self._events:
             fd, events = self._events.popitem()
             
             try:
                 self._handlers[fd](fd, events)
             
             except (KeyboardInterrupt, SystemExit):
                 raise
             
             except (OSError, IOError):
                 exc = exception().exception
                 if exc.args[0] == errno.EPIPE:
                     # Happens when the client closes the connection
                     pass
                 
                 else:
                     log.error("Exception in I/O handler for fd %d", fd, exc_info=True)
             
             except:
                 log.error("Exception in I/O handler for fd %d", fd, exc_info=True)
     
     # reset the stopped flag so another start/stop pair can be issued
     self._stopped = False
     
     if self._blocking_log_threshold is not None:
         signal.setitimer(signal.ITIMER_REAL, 0, 0)