Пример #1
0
    def test_tolerant_magic_dict_get_first(self):
        magic_dict = TolerantMagicDict()
        test_list = ["b", "c", "d"]
        for item in test_list:
            magic_dict.add(random.choice(["a", "A"]), item)

        self.assertEqual(magic_dict.get_first("A"), test_list[0])
Пример #2
0
 def test_tolerant_magic_dict_delitem_method(self):
     magic_dict = TolerantMagicDict()
     magic_dict.add("a", "b")
     magic_dict.add("A", "c")
     magic_dict.add("a", "d")
     del magic_dict["a"]
     self.assertNotIn("a", magic_dict)
     self.assertNotIn("A", magic_dict)
Пример #3
0
    def _parse_origin_path(self):
        parsed_url = urllib.parse.urlparse(self.origin_path)

        self._path = parsed_url.path

        link_args = TolerantMagicDict()
        for (query_name, query_value) in urllib.parse.parse_qsl(
         parsed_url.query):
            link_args.add(query_name, query_value)

        self._link_args = link_args
Пример #4
0
    def parse(content_type: str, data: bytes) -> "HTTPMultipartBody":
        """
        Parse HTTP v1 Multipart Body.

        It will raise an Error during the parse period if parse failed.
        """
        body_args = HTTPMultipartBody()
        if not content_type.lower().startswith("multipart/form-data"):
            raise ProtocolError("Unknown content-type.")

        for field in content_type.split(";"):  # Search Boundary
            if field.find("boundary=") == -1:
                continue
            boundary = ensure_bytes(field.split("=")[1])
            if boundary.startswith(b'"') and boundary.endswith(b'"'):
                boundary = boundary[1:-1]
            break
        else:
            raise ProtocolError("Cannot Find Boundary.")
        full_boundary = b"--" + boundary
        body_content = data.split(full_boundary + b"--")[0]

        full_boundary += _CRLF_BYTES_MARK
        splitted_body_content = body_content.split(full_boundary)

        for part in splitted_body_content:
            if not part:
                continue

            initial, content = part.split(_CRLF_BYTES_MARK * 2)
            headers = HTTPHeaders.parse(initial)

            disposition = headers.get_first("content-disposition")
            disposition_list = []
            disposition_dict = TolerantMagicDict()

            for field in disposition.split(";"):  # Split Disposition
                field = field.strip()  # Remove Useless Spaces.
                if field.find("=") == -1:  # This is not a key-value pair.
                    disposition_list.append(field)
                    continue
                key, value = field.split("=")
                if value.startswith('"') and value.endswith('"'):
                    value = value[1:-1]
                disposition_dict.add(key.strip().lower(), value.strip())

            if disposition_list[0] != "form-data":
                raise ProtocolError("Cannot Parse Body.")
                # Mixed form-data will be supported later.
            content = content[:-2]  # Drop CRLF Mark

            if "filename" in disposition_dict.keys():
                body_args.files.add(
                    disposition_dict.get_first("name", ""),
                    HTTPMultipartFileField(
                        fieldname=disposition_dict.get_first("name", ""),
                        filename=disposition_dict.get_first("filename", ""),
                        content=content,
                        content_type=headers.get_first(
                            "content-type", "application/octet-stream"),
                        headers=headers,
                        encoding=headers.get_first("content-transfer-encoding",
                                                   "binary")))
            else:
                try:
                    content = content.decode()
                except UnicodeDecodeError:
                    pass
                body_args.add(disposition_dict.get_first("name", ""), content)

        return body_args
Пример #5
0
 def __init__(self, *args, **kwargs):
     self.files = TolerantMagicDict()
     TolerantMagicDict.__init__(self, *args, **kwargs)
Пример #6
0
class HTTPMultipartBody(TolerantMagicDict):
    """
    HTTPBody class, based on TolerantMagicDict.

    It has not only all the features from TolerantMagicDict, but also
    can parse and make HTTP Body.
    """
    def __init__(self, *args, **kwargs):
        self.files = TolerantMagicDict()
        TolerantMagicDict.__init__(self, *args, **kwargs)

    @staticmethod
    def parse(content_type: str, data: bytes) -> "HTTPMultipartBody":
        """
        Parse HTTP v1 Multipart Body.

        It will raise an Error during the parse period if parse failed.
        """
        body_args = HTTPMultipartBody()
        if not content_type.lower().startswith("multipart/form-data"):
            raise ProtocolError("Unknown content-type.")

        for field in content_type.split(";"):  # Search Boundary
            if field.find("boundary=") == -1:
                continue
            boundary = ensure_bytes(field.split("=")[1])
            if boundary.startswith(b'"') and boundary.endswith(b'"'):
                boundary = boundary[1:-1]
            break
        else:
            raise ProtocolError("Cannot Find Boundary.")
        full_boundary = b"--" + boundary
        body_content = data.split(full_boundary + b"--")[0]

        full_boundary += _CRLF_BYTES_MARK
        splitted_body_content = body_content.split(full_boundary)

        for part in splitted_body_content:
            if not part:
                continue

            initial, content = part.split(_CRLF_BYTES_MARK * 2)
            headers = HTTPHeaders.parse(initial)

            disposition = headers.get_first("content-disposition")
            disposition_list = []
            disposition_dict = TolerantMagicDict()

            for field in disposition.split(";"):  # Split Disposition
                field = field.strip()  # Remove Useless Spaces.
                if field.find("=") == -1:  # This is not a key-value pair.
                    disposition_list.append(field)
                    continue
                key, value = field.split("=")
                if value.startswith('"') and value.endswith('"'):
                    value = value[1:-1]
                disposition_dict.add(key.strip().lower(), value.strip())

            if disposition_list[0] != "form-data":
                raise ProtocolError("Cannot Parse Body.")
                # Mixed form-data will be supported later.
            content = content[:-2]  # Drop CRLF Mark

            if "filename" in disposition_dict.keys():
                body_args.files.add(
                    disposition_dict.get_first("name", ""),
                    HTTPMultipartFileField(
                        fieldname=disposition_dict.get_first("name", ""),
                        filename=disposition_dict.get_first("filename", ""),
                        content=content,
                        content_type=headers.get_first(
                            "content-type", "application/octet-stream"),
                        headers=headers,
                        encoding=headers.get_first("content-transfer-encoding",
                                                   "binary")))
            else:
                try:
                    content = content.decode()
                except UnicodeDecodeError:
                    pass
                body_args.add(disposition_dict.get_first("name", ""), content)

        return body_args

    def assemble(self) -> Tuple[bytes, str]:
        """
        Generate HTTP v1 Body to bytes.

        It will return the body in bytes and the content-type in str.
        """
        body = b""
        boundary = "----------FutureFinityFormBoundary"
        boundary += ensure_str(security.get_random_str(8)).lower()
        content_type = "multipart/form-data; boundary=" + boundary

        full_boundary = b"--" + ensure_bytes(boundary)

        for field_name, field_value in self.items():
            body += full_boundary + _CRLF_BYTES_MARK

            if isinstance(field_value, str):
                body += b"Content-Disposition: form-data; "
                body += ensure_bytes("name=\"%s\"\r\n" % field_name)
                body += _CRLF_BYTES_MARK

                body += ensure_bytes(field_value)
                body += _CRLF_BYTES_MARK
            else:
                raise ProtocolError("Unknown Field Type")

        for file_field in self.files.values():
            body += full_boundary + _CRLF_BYTES_MARK
            body += file_field.assemble()

        body += full_boundary + b"--" + _CRLF_BYTES_MARK
        return body, content_type

    def __str__(self) -> str:
        # Multipart Body is not printable.
        return object.__str__(self)

    def __repr__(self) -> str:
        # Multipart Body is not printable.
        return object.__repr__(self)

    def copy(self) -> "HTTPMultipartBody":
        raise ProtocolError("HTTPMultipartBody is not copyable.")

    __copy__ = copy
Пример #7
0
 def test_tolerant_magic_dict_copy(self):
     magic_dict = TolerantMagicDict()
     magic_dict.add("a", "b")
     magic_dict.add("C", "D")
     copied_magic_dict = magic_dict.copy()
     self.assertEqual(magic_dict, copied_magic_dict)
Пример #8
0
    def test_tolerant_magic_dict_str_method(self):
        magic_dict = TolerantMagicDict()
        magic_dict.add("A", "b")

        self.assertEqual(str(magic_dict), "TolerantMagicDict([('a', 'b')])")
Пример #9
0
 def test_tolerant_magic_dict_getitem_method(self):
     magic_dict = TolerantMagicDict()
     magic_dict.add("a", "b")
     magic_dict.add("a", "c")
     magic_dict.add("a", "d")
     self.assertEqual(magic_dict["A"], "b")
Пример #10
0
 def test_tolerant_magic_dict_setitem_method(self):
     magic_dict = TolerantMagicDict()
     magic_dict["A"] = "b"
     self.assertListEqual(magic_dict.get_list("a"), ["b"])
Пример #11
0
 def test_tolerant_magic_dict_add(self):
     magic_dict = TolerantMagicDict()
     self.assertNotIn("a", magic_dict)
     magic_dict.add("A", "b")
     self.assertIn("a", magic_dict)
     self.assertEqual("b", magic_dict["a"])
Пример #12
0
 def __init__(self, files: typing.List=[HTTPMultipartFileField],
              *args, **kwargs):
     self.files = TolerantMagicDict()
     TolerantMagicDict.__init__(self, *args, **kwargs)