109 lines
2.5 KiB
Python
109 lines
2.5 KiB
Python
|
import io
|
||
|
import traceback
|
||
|
|
||
|
from hserver.mimeheaders import MIMEHeaders
|
||
|
|
||
|
class MIMEException(Exception):
|
||
|
pass
|
||
|
|
||
|
class ContentSizeLimitException(MIMEException):
|
||
|
pass
|
||
|
|
||
|
class MIME:
|
||
|
|
||
|
def __init__(self,fp=None,source=None,limit=10485760,defaultlength=-1,parent=None):
|
||
|
if (not fp is None):
|
||
|
self.__fp = fp
|
||
|
elif (not source is None):
|
||
|
self.__fp = io.BytesIO(source)
|
||
|
|
||
|
self.__parent = parent
|
||
|
self.__limit = limit
|
||
|
self.__defaultlength = defaultlength
|
||
|
|
||
|
self.__body = None
|
||
|
self.__headers = None
|
||
|
self.__multipart = False
|
||
|
self.__parts = []
|
||
|
|
||
|
self.__parse()
|
||
|
|
||
|
def __getitem__(self,name):
|
||
|
if self.__multipart:
|
||
|
for p in self.__parts:
|
||
|
if not p.name() is None:
|
||
|
return p.name()
|
||
|
raise KeyError()
|
||
|
|
||
|
def headers(self):
|
||
|
return self.__headers
|
||
|
|
||
|
def multipart(self):
|
||
|
return self.__multipart
|
||
|
|
||
|
def parts(self):
|
||
|
return self.__parts
|
||
|
|
||
|
def name(self):
|
||
|
pp = self.__headers.parameters("CONTENT-DISPOSITION")
|
||
|
if (not pp is None) and ("name" in pp.keys()):
|
||
|
return pp["name"]
|
||
|
return None
|
||
|
|
||
|
def body(self):
|
||
|
return self.__body
|
||
|
|
||
|
def __parse(self):
|
||
|
self.__headers = MIMEHeaders( fp=self.__fp )
|
||
|
l = int(self.__headers.value("CONTENT-LENGTH",self.__defaultlength))
|
||
|
if (l > self.__limit):
|
||
|
raise ContentSizeLimitException(size=l,limit=self.__limit)
|
||
|
|
||
|
self.__body = self.__fp.read(l)
|
||
|
|
||
|
if (not "filename" in self.__headers.parameters("CONTENT-DISPOSITION")) and (self.__headers.value("CONTENT-TYPE").upper() == "TEXT/PLAIN"):
|
||
|
if ("charset" in self.__headers.parameters("CONTENT-TYPE")):
|
||
|
charset = self.__headers.parameters("CONTENT-TYPE")["charset"]
|
||
|
else:
|
||
|
# charset = "us-ascii"
|
||
|
charset = "utf-8"
|
||
|
self.__body = str(self.__body,charset)
|
||
|
|
||
|
type = self.__headers.value("CONTENT-TYPE","/").split("/")[0].upper()
|
||
|
if (type == "MULTIPART"):
|
||
|
try:
|
||
|
self.__parsemultipart()
|
||
|
except Exception as ex:
|
||
|
traceback.print_exception(type(ex),ex,ex.__traceback__)
|
||
|
|
||
|
def __parsemultipart(self):
|
||
|
"""
|
||
|
p = start of preceeding boundary
|
||
|
c = end of preceeding boundary
|
||
|
e = start of following boundary
|
||
|
"""
|
||
|
self.__multipart = True
|
||
|
|
||
|
boundary = b'--' + bytes(self.__headers.get("CONTENT-TYPE").parameters()["boundary"],"iso-8859-1")
|
||
|
|
||
|
p = self.__body.find(boundary)
|
||
|
c = p + len(boundary) + 2
|
||
|
|
||
|
boundary = b'\r\n' + boundary
|
||
|
|
||
|
while (True):
|
||
|
e = self.__body.find(boundary,c)
|
||
|
|
||
|
if (e < 0):
|
||
|
return
|
||
|
else:
|
||
|
self.__parts.append(MIME(source=self.__body[c : e],parent=self))
|
||
|
|
||
|
p = e
|
||
|
c = p + len(boundary) + 2
|
||
|
|
||
|
if (self.__body[c - 2 : c] == b"--"):
|
||
|
return
|
||
|
|
||
|
|
||
|
|