You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					260 lines
				
				7.2 KiB
			
		
		
			
		
	
	
					260 lines
				
				7.2 KiB
			| 
								 
											8 years ago
										 
									 | 
							
								# -*- coding: utf-8 -
							 | 
						||
| 
								 | 
							
								#
							 | 
						||
| 
								 | 
							
								# This file is part of gunicorn released under the MIT license.
							 | 
						||
| 
								 | 
							
								# See the NOTICE for more information.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								from gunicorn.http.errors import (NoMoreData, ChunkMissingTerminator,
							 | 
						||
| 
								 | 
							
								        InvalidChunkSize)
							 | 
						||
| 
								 | 
							
								from gunicorn import six
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class ChunkedReader(object):
							 | 
						||
| 
								 | 
							
								    def __init__(self, req, unreader):
							 | 
						||
| 
								 | 
							
								        self.req = req
							 | 
						||
| 
								 | 
							
								        self.parser = self.parse_chunked(unreader)
							 | 
						||
| 
								 | 
							
								        self.buf = six.BytesIO()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def read(self, size):
							 | 
						||
| 
								 | 
							
								        if not isinstance(size, six.integer_types):
							 | 
						||
| 
								 | 
							
								            raise TypeError("size must be an integral type")
							 | 
						||
| 
								 | 
							
								        if size < 0:
							 | 
						||
| 
								 | 
							
								            raise ValueError("Size must be positive.")
							 | 
						||
| 
								 | 
							
								        if size == 0:
							 | 
						||
| 
								 | 
							
								            return b""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if self.parser:
							 | 
						||
| 
								 | 
							
								            while self.buf.tell() < size:
							 | 
						||
| 
								 | 
							
								                try:
							 | 
						||
| 
								 | 
							
								                    self.buf.write(six.next(self.parser))
							 | 
						||
| 
								 | 
							
								                except StopIteration:
							 | 
						||
| 
								 | 
							
								                    self.parser = None
							 | 
						||
| 
								 | 
							
								                    break
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        data = self.buf.getvalue()
							 | 
						||
| 
								 | 
							
								        ret, rest = data[:size], data[size:]
							 | 
						||
| 
								 | 
							
								        self.buf = six.BytesIO()
							 | 
						||
| 
								 | 
							
								        self.buf.write(rest)
							 | 
						||
| 
								 | 
							
								        return ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def parse_trailers(self, unreader, data):
							 | 
						||
| 
								 | 
							
								        buf = six.BytesIO()
							 | 
						||
| 
								 | 
							
								        buf.write(data)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        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:
							 | 
						||
| 
								 | 
							
								            unreader.unread(buf.getvalue()[2:])
							 | 
						||
| 
								 | 
							
								            return b""
							 | 
						||
| 
								 | 
							
								        self.req.trailers = self.req.parse_headers(buf.getvalue()[:idx])
							 | 
						||
| 
								 | 
							
								        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 NoMoreData()
							 | 
						||
| 
								 | 
							
								            yield rest[:size]
							 | 
						||
| 
								 | 
							
								            # Remove \r\n after chunk
							 | 
						||
| 
								 | 
							
								            rest = rest[size:]
							 | 
						||
| 
								 | 
							
								            while len(rest) < 2:
							 | 
						||
| 
								 | 
							
								                rest += unreader.read()
							 | 
						||
| 
								 | 
							
								            if rest[:2] != b'\r\n':
							 | 
						||
| 
								 | 
							
								                raise ChunkMissingTerminator(rest[:2])
							 | 
						||
| 
								 | 
							
								            (size, rest) = self.parse_chunk_size(unreader, data=rest[2:])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def parse_chunk_size(self, unreader, data=None):
							 | 
						||
| 
								 | 
							
								        buf = six.BytesIO()
							 | 
						||
| 
								 | 
							
								        if data is not None:
							 | 
						||
| 
								 | 
							
								            buf.write(data)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        idx = buf.getvalue().find(b"\r\n")
							 | 
						||
| 
								 | 
							
								        while idx < 0:
							 | 
						||
| 
								 | 
							
								            self.get_data(unreader, buf)
							 | 
						||
| 
								 | 
							
								            idx = buf.getvalue().find(b"\r\n")
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        data = buf.getvalue()
							 | 
						||
| 
								 | 
							
								        line, rest_chunk = data[:idx], data[idx + 2:]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        chunk_size = line.split(b";", 1)[0].strip()
							 | 
						||
| 
								 | 
							
								        try:
							 | 
						||
| 
								 | 
							
								            chunk_size = int(chunk_size, 16)
							 | 
						||
| 
								 | 
							
								        except ValueError:
							 | 
						||
| 
								 | 
							
								            raise InvalidChunkSize(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 NoMoreData()
							 | 
						||
| 
								 | 
							
								        buf.write(data)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class LengthReader(object):
							 | 
						||
| 
								 | 
							
								    def __init__(self, unreader, length):
							 | 
						||
| 
								 | 
							
								        self.unreader = unreader
							 | 
						||
| 
								 | 
							
								        self.length = length
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def read(self, size):
							 | 
						||
| 
								 | 
							
								        if not isinstance(size, six.integer_types):
							 | 
						||
| 
								 | 
							
								            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 b""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        buf = six.BytesIO()
							 | 
						||
| 
								 | 
							
								        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
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class EOFReader(object):
							 | 
						||
| 
								 | 
							
								    def __init__(self, unreader):
							 | 
						||
| 
								 | 
							
								        self.unreader = unreader
							 | 
						||
| 
								 | 
							
								        self.buf = six.BytesIO()
							 | 
						||
| 
								 | 
							
								        self.finished = False
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def read(self, size):
							 | 
						||
| 
								 | 
							
								        if not isinstance(size, six.integer_types):
							 | 
						||
| 
								 | 
							
								            raise TypeError("size must be an integral type")
							 | 
						||
| 
								 | 
							
								        if size < 0:
							 | 
						||
| 
								 | 
							
								            raise ValueError("Size must be positive.")
							 | 
						||
| 
								 | 
							
								        if size == 0:
							 | 
						||
| 
								 | 
							
								            return b""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if self.finished:
							 | 
						||
| 
								 | 
							
								            data = self.buf.getvalue()
							 | 
						||
| 
								 | 
							
								            ret, rest = data[:size], data[size:]
							 | 
						||
| 
								 | 
							
								            self.buf = six.BytesIO()
							 | 
						||
| 
								 | 
							
								            self.buf.write(rest)
							 | 
						||
| 
								 | 
							
								            return ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        data = self.unreader.read()
							 | 
						||
| 
								 | 
							
								        while data:
							 | 
						||
| 
								 | 
							
								            self.buf.write(data)
							 | 
						||
| 
								 | 
							
								            if self.buf.tell() > size:
							 | 
						||
| 
								 | 
							
								                break
							 | 
						||
| 
								 | 
							
								            data = self.unreader.read()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if not data:
							 | 
						||
| 
								 | 
							
								            self.finished = True
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        data = self.buf.getvalue()
							 | 
						||
| 
								 | 
							
								        ret, rest = data[:size], data[size:]
							 | 
						||
| 
								 | 
							
								        self.buf = six.BytesIO()
							 | 
						||
| 
								 | 
							
								        self.buf.write(rest)
							 | 
						||
| 
								 | 
							
								        return ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class Body(object):
							 | 
						||
| 
								 | 
							
								    def __init__(self, reader):
							 | 
						||
| 
								 | 
							
								        self.reader = reader
							 | 
						||
| 
								 | 
							
								        self.buf = six.BytesIO()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __iter__(self):
							 | 
						||
| 
								 | 
							
								        return self
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __next__(self):
							 | 
						||
| 
								 | 
							
								        ret = self.readline()
							 | 
						||
| 
								 | 
							
								        if not ret:
							 | 
						||
| 
								 | 
							
								            raise StopIteration()
							 | 
						||
| 
								 | 
							
								        return ret
							 | 
						||
| 
								 | 
							
								    next = __next__
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def getsize(self, size):
							 | 
						||
| 
								 | 
							
								        if size is None:
							 | 
						||
| 
								 | 
							
								            return six.MAXSIZE
							 | 
						||
| 
								 | 
							
								        elif not isinstance(size, six.integer_types):
							 | 
						||
| 
								 | 
							
								            raise TypeError("size must be an integral type")
							 | 
						||
| 
								 | 
							
								        elif size < 0:
							 | 
						||
| 
								 | 
							
								            return six.MAXSIZE
							 | 
						||
| 
								 | 
							
								        return size
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def read(self, size=None):
							 | 
						||
| 
								 | 
							
								        size = self.getsize(size)
							 | 
						||
| 
								 | 
							
								        if size == 0:
							 | 
						||
| 
								 | 
							
								            return b""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        if size < self.buf.tell():
							 | 
						||
| 
								 | 
							
								            data = self.buf.getvalue()
							 | 
						||
| 
								 | 
							
								            ret, rest = data[:size], data[size:]
							 | 
						||
| 
								 | 
							
								            self.buf = six.BytesIO()
							 | 
						||
| 
								 | 
							
								            self.buf.write(rest)
							 | 
						||
| 
								 | 
							
								            return ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        while size > self.buf.tell():
							 | 
						||
| 
								 | 
							
								            data = self.reader.read(1024)
							 | 
						||
| 
								 | 
							
								            if not data:
							 | 
						||
| 
								 | 
							
								                break
							 | 
						||
| 
								 | 
							
								            self.buf.write(data)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        data = self.buf.getvalue()
							 | 
						||
| 
								 | 
							
								        ret, rest = data[:size], data[size:]
							 | 
						||
| 
								 | 
							
								        self.buf = six.BytesIO()
							 | 
						||
| 
								 | 
							
								        self.buf.write(rest)
							 | 
						||
| 
								 | 
							
								        return ret
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def readline(self, size=None):
							 | 
						||
| 
								 | 
							
								        size = self.getsize(size)
							 | 
						||
| 
								 | 
							
								        if size == 0:
							 | 
						||
| 
								 | 
							
								            return b""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        data = self.buf.getvalue()
							 | 
						||
| 
								 | 
							
								        self.buf = six.BytesIO()
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        ret = []
							 | 
						||
| 
								 | 
							
								        while 1:
							 | 
						||
| 
								 | 
							
								            idx = data.find(b"\n", 0, size)
							 | 
						||
| 
								 | 
							
								            idx = idx + 1 if idx >= 0 else size if len(data) >= size else 0
							 | 
						||
| 
								 | 
							
								            if idx:
							 | 
						||
| 
								 | 
							
								                ret.append(data[:idx])
							 | 
						||
| 
								 | 
							
								                self.buf.write(data[idx:])
							 | 
						||
| 
								 | 
							
								                break
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            ret.append(data)
							 | 
						||
| 
								 | 
							
								            size -= len(data)
							 | 
						||
| 
								 | 
							
								            data = self.reader.read(min(1024, size))
							 | 
						||
| 
								 | 
							
								            if not data:
							 | 
						||
| 
								 | 
							
								                break
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        return b"".join(ret)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def readlines(self, size=None):
							 | 
						||
| 
								 | 
							
								        ret = []
							 | 
						||
| 
								 | 
							
								        data = self.read()
							 | 
						||
| 
								 | 
							
								        while data:
							 | 
						||
| 
								 | 
							
								            pos = data.find(b"\n")
							 | 
						||
| 
								 | 
							
								            if pos < 0:
							 | 
						||
| 
								 | 
							
								                ret.append(data)
							 | 
						||
| 
								 | 
							
								                data = b""
							 | 
						||
| 
								 | 
							
								            else:
							 | 
						||
| 
								 | 
							
								                line, data = data[:pos + 1], data[pos + 1:]
							 | 
						||
| 
								 | 
							
								                ret.append(line)
							 | 
						||
| 
								 | 
							
								        return ret
							 |