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 __contains__(self, name): return name in self.__headers 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