Beispiel #1
0
 def __init__(self, server, loop, sock, address_info):
     self.server = server
     self.loop = loop
     self.sock = sock
     self.sock.setblocking(0)
     self.address_info = address_info
     self.pipe_buffer = PipeBuffer()
     self.watchers = {
         'recv': loop.io(sock.fileno(), EV_READ, self.recv_data),
         'send': loop.io(sock.fileno(), EV_WRITE, self.send_data, 0),
         'timeout': loop.timer(self.IO_TIMEOUT, self.IO_TIMEOUT,
                               self.timeout),
         }
     self.http_parser = HTTPParser()
Beispiel #2
0
    def authorize(self, client_address: tuple[str, int],
                  client_request: HTTPParser) -> Optional[HTTPResponse]:
        path = client_request.request_path
        secret = self.protected_paths[path]["secret"]
        timeout = self.protected_paths[path]["timeout"]
        prefix: str = self.protected_paths[path]["prefix"]
        if secret:
            # This path is token-protected
            if not path.startswith(prefix):
                # Incorrect prefix
                # FIXME: note that something is probably wrong with
                # the configuration here, we should probably log /
                # warn the admin
                return AUTH_FAILURE
            else:
                # Get rid of prefix and slashes
                path = path[len(prefix):].strip("/")
                if path.count("/") < 2:
                    # Not enough components to be a tokenised path
                    return AUTH_FAILURE
                # Split into token, timestamp, and path
                token, timestamp, path = path.split("/", 2)
                # Check the token is valid
                if token != hashlib.md5(secret + "/" + path +
                                        timestamp).hexdigest():
                    # Invalid token
                    return AUTH_FAILURE
                # Check the timeout is not expired, if needed
                if timeout and (int(time.time()) - timeout) > int(
                        timestamp, 16):
                    return AUTH_FAILURE

                # We have to remove the token and timestamp from the original
                # path or else the server won't find the correct handler
                # afterwards
                client_request.request_path = "/".join([prefix, path])
                return AUTH_SUCCESS

        return None
Beispiel #3
0
class InboundClient(object):

    IO_TIMEOUT = 10
    MAX_REQUEST_SIZE = 4096

    def __init__(self, server, loop, sock, address_info):
        self.server = server
        self.loop = loop
        self.sock = sock
        self.sock.setblocking(0)
        self.address_info = address_info
        self.pipe_buffer = PipeBuffer()
        self.watchers = {
            'recv': loop.io(sock.fileno(), EV_READ, self.recv_data),
            'send': loop.io(sock.fileno(), EV_WRITE, self.send_data, 0),
            'timeout': loop.timer(self.IO_TIMEOUT, self.IO_TIMEOUT,
                                  self.timeout),
            }
        self.http_parser = HTTPParser()

    def start(self):
        self.watchers['recv'].start()
        self.watchers['timeout'].start()
        # send is not started yet

    def stop(self):
        for watcher in self.watchers.values():
            watcher.stop()
        self.sock.close()
        self.pipe_buffer.close()
        self.server.remove_client(self)
        self.server.logger.debug('Stopped client: %s', self)

    def recv_data(self, watcher, revents):
        try:
            data = self.sock.recv(self.MAX_REQUEST_SIZE, socket.MSG_PEEK)
            self.http_parser.execute(data)
            if self.http_parser.has_error():
                self.stop()
            elif self.http_parser.is_finished():
                # IO_TIMEOUT seconds at most for the response to come in
                self.watchers['timeout'].reset()
                data = self.sock.recv(self.MAX_REQUEST_SIZE)
                # We're not interested in any more data from this peer
                self.sock.shutdown(socket.SHUT_RD)
                watcher.stop()
                # Ask our server for the response, cached or not
                self.server.proxy(self, self.http_parser, data)
        except:
            self.server.logger.exception('While recv_data():')
            raise

    def start_sending(self):
        self.watchers['send'].start()

    def send_data(self, watcher, revents):
        self.watchers['timeout'].reset()
        self.server.logger.debug('Sending (%d - %d) = %d bytes to %s',
                                 self.pipe_buffer.size, watcher.data,
                                 self.pipe_buffer.size - watcher.data, self)
        watcher.data += splice(self.pipe_buffer.reader, None,
                               self.sock.fileno(), None,
                               self.pipe_buffer.size - watcher.data)[0]
        if watcher.data >= self.pipe_buffer.size:
            self.server.logger.debug('Done sending data to %s', self)
            self.stop()
        self.server.logger.debug('Sent %d bytes to %s', watcher.data, self)

    def timeout(self, watcher, revents):
        self.stop()