예제 #1
0
    def __call__(self, out, buf):
        try:
            # read http message (response line + headers)
            try:
                raw_data = yield from buf.readuntil(
                    b'\r\n\r\n', self.max_line_size + self.max_headers)
            except errors.LineLimitExceededParserError as exc:
                raise errors.LineTooLong(exc.limit) from None

            lines = raw_data.decode('ascii',
                                    'surrogateescape').splitlines(True)

            line = lines[0]
            try:
                version, status = line.split(None, 1)
            except ValueError:
                raise errors.BadStatusLine(line) from None
            else:
                try:
                    status, reason = status.split(None, 1)
                except ValueError:
                    reason = ''

            # version
            match = VERSRE.match(version)
            if match is None:
                raise errors.BadStatusLine(line)
            version = (int(match.group(1)), int(match.group(2)))

            # The status code is a three-digit number
            try:
                status = int(status)
            except ValueError:
                raise errors.BadStatusLine(line) from None

            if status < 100 or status > 999:
                raise errors.BadStatusLine(line)

            # read headers
            headers, close, compression = self.parse_headers(lines)

            if close is None:
                close = version <= (1, 0)

            out.feed_data(
                RawResponseMessage(version, status, reason.strip(), headers,
                                   close, compression))
            out.feed_eof()
        except aiohttp.EofStream:
            # Presumably, the server closed the connection before
            # sending a valid response.
            raise errors.ClientConnectionError(
                'Can not read status line') from None
예제 #2
0
파일: protocol.py 프로젝트: jmcarp/aiohttp
    def __call__(self, out, buf):
        # read http message (response line + headers)
        try:
            raw_data = yield from buf.readuntil(
                b'\r\n\r\n', self.max_line_size + self.max_headers)
        except errors.LineLimitExceededParserError as exc:
            raise errors.LineTooLong(exc.limit) from None

        lines = raw_data.decode('ascii', 'surrogateescape').split('\r\n')

        line = lines[0]
        try:
            version, status = line.split(None, 1)
        except ValueError:
            raise errors.BadStatusLine(line) from None
        else:
            try:
                status, reason = status.split(None, 1)
            except ValueError:
                reason = ''

        # version
        match = VERSRE.match(version)
        if match is None:
            raise errors.BadStatusLine(line)
        version = HttpVersion(int(match.group(1)), int(match.group(2)))

        # The status code is a three-digit number
        try:
            status = int(status)
        except ValueError:
            raise errors.BadStatusLine(line) from None

        if status < 100 or status > 999:
            raise errors.BadStatusLine(line)

        # read headers
        headers, close, compression = self.parse_headers(lines)

        if close is None:
            close = version <= HttpVersion10

        out.feed_data(
            RawResponseMessage(version, status, reason.strip(), headers, close,
                               compression))
        out.feed_eof()
예제 #3
0
    def __call__(self, out, buf):
        # read http message (request line + headers)
        try:
            raw_data = yield from buf.readuntil(b'\r\n\r\n', self.max_headers)
        except errors.LineLimitExceededParserError as exc:
            raise errors.LineTooLong(exc.limit) from None

        lines = raw_data.decode('ascii', 'surrogateescape').split('\r\n')

        # request line
        line = lines[0]
        try:
            method, path, version = line.split(None, 2)
        except ValueError:
            raise errors.BadStatusLine(line) from None

        # method
        method = method.upper()
        if not METHRE.match(method):
            raise errors.BadStatusLine(method)

        # version
        match = VERSRE.match(version)
        if match is None:
            raise errors.BadStatusLine(version)
        version = HttpVersion(int(match.group(1)), int(match.group(2)))

        # read headers
        headers, close, compression = self.parse_headers(lines)
        if version <= HttpVersion10:
            close = True
        elif close is None:
            close = False

        out.feed_data(
            RawRequestMessage(method, path, version, headers, close,
                              compression))
        out.feed_eof()
예제 #4
0
    def parse_headers(self, lines):
        """Parses RFC2822 headers from a stream.

        Line continuations are supported. Returns list of header name
        and value pairs. Header name is in upper case.
        """
        close_conn = None
        encoding = None
        headers = []

        lines_idx = 1
        line = lines[1]

        while line:
            header_length = len(line)

            # Parse initial header name : value pair.
            try:
                name, value = line.split(':', 1)
            except ValueError:
                raise ValueError('Invalid header: {}'.format(line)) from None

            name = name.strip(' \t').upper()
            if HDRRE.search(name):
                raise ValueError('Invalid header name: {}'.format(name))

            # next line
            lines_idx += 1
            line = lines[lines_idx]

            # consume continuation lines
            continuation = line and line[0] in CONTINUATION

            if continuation:
                value = [value]
                while continuation:
                    header_length += len(line)
                    if header_length > self.max_field_size:
                        raise errors.LineTooLong(
                            'limit request headers fields size')
                    value.append(line)

                    # next line
                    lines_idx += 1
                    line = lines[lines_idx]
                    continuation = line[0] in CONTINUATION
                value = '\r\n'.join(value)
            else:
                if header_length > self.max_field_size:
                    raise errors.LineTooLong(
                        'limit request headers fields size')

            value = value.strip()

            # keep-alive and encoding
            if name == 'CONNECTION':
                v = value.lower()
                if v == 'close':
                    close_conn = True
                elif v == 'keep-alive':
                    close_conn = False
            elif name == 'CONTENT-ENCODING':
                enc = value.lower()
                if enc in ('gzip', 'deflate'):
                    encoding = enc

            headers.append((name, value))

        return multidict.MultiDict(headers), close_conn, encoding