Skip to content

Instantly share code, notes, and snippets.

@androiddrew
Created May 19, 2018 17:29
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save androiddrew/18b92fc1aa6869552a796f834867d500 to your computer and use it in GitHub Desktop.
Save androiddrew/18b92fc1aa6869552a796f834867d500 to your computer and use it in GitHub Desktop.
Re-implementing the Multi-part Form Parser in APIStar >= 0.4
import io
import typing
from apistar import Component, http
from apistar.server.wsgi import WSGIEnviron
from werkzeug.datastructures import ImmutableMultiDict
from werkzeug.formparser import FormDataParser
from werkzeug.http import parse_options_header
from werkzeug.wsgi import get_input_stream
RequestStream = typing.NewType('RequestStream', io.BufferedIOBase)
MultiPartForm = typing.NewType('MultiPartForm', ImmutableMultiDict)
class RequestStreamComponent(Component):
def resolve(self, environ: WSGIEnviron) -> RequestStream:
return get_input_stream(environ)
class MultiPartParser(Component):
media_type = 'multipart/form-data'
def get_content_length(self, headers: http.Headers) -> typing.Optional[int]:
content_length = headers.get('Content-Length')
if content_length is not None:
try:
return max(0, int(content_length))
except (ValueError, TypeError):
pass
return None
def get_mimetype_and_options(self, headers: http.Headers) -> typing.Tuple[str, dict]:
content_type = headers.get('Content-Type')
if content_type:
return parse_options_header(content_type)
return '', {}
def resolve(self, headers: http.Headers, stream: RequestStream) -> MultiPartForm:
mimetype, options = self.get_mimetype_and_options(headers)
content_length = self.get_content_length(headers)
parser = FormDataParser()
stream, form, files = parser.parse(stream, mimetype, content_length, options)
return ImmutableMultiDict(list(form.items()) + list(files.items()))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment