예제 #1
0
    def __init__( self, stream, address, settings ={} ):
        self.stream = stream
        if self.stream.socket.family not in (socket.AF_INET, socket.AF_INET6):
            # Unix (or other) socket; fake the remote address
            address = ('0.0.0.0', 0)
        self.address = address
        self.pa = query_plugin( None, ISettings, 'pluggdapps' )
        self.settings = settings
        self.no_keep_alive = settings['no_keep_alive']
        self.xheaders = settings['xheaders']

        # Per request attributes
        self.startline = None
        self.headers = None
        self.body = None
        self.receiving = False
        self.responding = False

        # Save stack context here, outside of any request.  This keeps
        # contexts from one request from leaking into the next.
        self._header_callback = sc.wrap( self.on_headers )
        self._write_callback = None
        self._close_callback = None
        self.stream.read_until( b"\r\n\r\n", self._header_callback )

        # on-connection
        self.stream.set_close_callback( self.on_connection_close )
예제 #2
0
    def connect(self, address, callback=None):
        """Connects the socket to a remote address without blocking.

        May only be called if the socket passed to the constructor was
        not previously connected.  The address parameter is in the
        same format as for socket.connect, i.e. a (host, port) tuple.
        If callback is specified, it will be called when the
        connection is completed.

        Note that it is safe to call HTTPIOStream.write while the
        connection is pending, in which case the data will be written
        as soon as the connection is ready.  Calling HTTPIOStream read
        methods before the socket is connected works on some platforms
        but is non-portable.
        """
        self._connecting = True
        try:
            self.socket.connect(address)
        except socket.error as e:
            # In non-blocking mode we expect connect() to raise an
            # exception with EINPROGRESS or EWOULDBLOCK.
            #
            # On freebsd, other errors such as ECONNREFUSED may be
            # returned immediately when attempting to connect to
            # localhost, so handle them the same way as an error
            # reported later in _handle_connect.
            if e.args[0] not in (errno.EINPROGRESS, errno.EWOULDBLOCK):
                #log.warning( 
                #    "Connect error on fd %d: %s", self.socket.fileno(), e )
                self.close()
                return
        self._connect_callback = sc.wrap(callback)
        self._add_io_state(self.ioloop.WRITE)
예제 #3
0
 def add_handler( self, fd, handler, events ):
     """Registers the given handler to receive the given events for fd."""
     self._handlers[fd] = sc.wrap(handler)
     self._evpoll.register( fd, events | self.ERROR )
     if len(self._handlers) > self.poll_threshold :
         #log.warning( 
         #  "Polled descriptors exceeded threshold %r", self.poll_threshold )
         pass
예제 #4
0
    def read_bytes(self, num_bytes, callback, streaming_callback=None):
        """Call callback when we read the given number of bytes.

        If a ``streaming_callback`` is given, it will be called with chunks
        of data as they become available, and the argument to the final
        ``callback`` will be empty.
        """
        self._set_read_callback(callback)
        assert isinstance(num_bytes, int)
        self._read_bytes = num_bytes
        self._streaming_callback = sc.wrap(streaming_callback)
        self._try_inline_read()
예제 #5
0
    def add_timeout( self, deadline, callback ):
        """Calls the given callback at the time deadline from the I/O loop.

        Returns a handle that may be passed to remove_timeout to cancel.

        ``deadline`` may be a number denoting a unix timestamp (as returned
        by ``time.time()`` or a ``datetime.timedelta`` object for a deadline
        relative to the current time.

        Note that it is not safe to call `add_timeout` from other threads.
        Instead, you must use `add_callback` to transfer control to the
        HTTPIOLoop's thread, and then call `add_timeout` from there."""
        timeout = _Timeout( deadline, sc.wrap(callback) )
        heapq.heappush( self._timeouts, timeout )
        return timeout
예제 #6
0
    def read_until_close(self, callback, streaming_callback=None):
        """Reads all data from the socket until it is closed.

        If a ``streaming_callback`` is given, it will be called with chunks
        of data as they become available, and the argument to the final
        ``callback`` will be empty.

        Subject to ``max_buffer_size`` limit if a ``streaming_callback`` is 
        not used.
        """
        self._set_read_callback(callback)
        if self.closed():
            self._run_callback(callback, self._consume(self._read_buffer_size))
            self._read_callback = None
            return
        self._read_until_close = True
        self._streaming_callback = sc.wrap(streaming_callback)
        self._add_io_state(self.ioloop.READ)
예제 #7
0
    def write(self, data, callback=None):
        """Write the given data to this stream.

        If callback is given, we call it when all of the buffered write
        data has been successfully written to the stream. If there was
        previously buffered write data and an old write callback, that
        callback is simply overwritten with this new callback.
        """
        assert isinstance(data, bytes)
        self._check_closed()
        if data:
            # We use bool(_write_buffer) as a proxy for write_buffer_size>0,
            # so never put empty strings in the buffer.
            self._write_buffer.append(data)
        self._write_callback = sc.wrap(callback)
        self._handle_write()
        if self._write_buffer:
            self._add_io_state(self.ioloop.WRITE)
        self._maybe_add_error_listener()
예제 #8
0
    def add_callback( self, callback ):
        """Calls the given callback on the next I/O loop iteration.

        It is safe to call this method from any thread at any time.
        Note that this is the *only* method in HTTPIOLoop that makes this
        guarantee; all other interaction with the HTTPIOLoop must be done
        from that HTTPIOLoop's thread.  add_callback() may be used to transfer
        control from other threads to the HTTPIOLoop's thread.
        """
        with self._callback_lock :
            list_empty = not self._callbacks
            self._callbacks.append(sc.wrap(callback))

        if list_empty and _thread.get_ident() != self._thread_ident:
            # If we're in the HTTPIOLoop's thread, we know it's not currently
            # polling.  If we're not, and we added the first callback to an
            # empty list, we may need to wake it up (it may wake up on its
            # own, but an occasional extra wake is harmless).  Waking
            # up a polling HTTPIOLoop is relatively expensive, so we try to
            # avoid it when we can.
            self._waker.wake()
예제 #9
0
 def write( self, chunk, callback=None ):
     assert self.responding, "Request closed"
     if not self.stream.closed() :
         self._write_callback = sc.wrap( callback )
         self.stream.write( chunk, self.on_write_complete )
예제 #10
0
 def set_close_callback( self, callback ):
     self._close_callback = sc.wrap( callback )
예제 #11
0
 def set_close_callback(self, callback):
     """Call the given callback when the stream is closed."""
     self._close_callback = sc.wrap(callback)