def __call__(self, env, start_response):
        """
        Main hook into the WSGI paste.deploy filter/app pipeline.

        :param env: The WSGI environment dict.
        :param start_response: The WSGI start_response hook.
        :returns: Response as per WSGI.
        """
        if env["REQUEST_METHOD"] == "POST":
            try:
                content_type, attrs = parse_content_disposition(env.get("CONTENT_TYPE") or "")
                if content_type == "multipart/form-data" and "boundary" in attrs:
                    http_user_agent = "%s FormPost" % (env.get("HTTP_USER_AGENT", ""))
                    env["HTTP_USER_AGENT"] = http_user_agent.strip()
                    status, headers, body = self._translate_form(env, attrs["boundary"])
                    start_response(status, headers)
                    return [body]
            except MimeInvalid:
                body = "FormPost: invalid starting boundary"
                start_response("400 Bad Request", (("Content-Type", "text/plain"), ("Content-Length", str(len(body)))))
                return [body]
            except (FormInvalid, EOFError) as err:
                body = "FormPost: %s" % err
                start_response("400 Bad Request", (("Content-Type", "text/plain"), ("Content-Length", str(len(body)))))
                return [body]
            except FormUnauthorized as err:
                message = "FormPost: %s" % str(err).title()
                return HTTPUnauthorized(body=message)(env, start_response)
        return self.app(env, start_response)
Exemplo n.º 2
0
    def __call__(self, env, start_response):
        """
        Main hook into the WSGI paste.deploy filter/app pipeline.

        :param env: The WSGI environment dict.
        :param start_response: The WSGI start_response hook.
        :returns: Response as per WSGI.
        """
        if env['REQUEST_METHOD'] == 'POST':
            try:
                content_type, attrs = \
                    parse_content_disposition(env.get('CONTENT_TYPE') or '')
                if content_type == 'multipart/form-data' and \
                        'boundary' in attrs:
                    http_user_agent = "%s FormPost" % (env.get(
                        'HTTP_USER_AGENT', ''))
                    env['HTTP_USER_AGENT'] = http_user_agent.strip()
                    status, headers, body = self._translate_form(
                        env, attrs['boundary'])
                    start_response(status, headers)
                    return [body]
            except (FormInvalid, MimeInvalid, EOFError) as err:
                body = 'FormPost: %s' % err
                start_response('400 Bad Request',
                               (('Content-Type', 'text/plain'),
                                ('Content-Length', str(len(body)))))
                return [body]
            except FormUnauthorized as err:
                message = 'FormPost: %s' % str(err).title()
                return HTTPUnauthorized(body=message)(env, start_response)
        return self.app(env, start_response)
Exemplo n.º 3
0
    def __call__(self, env, start_response):
        """
        Main hook into the WSGI paste.deploy filter/app pipeline.

        :param env: The WSGI environment dict.
        :param start_response: The WSGI start_response hook.
        :returns: Response as per WSGI.
        """
        if env['REQUEST_METHOD'] == 'POST':
            try:
                content_type, attrs = \
                    parse_content_disposition(env.get('CONTENT_TYPE') or '')
                if content_type == 'multipart/form-data' and \
                        'boundary' in attrs:
                    http_user_agent = "%s FormPost" % (
                        env.get('HTTP_USER_AGENT', ''))
                    env['HTTP_USER_AGENT'] = http_user_agent.strip()
                    status, headers, body = self._translate_form(
                        env, attrs['boundary'])
                    start_response(status, headers)
                    return [body]
            except (FormInvalid, MimeInvalid, EOFError) as err:
                body = 'FormPost: %s' % err
                start_response(
                    '400 Bad Request',
                    (('Content-Type', 'text/plain'),
                     ('Content-Length', str(len(body)))))
                return [body]
            except FormUnauthorized as err:
                message = 'FormPost: %s' % str(err).title()
                return HTTPUnauthorized(body=message)(
                    env, start_response)
        return self.app(env, start_response)
Exemplo n.º 4
0
    def _translate_form(self, env, boundary):
        """
        Translates the form data into subrequests and issues a
        response.

        :param env: The WSGI environment dict.
        :param boundary: The MIME type boundary to look for.
        :returns: status_line, headers_list, body
        """
        keys = self._get_keys(env)
        if six.PY3:
            boundary = boundary.encode('utf-8')
        status = message = ''
        attributes = {}
        file_attributes = {}
        subheaders = []
        file_count = 0
        for fp in iter_multipart_mime_documents(
                env['wsgi.input'], boundary, read_chunk_size=READ_CHUNK_SIZE):
            hdrs = parse_mime_headers(fp)
            disp, attrs = parse_content_disposition(
                hdrs.get('Content-Disposition', ''))
            if disp == 'form-data' and attrs.get('filename'):
                file_count += 1
                try:
                    if file_count > int(attributes.get('max_file_count') or 0):
                        status = '400 Bad Request'
                        message = 'max file count exceeded'
                        break
                except ValueError:
                    raise FormInvalid('max_file_count not an integer')
                file_attributes = attributes.copy()
                file_attributes['filename'] = attrs['filename'] or 'filename'
                if 'content-type' not in attributes and 'content-type' in hdrs:
                    file_attributes['content-type'] = \
                        hdrs['Content-Type'] or 'application/octet-stream'
                if 'content-encoding' not in attributes and \
                        'content-encoding' in hdrs:
                    file_attributes['content-encoding'] = \
                        hdrs['Content-Encoding']
                status, subheaders = \
                    self._perform_subrequest(env, file_attributes, fp, keys)
                if not status.startswith('2'):
                    break
            else:
                data = b''
                mxln = MAX_VALUE_LENGTH
                while mxln:
                    chunk = fp.read(mxln)
                    if not chunk:
                        break
                    mxln -= len(chunk)
                    data += chunk
                while fp.read(READ_CHUNK_SIZE):
                    pass
                if six.PY3:
                    data = data.decode('utf-8')
                if 'name' in attrs:
                    attributes[attrs['name'].lower()] = data.rstrip('\r\n--')
        if not status:
            status = '400 Bad Request'
            message = 'no files to process'

        headers = [(k, v) for k, v in subheaders
                   if k.lower().startswith('access-control')]

        redirect = attributes.get('redirect')
        if not redirect:
            body = status
            if message:
                body = status + '\r\nFormPost: ' + message.title()
            headers.extend([('Content-Type', 'text/plain'),
                            ('Content-Length', len(body))])
            if six.PY3:
                body = body.encode('utf-8')
            return status, headers, body
        status = status.split(' ', 1)[0]
        if '?' in redirect:
            redirect += '&'
        else:
            redirect += '?'
        redirect += 'status=%s&message=%s' % (quote(status), quote(message))
        body = '<html><body><p><a href="%s">' \
               'Click to continue...</a></p></body></html>' % redirect
        if six.PY3:
            body = body.encode('utf-8')
        headers.extend(
            [('Location', redirect), ('Content-Length', str(len(body)))])
        return '303 See Other', headers, body
    def _translate_form(self, env, boundary):
        """
        Translates the form data into subrequests and issues a
        response.

        :param env: The WSGI environment dict.
        :param boundary: The MIME type boundary to look for.
        :returns: status_line, headers_list, body
        """
        keys = self._get_keys(env)
        status = message = ""
        attributes = {}
        subheaders = []
        file_count = 0
        for fp in iter_multipart_mime_documents(env["wsgi.input"], boundary, read_chunk_size=READ_CHUNK_SIZE):
            hdrs = rfc822.Message(fp, 0)
            disp, attrs = parse_content_disposition(hdrs.getheader("Content-Disposition", ""))
            if disp == "form-data" and attrs.get("filename"):
                file_count += 1
                try:
                    if file_count > int(attributes.get("max_file_count") or 0):
                        status = "400 Bad Request"
                        message = "max file count exceeded"
                        break
                except ValueError:
                    raise FormInvalid("max_file_count not an integer")
                attributes["filename"] = attrs["filename"] or "filename"
                if "content-type" not in attributes and "content-type" in hdrs:
                    attributes["content-type"] = hdrs["Content-Type"] or "application/octet-stream"
                status, subheaders, message = self._perform_subrequest(env, attributes, fp, keys)
                if status[:1] != "2":
                    break
            else:
                data = ""
                mxln = MAX_VALUE_LENGTH
                while mxln:
                    chunk = fp.read(mxln)
                    if not chunk:
                        break
                    mxln -= len(chunk)
                    data += chunk
                while fp.read(READ_CHUNK_SIZE):
                    pass
                if "name" in attrs:
                    attributes[attrs["name"].lower()] = data.rstrip("\r\n--")
        if not status:
            status = "400 Bad Request"
            message = "no files to process"

        headers = [(k, v) for k, v in subheaders if k.lower().startswith("access-control")]

        redirect = attributes.get("redirect")
        if not redirect:
            body = status
            if message:
                body = status + "\r\nFormPost: " + message.title()
            headers.extend([("Content-Type", "text/plain"), ("Content-Length", len(body))])
            return status, headers, body
        status = status.split(" ", 1)[0]
        if "?" in redirect:
            redirect += "&"
        else:
            redirect += "?"
        redirect += "status=%s&message=%s" % (quote(status), quote(message))
        body = '<html><body><p><a href="%s">' "Click to continue...</a></p></body></html>" % redirect
        headers.extend([("Location", redirect), ("Content-Length", str(len(body)))])
        return "303 See Other", headers, body
Exemplo n.º 6
0
    def _translate_form(self, env, boundary):
        """
        Translates the form data into subrequests and issues a
        response.

        :param env: The WSGI environment dict.
        :param boundary: The MIME type boundary to look for.
        :returns: status_line, headers_list, body
        """
        keys = self._get_keys(env)
        if six.PY3:
            boundary = boundary.encode('utf-8')
        status = message = ''
        attributes = {}
        subheaders = []
        file_count = 0
        for fp in iter_multipart_mime_documents(
                env['wsgi.input'], boundary, read_chunk_size=READ_CHUNK_SIZE):
            hdrs = parse_mime_headers(fp)
            disp, attrs = parse_content_disposition(
                hdrs.get('Content-Disposition', ''))
            if disp == 'form-data' and attrs.get('filename'):
                file_count += 1
                try:
                    if file_count > int(attributes.get('max_file_count') or 0):
                        status = '400 Bad Request'
                        message = 'max file count exceeded'
                        break
                except ValueError:
                    raise FormInvalid('max_file_count not an integer')
                attributes['filename'] = attrs['filename'] or 'filename'
                if 'content-type' not in attributes and 'content-type' in hdrs:
                    attributes['content-type'] = \
                        hdrs['Content-Type'] or 'application/octet-stream'
                if 'content-encoding' not in attributes and \
                        'content-encoding' in hdrs:
                    attributes['content-encoding'] = hdrs['Content-Encoding']
                status, subheaders = \
                    self._perform_subrequest(env, attributes, fp, keys)
                if not status.startswith('2'):
                    break
            else:
                data = b''
                mxln = MAX_VALUE_LENGTH
                while mxln:
                    chunk = fp.read(mxln)
                    if not chunk:
                        break
                    mxln -= len(chunk)
                    data += chunk
                while fp.read(READ_CHUNK_SIZE):
                    pass
                if six.PY3:
                    data = data.decode('utf-8')
                if 'name' in attrs:
                    attributes[attrs['name'].lower()] = data.rstrip('\r\n--')
        if not status:
            status = '400 Bad Request'
            message = 'no files to process'

        headers = [(k, v) for k, v in subheaders
                   if k.lower().startswith('access-control')]

        redirect = attributes.get('redirect')
        if not redirect:
            body = status
            if message:
                body = status + '\r\nFormPost: ' + message.title()
            headers.extend([('Content-Type', 'text/plain'),
                            ('Content-Length', len(body))])
            if six.PY3:
                body = body.encode('utf-8')
            return status, headers, body
        status = status.split(' ', 1)[0]
        if '?' in redirect:
            redirect += '&'
        else:
            redirect += '?'
        redirect += 'status=%s&message=%s' % (quote(status), quote(message))
        body = '<html><body><p><a href="%s">' \
               'Click to continue...</a></p></body></html>' % redirect
        if six.PY3:
            body = body.encode('utf-8')
        headers.extend(
            [('Location', redirect), ('Content-Length', str(len(body)))])
        return '303 See Other', headers, body