コード例 #1
0
ファイル: test_http.py プロジェクト: polyfemos/atavism
 def test_002(self):
     cases = [
         ([b'Hello World!'], 12, 'text/plain', 'Hello World!'),
         ([b'{"origin"', b': "127.0.0.1"}'], 23, 'application/json', {'origin': '127.0.0.1'}),
     ]
     for c in cases:
         ct = Content(data=c[0][0], content_length=c[1], content_type=c[2])
         self.assertEqual(ct.finished, True if len(c[0]) == 1 else False)
         self.assertEqual(len(ct), len(c[0][0]))
         for n in range(1, len(c[0])):
             ct.read_content(c[0][n])
         self.assertTrue(ct.finished)
         self.assertEqual(ct.decoded_content(), c[3])
コード例 #2
0
ファイル: test_http.py プロジェクト: Mesteriis/atavism
 def test_002(self):
     cases = [
         ([b'Hello World!'], 12, 'text/plain', 'Hello World!'),
         ([b'{"origin"', b': "127.0.0.1"}'], 23, 'application/json', {
             'origin': '127.0.0.1'
         }),
     ]
     for c in cases:
         ct = Content(data=c[0][0], content_sz=c[1], content_type=c[2])
         self.assertEqual(ct.finished, True if len(c[0]) == 1 else False)
         self.assertEqual(len(ct), len(c[0][0]))
         for n in range(1, len(c[0])):
             ct.read_content(c[0][n])
         self.assertTrue(ct.finished)
         self.assertEqual(ct.decoded_content(), c[3])
コード例 #3
0
ファイル: base.py プロジェクト: polyfemos/atavism
class BaseHttp(object):
    """ Base class for other HTTP transactional classes. This class tries
        to provide the core functionality for various classes.
    """
    RANGE_re = re.compile(r"([0-9]+)?-([0-9]+)?,?")

    def __init__(self):
        self.path = ''
        self.http = 'HTTP/1.1'

        self.header = Headers()
        self._content = Content()

        self.close_connection = False
        self.headers_sent = False
        self.headers_only = False
        self.ranges = []

    def __len__(self):
        return len(self._content)

    def get(self, key, default=None):
        return self.header.get(key, default)

    def add_header(self, key, val):
        self.header.add_header(key, val)

    def add_headers(self, hdr_dict):
        self.header.add_headers(hdr_dict)

    ### Connection Information
    def send_complete(self):
        if self.headers_sent and self._content.finished:
            return True
        return False

    def next_output(self):
        data = b''
        if not self.headers_sent:
            data += str(self.header).encode()
            self.headers_sent = True
        if self.headers_only:
            self._content.finished = True
            return data

        data += self._content.next(len(data))
        return data

    # Ranges
    def parse_ranges(self, key):
        """ Parse a range request into individual byte ranges. """
        self.ranges = []
        poss = self.get(key)
        if poss is None or poss.lower() == 'none':
            return
        if not poss.startswith("bytes="):
            return
        matches = self.RANGE_re.findall(poss[6:])
        for m in matches:
            self.ranges.append(Range(m))

    def add_range(self, start=None, end=None):
        if start is None and end is None:
            return
        self.ranges.append(Range((start, end)))

    def has_ranges(self):
        return len(self.ranges) > 0

    def set_ranges(self, ranges):
        self.ranges = ranges

    ### Content

    @property
    def content(self):
        return self._content.content

    def decoded_content(self):
        return self._content.decoded_content()

    def set_content(self, cntnt_obj):
        self._content = cntnt_obj

    def read_content(self, cntnt):
        r = 0
        if not self.header.finished:
            r = self.header.read_content(cntnt)
            if self.header.finished:
                self._update_content()
        r += self._content.read_content(cntnt[r:])
        return r

    def _update_content(self):
        self._content.content_type = self.header.get('content-type')
        self._content.content_length = self.header.get('content-length')

        rngs = self.get('range')
        if rngs is not None:
            self.parse_ranges('range')

        te = self.get('transfer-encoding')
        if te is not None and te.lower() == 'chunked':
            self._content.chunked = True

        ce = self.get('content-encoding')
        if ce is not None and ce.lower() != 'identity':
            self._content.set_compression(ce)

        conn = self.get('connection')
        if conn is not None and conn.lower() == 'close':
            self.close_connection = True

    def set_compression(self, method):
        self._content.set_compression(method)

    def _complete(self):
        """ Record that the creation of a response/request is complete. """
        self._content.finished = True
        self._content.compress()
        self.header.add_headers(self._content.header_lines())

    def is_complete(self):
        """ Has the entire input stream been seen?
        :return: True or False
        """
        if self.header.finished is False:
            return False
        return self._content.finished

    def add_content(self, cntnt):
        self._content.add_content(cntnt)