Exemple #1
0
 def parse_trailers(self, unreader, data):
     buf = BufferIO()
     buf.write(data)
     
     idx = buf.getvalue().find("\r\n\r\n")
     done = buf.getvalue()[:2] == "\r\n"
     while idx < 0 and not done:
         self.get_data(unreader, buf)
         idx = buf.getvalue().find("\r\n\r\n")
         done = buf.getvalue()[:2] == "\r\n"
     if done:
         unreader.unread(buf.getvalue()[2:])
         return ""
     self.req.trailers = self.req.parse_headers(buf.getvalue()[:idx])
     if self.trailer_handler is not None:
         self.trailer_handler(self.req.trailers)
     unreader.unread(buf.getvalue()[idx+4:])
Exemple #2
0
    def parse_chunk_size(self, unreader, data=None):
        buf = BufferIO()
        if data is not None:
            buf.write(data)

        idx = buf.getvalue().find("\r\n")
        while idx < 0:
            self.get_data(unreader, buf)
            idx = buf.getvalue().find("\r\n")

        data = buf.getvalue()
        line, rest_chunk = data[:idx], data[idx + 2:]

        chunk_size = line.split(";", 1)[0].strip()
        try:
            chunk_size = int(chunk_size, 16)
        except ValueError:
            raise ParseError("Invalid chunk size: %r" % chunk_size)

        if chunk_size == 0:
            try:
                self.parse_trailers(unreader, rest_chunk)
            except NoMoreData:
                pass
            return (0, None)
        return (chunk_size, rest_chunk)
Exemple #3
0
    def parse_chunk_size(self, unreader, data=None):
        buf = BufferIO()
        if data is not None:
            buf.write(data)

        idx = buf.getvalue().find("\r\n")
        while idx < 0:
            self.get_data(unreader, buf)
            idx = buf.getvalue().find("\r\n")

        data = buf.getvalue()
        line, rest_chunk = data[:idx], data[idx+2:]
    
        chunk_size = line.split(";", 1)[0].strip()
        try:
            chunk_size = int(chunk_size, 16)
        except ValueError:
            raise ParseError("Invalid chunk size: %r" % chunk_size)

        if chunk_size == 0:
            try:
                self.parse_trailers(unreader, rest_chunk)
            except NoMoreData:
                pass
            return (0, None)
        return (chunk_size, rest_chunk)
Exemple #4
0
 def read(self, size):
     if not isinstance(size, (int, long)):
         raise TypeError("size must be an integral type")
     
     size = min(self.length, size)
     if size < 0:
         raise ValueError("Size must be positive.")
     if size == 0:
         return ""
     
     buf = BufferIO()
     data = self.unreader.read()
     while data:
         buf.write(data)
         if buf.tell() >= size:
             break
         data = self.unreader.read()
     
     buf = buf.getvalue()
     ret, rest = buf[:size], buf[size:]
     self.unreader.unread(rest)
     self.length -= size
     return ret
Exemple #5
0
    def read(self, size):
        if not isinstance(size, (int, long)):
            raise TypeError("size must be an integral type")

        size = min(self.length, size)
        if size < 0:
            raise ValueError("Size must be positive.")
        if size == 0:
            return ""

        buf = BufferIO()
        data = self.unreader.read()
        while data:
            buf.write(data)
            if buf.tell() >= size:
                break
            data = self.unreader.read()

        buf = buf.getvalue()
        ret, rest = buf[:size], buf[size:]
        self.unreader.unread(rest)
        self.length -= size
        return ret
Exemple #6
0
class Unreader(object):
    """\
    An Unreader is an object that can have previously read
    bytes pushed back into it to be re-read. This helps so
    that we don't have to read bytes one at a time.
    """
    def __init__(self, sock, max_chunk=8192):
        self.sock = sock
        self.max_chunk = max_chunk
        self.buf = BufferIO()

    def _data(self):
        return self.sock.recv(self.max_chunk)

    def unread(self, data):
        self.buf.seek(0, os.SEEK_END)
        self.buf.write(data)

    def read(self, size=None):
        if size is not None and not isinstance(size, (int, long)):
            raise TypeError("size parameter must be an int or long.")
        if size == 0:
            return ""
        if size is None or size < 0:
            size = None

        self.buf.seek(0, os.SEEK_END)

        if size is None and self.buf.tell():
            ret = self.buf.getvalue()
            self.buf.truncate(0)
            self.buf.seek(0)
            return ret
        if size is None:
            return self._data()

        while self.buf.tell() < size:
            data = self._data()
            if not len(data):
                ret = self.buf.getvalue()
                self.buf.truncate(0)
                self.buf.seek(0)
                return ret
            self.buf.write(data)

        data = self.buf.getvalue()
        self.buf.truncate(0)
        self.buf.seek(0)
        self.buf.write(data[size:])
        return data[:size]
Exemple #7
0
 def __init__(self, sock, max_chunk=8192):
     self.sock = sock
     self.max_chunk = max_chunk
     self.buf = BufferIO()
Exemple #8
0
class Body(object):
    """\
    This class implements the necessary methods specified by
    WSGI v1.0.
    """
    def __init__(self, reader):
        self.reader = reader
        self.buf = BufferIO()
        self.pre_read = None

    def set_pre_read(self, func):
        if not callable(func):
            raise TypeError("func must be callable.")
        self.pre_read = func

    def set_trailers_handler(self, func):
        self.reader.set_trailers_handler(func)

    def __iter__(self):
        return self

    def next(self):
        ret = self.readline()
        if not ret:
            raise StopIteration()
        return ret

    def discard(self):
        """\
        If processing a request failed to read all the available
        body data we need to discard anything before processing
        the nest request.
        """
        data = self.read(8192)
        while data:
            data = self.read(8192)

    def read(self, size=None):
        size = self._get_size(size)
        if size == 0:
            return ""

        if size < self.buf.tell():
            data = self.buf.getvalue()
            ret, rest = data[:size], data[size:]
            self.buf.truncate(0)
            self.buf.seek(0)
            self.buf.write(rest)
            return ret

        while size > self.buf.tell():
            data = self._get_data()
            if not len(data):
                break
            self.buf.write(data)

        data = self.buf.getvalue()
        ret, rest = data[:size], data[size:]
        self.buf.truncate(0)
        self.buf.seek(0)
        self.buf.write(rest)
        return ret

    def readline(self, size=None):
        size = self._get_size(size)
        if size == 0:
            return ""

        idx = self.buf.getvalue().find("\n")
        while idx < 0:
            data = self._get_data(1024)
            if not len(data):
                break
            self.buf.write(data)
            idx = self.buf.getvalue().find("\n")
            if size < self.buf.tell():
                break

        # If we didn't find it, and we got here, we've
        # exceeded size or run out of data.
        if idx < 0:
            rlen = min(size, self.buf.tell())
        else:
            rlen = idx + 1

            # If rlen is beyond our size threshold, trim back
            if rlen > size:
                rlen = size

        data = self.buf.getvalue()
        ret, rest = data[:rlen], data[rlen:]

        self.buf.truncate(0)
        self.buf.seek(0)
        self.buf.write(rest)
        return ret

    def readlines(self, size=None):
        ret = []
        data = self.read()
        while len(data):
            pos = data.find("\n")
            if pos < 0:
                ret.append(data)
                data = ""
            else:
                line, data = data[:pos + 1], data[pos + 1:]
                ret.append(line)
        return ret

    def _get_size(self, size):
        """\
        Correct a size hint passed in to a read request. This
        attempts to mimic the behaviour of a file object.
        """
        if size is None:
            return sys.maxint
        elif not isinstance(size, (int, long)):
            raise TypeError("Size must be an integral type")
        elif size < 0:
            return sys.maxint
        return size

    def _get_data(self):
        if self.pre_read is not None:
            self.pre_read()
            self.pre_read = None
        return self.reader.read(1024)
Exemple #9
0
 def __init__(self, reader):
     self.reader = reader
     self.buf = BufferIO()
     self.pre_read = None
Exemple #10
0
    def parse_trailers(self, unreader, data):
        buf = BufferIO()
        buf.write(data)

        idx = buf.getvalue().find("\r\n\r\n")
        done = buf.getvalue()[:2] == "\r\n"
        while idx < 0 and not done:
            self.get_data(unreader, buf)
            idx = buf.getvalue().find("\r\n\r\n")
            done = buf.getvalue()[:2] == "\r\n"
        if done:
            unreader.unread(buf.getvalue()[2:])
            return ""
        self.req.trailers = self.req.parse_headers(buf.getvalue()[:idx])
        if self.trailer_handler is not None:
            self.trailer_handler(self.req.trailers)
        unreader.unread(buf.getvalue()[idx + 4:])
Exemple #11
0
class Body(object):
    """\
    This class implements the necessary methods specified by
    WSGI v1.0.
    """
    def __init__(self, reader):
        self.reader = reader
        self.buf = BufferIO()
        self.pre_read = None
    
    def set_pre_read(self, func):
        if not callable(func):
            raise TypeError("func must be callable.")
        self.pre_read = func

    def set_trailers_handler(self, func):
        self.reader.set_trailers_handler(func)

    def __iter__(self):
        return self
    
    def next(self):
        ret = self.readline()
        if not ret:
            raise StopIteration()
        return ret

    def discard(self):
        """\
        If processing a request failed to read all the available
        body data we need to discard anything before processing
        the nest request.
        """
        data = self.read(8192)
        while data:
            data = self.read(8192)
    
    def read(self, size=None):
        size = self._get_size(size)
        if size == 0:
            return ""

        if size < self.buf.tell():
            data = self.buf.getvalue()
            ret, rest = data[:size], data[size:]
            self.buf.truncate(0)
            self.buf.seek(0)
            self.buf.write(rest)
            return ret

        while size > self.buf.tell():
            data = self._get_data()
            if not len(data):
                break
            self.buf.write(data)

        data = self.buf.getvalue()
        ret, rest = data[:size], data[size:]
        self.buf.truncate(0)
        self.buf.seek(0)
        self.buf.write(rest)
        return ret
    
    def readline(self, size=None):
        size = self._get_size(size)
        if size == 0:
            return ""
        
        idx = self.buf.getvalue().find("\n")
        while idx < 0:
            data = self._get_data(1024)
            if not len(data):
                break
            self.buf.write(data)
            idx = self.buf.getvalue().find("\n")
            if size < self.buf.tell():
                break
        
        # If we didn't find it, and we got here, we've
        # exceeded size or run out of data.
        if idx < 0:
            rlen = min(size, self.buf.tell())
        else:
            rlen = idx + 1

            # If rlen is beyond our size threshold, trim back
            if rlen > size:
                rlen = size
        
        data = self.buf.getvalue()
        ret, rest = data[:rlen], data[rlen:]
        
        self.buf.truncate(0)
        self.buf.seek(0)
        self.buf.write(rest)
        return ret
    
    def readlines(self, size=None):
        ret = []
        data = self.read()
        while len(data):
            pos = data.find("\n")
            if pos < 0:
                ret.append(data)
                data = ""
            else:
                line, data = data[:pos+1], data[pos+1:]
                ret.append(line)
        return ret

    def _get_size(self, size):
        """\
        Correct a size hint passed in to a read request. This
        attempts to mimic the behaviour of a file object.
        """
        if size is None:
            return sys.maxint
        elif not isinstance(size, (int, long)):
            raise TypeError("Size must be an integral type")
        elif size < 0:
            return sys.maxint
        return size

    def _get_data(self):
        if self.pre_read is not None:
            self.pre_read()
            self.pre_read = None
        return self.reader.read(1024)
Exemple #12
0
 def __init__(self, unreader, req):
     self.parser = self.parse_chunked(unreader)
     self.req = req
     self.buf = BufferIO()
     self.trailer_handler = None
Exemple #13
0
 def __init__(self, unreader, req):
     self.parser = self.parse_chunked(unreader)
     self.req = req
     self.buf = BufferIO()
     self.trailer_handler = None
Exemple #14
0
    def parse(self, unreader):
        buf = BufferIO()

        self._get_data(unreader, buf, stop=True)

        # Request line
        idx = buf.getvalue().find(b("\r\n"))
        while idx < 0:
            self._get_data(unreader, buf)
            idx = buf.getvalue().find(b("\r\n"))
        self.parse_request_line(buf.getvalue()[:idx])
        rest = buf.getvalue()[idx + 2:]  # Skip \r\n
        buf.truncate(0)
        buf.seek(0)
        buf.write(rest)

        # Headers
        idx = buf.getvalue().find(b("\r\n\r\n"))
        done = buf.getvalue()[:2] == b("\r\n")
        while idx < 0 and not done:
            self._get_data(unreader, buf)
            idx = buf.getvalue().find(b("\r\n\r\n"))
            done = buf.getvalue()[:2] == b("\r\n")
        if done:
            self.unreader.unread(buf.getvalue()[2:])
            return b("")
        self.headers = self.parse_headers(buf.getvalue()[:idx])

        ret = buf.getvalue()[idx + 4:]
        buf.truncate(0)
        buf.seek(0)
        return ret
Exemple #15
0
    def parse(self, unreader):
        buf = BufferIO()

        self._get_data(unreader, buf, stop=True)
        
        # Request line
        idx = buf.getvalue().find(b("\r\n"))
        while idx < 0:
            self._get_data(unreader, buf)
            idx = buf.getvalue().find(b("\r\n"))
        self.parse_request_line(buf.getvalue()[:idx])
        rest = buf.getvalue()[idx+2:] # Skip \r\n
        buf.truncate(0)
        buf.seek(0)
        buf.write(rest)
        
        # Headers
        idx = buf.getvalue().find(b("\r\n\r\n"))
        done = buf.getvalue()[:2] == b("\r\n")
        while idx < 0 and not done:
            self._get_data(unreader, buf)
            idx = buf.getvalue().find(b("\r\n\r\n"))
            done = buf.getvalue()[:2] == b("\r\n")
        if done:
            self.unreader.unread(buf.getvalue()[2:])
            return b("")
        self.headers = self.parse_headers(buf.getvalue()[:idx])

        ret = buf.getvalue()[idx+4:]
        buf.truncate(0)
        buf.seek(0)
        return ret
Exemple #16
0
 def __init__(self, sock, max_chunk=8192):
     self.sock = sock
     self.max_chunk = max_chunk
     self.buf = BufferIO()
Exemple #17
0
class Unreader(object):
    """\
    An Unreader is an object that can have previously read
    bytes pushed back into it to be re-read. This helps so
    that we don't have to read bytes one at a time.
    """
    def __init__(self, sock, max_chunk=8192):
        self.sock = sock
        self.max_chunk = max_chunk
        self.buf = BufferIO()
    
    def _data(self):
        return self.sock.recv(self.max_chunk)
    
    def unread(self, data):
        self.buf.seek(0, os.SEEK_END)
        self.buf.write(data)
    
    def read(self, size=None):
        if size is not None and not isinstance(size, (int, long)):
            raise TypeError("size parameter must be an int or long.")
        if size == 0:
            return ""
        if size is None or size < 0:
            size = None

        self.buf.seek(0, os.SEEK_END)

        if size is None and self.buf.tell():
            ret = self.buf.getvalue()
            self.buf.truncate(0)
            self.buf.seek(0)
            return ret
        if size is None:
            return self._data()

        while self.buf.tell() < size:
            data = self._data()
            if not len(data):
                ret = self.buf.getvalue()
                self.buf.truncate(0)
                self.buf.seek(0)
                return ret
            self.buf.write(data)

        data = self.buf.getvalue()
        self.buf.truncate(0)
        self.buf.seek(0)
        self.buf.write(data[size:])
        return data[:size]
Exemple #18
0
 def __init__(self, reader):
     self.reader = reader
     self.buf = BufferIO()
     self.pre_read = None
Exemple #19
0
class ChunkedReader(object):
    """\
    A class that is capable of decoding an HTTP request body
    that uses chunked transfer encoding. Also attempts to
    parse any trailers that may be present setting them on
    the request instance.
    """
    def __init__(self, unreader, req):
        self.parser = self.parse_chunked(unreader)
        self.req = req
        self.buf = BufferIO()
        self.trailer_handler = None

    def set_trailer_handler(self, func):
        if not callable(func):
            raise TypeError("Trailer handler must be callable.")
        self.trailer_handler = func

    def read(self, size):
        if not isinstance(size, (int, long)):
            raise TypeError("size must be an integral type")
        if size <= 0:
            raise ValueError("Size must be positive.")
        if size == 0:
            return ""

        if self.parser:
            while self.buf.tell() < size:
                try:
                    self.buf.write(self.parser.next())
                except StopIteration:
                    self.parser = None
                    break

        data = self.buf.getvalue()
        ret, rest = data[:size], data[size:]
        self.buf.truncate(0)
        self.buf.seek(0)
        self.buf.write(rest)
        return ret

    def parse_trailers(self, unreader, data):
        buf = BufferIO()
        buf.write(data)

        idx = buf.getvalue().find("\r\n\r\n")
        done = buf.getvalue()[:2] == "\r\n"
        while idx < 0 and not done:
            self.get_data(unreader, buf)
            idx = buf.getvalue().find("\r\n\r\n")
            done = buf.getvalue()[:2] == "\r\n"
        if done:
            unreader.unread(buf.getvalue()[2:])
            return ""
        self.req.trailers = self.req.parse_headers(buf.getvalue()[:idx])
        if self.trailer_handler is not None:
            self.trailer_handler(self.req.trailers)
        unreader.unread(buf.getvalue()[idx + 4:])

    def parse_chunked(self, unreader):
        (size, rest) = self.parse_chunk_size(unreader)
        while size > 0:
            while size > len(rest):
                size -= len(rest)
                yield rest
                rest = unreader.read()
                if not rest:
                    raise ParseError("Client disconected during chunk.")
            yield rest[:size]
            # Remove \r\n after chunk
            rest = rest[size:]
            while len(rest) < 2:
                rest += unreader.read()
            if rest[:2] != '\r\n':
                raise ParseError("Chunk is missing the \\r\\n terminator.")
            (size, rest) = self.parse_chunk_size(unreader, data=rest[2:])

    def parse_chunk_size(self, unreader, data=None):
        buf = BufferIO()
        if data is not None:
            buf.write(data)

        idx = buf.getvalue().find("\r\n")
        while idx < 0:
            self.get_data(unreader, buf)
            idx = buf.getvalue().find("\r\n")

        data = buf.getvalue()
        line, rest_chunk = data[:idx], data[idx + 2:]

        chunk_size = line.split(";", 1)[0].strip()
        try:
            chunk_size = int(chunk_size, 16)
        except ValueError:
            raise ParseError("Invalid chunk size: %r" % chunk_size)

        if chunk_size == 0:
            try:
                self.parse_trailers(unreader, rest_chunk)
            except NoMoreData:
                pass
            return (0, None)
        return (chunk_size, rest_chunk)

    def get_data(self, unreader, buf):
        data = unreader.read()
        if not data:
            raise ParseError("Client disconnected while reading chunked body.")
            raise NoMoreData()
        buf.write(data)
Exemple #20
0
class ChunkedReader(object):
    """\
    A class that is capable of decoding an HTTP request body
    that uses chunked transfer encoding. Also attempts to
    parse any trailers that may be present setting them on
    the request instance.
    """
    def __init__(self, unreader, req):
        self.parser = self.parse_chunked(unreader)
        self.req = req
        self.buf = BufferIO()
        self.trailer_handler = None

    def set_trailer_handler(self, func):
        if not callable(func):
            raise TypeError("Trailer handler must be callable.")
        self.trailer_handler = func

    def read(self, size):
        if not isinstance(size, (int, long)):
            raise TypeError("size must be an integral type")
        if size <= 0:
            raise ValueError("Size must be positive.")
        if size == 0:
            return ""

        if self.parser:
            while self.buf.tell() < size:
                try:
                    self.buf.write(self.parser.next())
                except StopIteration:
                    self.parser = None
                    break

        data = self.buf.getvalue()
        ret, rest = data[:size], data[size:]
        self.buf.truncate(0)
        self.buf.seek(0)
        self.buf.write(rest)
        return ret
    
    def parse_trailers(self, unreader, data):
        buf = BufferIO()
        buf.write(data)
        
        idx = buf.getvalue().find("\r\n\r\n")
        done = buf.getvalue()[:2] == "\r\n"
        while idx < 0 and not done:
            self.get_data(unreader, buf)
            idx = buf.getvalue().find("\r\n\r\n")
            done = buf.getvalue()[:2] == "\r\n"
        if done:
            unreader.unread(buf.getvalue()[2:])
            return ""
        self.req.trailers = self.req.parse_headers(buf.getvalue()[:idx])
        if self.trailer_handler is not None:
            self.trailer_handler(self.req.trailers)
        unreader.unread(buf.getvalue()[idx+4:])

    def parse_chunked(self, unreader):
        (size, rest) = self.parse_chunk_size(unreader)
        while size > 0:
            while size > len(rest):
                size -= len(rest)
                yield rest
                rest = unreader.read()
                if not rest:
                    raise ParseError("Client disconected during chunk.")
            yield rest[:size]
            # Remove \r\n after chunk
            rest = rest[size:]
            while len(rest) < 2:
                rest += unreader.read()
            if rest[:2] != '\r\n':
                raise ParseError("Chunk is missing the \\r\\n terminator.")
            (size, rest) = self.parse_chunk_size(unreader, data=rest[2:]) 

    def parse_chunk_size(self, unreader, data=None):
        buf = BufferIO()
        if data is not None:
            buf.write(data)

        idx = buf.getvalue().find("\r\n")
        while idx < 0:
            self.get_data(unreader, buf)
            idx = buf.getvalue().find("\r\n")

        data = buf.getvalue()
        line, rest_chunk = data[:idx], data[idx+2:]
    
        chunk_size = line.split(";", 1)[0].strip()
        try:
            chunk_size = int(chunk_size, 16)
        except ValueError:
            raise ParseError("Invalid chunk size: %r" % chunk_size)

        if chunk_size == 0:
            try:
                self.parse_trailers(unreader, rest_chunk)
            except NoMoreData:
                pass
            return (0, None)
        return (chunk_size, rest_chunk)

    def get_data(self, unreader, buf):
        data = unreader.read()
        if not data:
            raise ParseError("Client disconnected while reading chunked body.")
            raise NoMoreData()
        buf.write(data)