Пример #1
0
    def locateResource(self, url):
        """
        Looks up the resource with the given URL.
        @param uri: The URL of the desired resource.
        @return: a L{Deferred} resulting in the L{IResource} at the
            given URL or C{None} if no such resource can be located.
        @raise HTTPError: If C{url} is not a URL on the site that this
            request is being applied to.  The contained response will
            have a status code of L{responsecode.BAD_GATEWAY}.
        @raise HTTPError: If C{url} contains a query or fragment.
            The contained response will have a status code of
            L{responsecode.BAD_REQUEST}.
        """
        if url is None: return None

        #
        # Parse the URL
        #
        (scheme, host, path, query, fragment) = urlsplit(url)

        if query or fragment:
            raise http.HTTPError(
                http.StatusResponse(
                    responsecode.BAD_REQUEST,
                    "URL may not contain a query or fragment: %s" % (url, )))

        # The caller shouldn't be asking a request on one server to lookup a
        # resource on some other server.
        if (scheme and scheme != self.scheme) or (
                host and host != self.headers.getHeader("host")):
            raise http.HTTPError(
                http.StatusResponse(
                    responsecode.BAD_GATEWAY,
                    "URL is not on this site (%s://%s/): %s" %
                    (scheme, self.headers.getHeader("host"), url)))

        segments = path.split("/")
        assert segments[0] == "", "URL path didn't begin with '/': %s" % (
            path, )
        segments = map(unquote, segments[1:])

        def notFound(f):
            f.trap(http.HTTPError)
            if f.value.response.code != responsecode.NOT_FOUND:
                return f
            return None

        d = defer.maybeDeferred(self._getChild,
                                None,
                                self.site.resource,
                                segments,
                                updatepaths=False)
        d.addCallback(self._rememberResource, path)
        d.addErrback(notFound)
        return d
Пример #2
0
 def http_PUT(self, request):
     content_type = request.headers.getHeader('content-type')
     if not content_type or content_type != self.content_type:
         raise http.HTTPError(responsecode.UNSUPPORTED_MEDIA_TYPE)
     element = request.attachment
     d = self.application.put_element(self.xcap_uri, element,
                                      lambda e: self.checkEtag(request, e))
     return d
Пример #3
0
 def locateChild(self, request, segments):
     fnp = self.child(segments[0])
     if not fnp.exists():
         raise http.HTTPError(responsecode.NOT_FOUND)
     elif fnp.isdir():
         return CGIDirectory(fnp.path), segments[1:]
     else:
         return CGIScript(fnp.path), segments[1:]
     return None, ()
Пример #4
0
 def render(self, req):
     if req.avatar.username == 'anonymous':
         if not self.sendOwnHeaders:
             raise http.HTTPError(responsecode.UNAUTHORIZED)
         else:
             return http.Response(
                 responsecode.UNAUTHORIZED,
                 {'www-authenticate': [('basic', {
                     'realm': 'foo'
                 })]})
     else:
         return super(NonAnonymousResource, self).render(req)
Пример #5
0
    def _loginFailed(self, result, request):
        """
        Errback for failed login.

        @param result: L{Failure} returned by portal.login

        @param request: L{IRequest} that encapsulates this auth
            attempt.

        @return: A L{Failure} containing an L{HTTPError} containing the
            L{UnauthorizedResponse} if C{result} is an L{UnauthorizedLogin}
            or L{UnhandledCredentials} error
        """
        result.trap(error.UnauthorizedLogin, error.UnhandledCredentials)

        return failure.Failure(
            http.HTTPError(
                UnauthorizedResponse(self.credentialFactories,
                                     request.remoteAddr)))
Пример #6
0
    def locateChild(self, req, segments):
        scheme = req.headers.getRawHeaders('x-app-scheme')

        if self.sendsRealHost:
            host = req.headers.getRawHeaders('host')
        else:
            host = req.headers.getRawHeaders('x-forwarded-host')

        app_location = req.headers.getRawHeaders('x-app-location')
        remote_ip = req.headers.getRawHeaders('x-forwarded-for')

        if not (host and remote_ip):
            if not host:
                warnings.warn(
                    ("No host was obtained either from Host or "
                     "X-Forwarded-Host headers.  If your proxy does not "
                     "send either of these headers use VHostURIRewrite. "
                     "If your proxy sends the real host as the Host header "
                     "use "
                     "AutoVHostURIRewrite(resrc, sendsRealHost=True)"))

            # some header unspecified => Error
            raise http.HTTPError(responsecode.BAD_REQUEST)
        host = host[0]
        remote_ip = remote_ip[0]
        if app_location:
            app_location = app_location[0]
        else:
            app_location = '/'
        if scheme:
            scheme = scheme[0]
        else:
            scheme='http'
        
        req.host, req.port = http.splitHostPort(scheme, host)
        req.scheme = scheme
        
        req.remoteAddr = address.IPv4Address('TCP', remote_ip, 0)
            
        req.prepath = app_location[1:].split('/')[:-1]
        req.path = '/'+('/'.join([urllib.quote(s, '') for s in (req.prepath + segments)]))
        
        return self.resource, segments
Пример #7
0
    def _handleSegment(self, result, res, path, updatepaths):
        """Handle the result of a locateChild call done in _getChild."""

        newres, newpath = result
        # If the child resource is None then display a error page
        if newres is None:
            raise http.HTTPError(responsecode.NOT_FOUND)

        # If we got a deferred then we need to call back later, once the
        # child is actually available.
        if isinstance(newres, defer.Deferred):
            return newres.addCallback(lambda actualRes: self._handleSegment(
                (actualRes, newpath), res, path, updatepaths))

        if path:
            url = quote("/" + "/".join(path))
        else:
            url = "/"

        if newpath is StopTraversal:
            # We need to rethink how to do this.
            #if newres is res:
            self._rememberResource(res, url)
            return res
        #else:
        #    raise ValueError("locateChild must not return StopTraversal with a resource other than self.")

        newres = iweb.IResource(newres)
        if newres is res:
            assert not newpath is path, "URL traversal cycle detected when attempting to locateChild %r from resource %r." % (
                path, res)
            assert len(newpath) < len(path), "Infinite loop impending..."

        if updatepaths:
            # We found a Resource... update the request.prepath and postpath
            for x in xrange(len(path) - len(newpath)):
                self.prepath.append(self.postpath.pop(0))

        child = self._getChild(None, newres, newpath, updatepaths=updatepaths)
        self._rememberResource(child, url)

        return child
Пример #8
0
    def _fixupURLParts(self):
        hostaddr, secure = self.chanRequest.getHostInfo()
        if not self.scheme:
            self.scheme = ('http', 'https')[secure]

        if self.host:
            self.host, self.port = http.splitHostPort(self.scheme, self.host)
        else:
            # If GET line wasn't an absolute URL
            host = self.headers.getHeader('host')
            if host:
                self.host, self.port = http.splitHostPort(self.scheme, host)
            else:
                # When no hostname specified anywhere, either raise an
                # error, or use the interface hostname, depending on
                # protocol version
                if self.clientproto >= (1, 1):
                    raise http.HTTPError(responsecode.BAD_REQUEST)
                self.host = hostaddr.host
                self.port = hostaddr.port
Пример #9
0
    def _loginSucceeded(self, avatar, request):
        """Authorizes an XCAP request after it has been authenticated."""

        interface, avatar_id = avatar  ## the avatar is the authenticated XCAP User
        xcap_uri = request.xcap_uri

        application = getApplicationForURI(xcap_uri)

        if not application:
            raise ResourceNotFound

        if interface is IAuthUser and application.is_authorized(
                XCAPUser.parse(avatar_id), xcap_uri):
            return HTTPAuthResource._loginSucceeded(self, avatar, request)
        elif interface is ITrustedPeer or interface is IPublicGetApplication:
            return HTTPAuthResource._loginSucceeded(self, avatar, request)
        else:
            return failure.Failure(
                http.HTTPError(
                    UnauthorizedResponse(self.credentialFactories,
                                         request.remoteAddr)))
Пример #10
0
    def authenticate(self, request):
        """
        Attempt to authenticate the givin request

        @param request: An L{IRequest} to be authenticated.
        """
        authHeader = request.headers.getHeader('authorization')

        if authHeader is None:
            return self.portal.login(credentials.Anonymous(), None,
                                     *self.interfaces).addCallbacks(
                                         self._loginSucceeded,
                                         self._loginFailed, (request, ), None,
                                         (request, ), None)

        elif authHeader[0] not in self.credentialFactories:
            raise http.HTTPError(
                UnauthorizedResponse(self.credentialFactories,
                                     request.remoteAddr))
        else:
            return self.login(self.credentialFactories[authHeader[0]],
                              authHeader[1], request)
Пример #11
0
    def _processingFailed(self, reason):
        # save the reason, it will be used for the stacktrace
        self._reason = reason

        exc = getattr(reason, 'value', None)
        if exc:
            # if the exception has 'http_error' and it is HTTPError, we use it to generate the response.
            # this allows us to attach http_error to non-HTTPError errors (as opposed to
            # re-raising HTTPError-derived exception) and enjoy the original stacktraces in the log
            if not isinstance(exc, http.HTTPError) and hasattr(exc, 'http_error'):
                http_error = exc.http_error
                if isinstance(http_error, http.HTTPError):
                    return server.Request._processingFailed(self, failure.Failure(http_error))
                elif isinstance(http_error, int):
                    s = get_response_body(exc)
                    response = http.Response(http_error,
                                             {'content-type': http_headers.MimeType('text','plain')},
                                             stream=s)
                    fail = failure.Failure(http.HTTPError(response))
                    return server.Request._processingFailed(self, fail)

        return server.Request._processingFailed(self, reason)
Пример #12
0
    def login(self, factory, response, request):
        """
        @param factory: An L{ICredentialFactory} that understands the given
            response.

        @param response: The client's authentication response as a string.

        @param request: The request that prompted this authentication attempt.

        @return: A L{Deferred} that fires with the wrappedResource on success
            or a failure containing an L{UnauthorizedResponse}
        """
        try:
            creds = factory.decode(response, request)
        except error.LoginFailed:
            raise http.HTTPError(
                UnauthorizedResponse(self.credentialFactories,
                                     request.remoteAddr))

        return self.portal.login(creds, None, *self.interfaces).addCallbacks(
            self._loginSucceeded, self._loginFailed, (request, ), None,
            (request, ), None)
Пример #13
0
def parsePOSTData(request):
    if request.stream.length == 0:
        return defer.succeed(None)

    parser = None
    ctype = request.headers.getHeader('content-type')

    if ctype is None:
        return defer.succeed(None)

    def updateArgs(data):
        args = data
        request.args.update(args)

    def updateArgsAndFiles(data):
        args, files = data
        request.args.update(args)
        request.files.update(files)

    def error(f):
        f.trap(fileupload.MimeFormatError)
        raise http.HTTPError(responsecode.BAD_REQUEST)

    if ctype.mediaType == 'application' and ctype.mediaSubtype == 'x-www-form-urlencoded':
        d = fileupload.parse_urlencoded(request.stream)
        d.addCallbacks(updateArgs, error)
        return d
    elif ctype.mediaType == 'multipart' and ctype.mediaSubtype == 'form-data':
        boundary = ctype.params.get('boundary')
        if boundary is None:
            return failure.Failure(
                fileupload.MimeFormatError(
                    "Boundary not specified in Content-Type."))
        d = fileupload.parseMultipartFormData(request.stream, boundary)
        d.addCallbacks(updateArgsAndFiles, error)
        return d
    else:
        raise http.HTTPError(responsecode.BAD_REQUEST)
Пример #14
0
    def http_POST(self, request):
        # we override the upstream version because it doesn't handle
        # JSON mime types
        from twisted.web2 import http, fileupload, responsecode, stream

        if request.stream.length == 0:
            d = defer.succeed(None)
        else:
            parser = None
            ctype = request.headers.getHeader('content-type')

            if ctype is None:
                d = defer.succeed(None)
            else:

                def updateArgs(data):
                    args = data
                    request.args.update(args)

                def updateJson(data):
                    request.args['message'] = [data]

                def error(f):
                    raise http.HTTPError(responsecode.BAD_REQUEST)

                if ctype.mediaType == 'application' and ctype.mediaSubtype == 'x-www-form-urlencoded':
                    d = fileupload.parse_urlencoded(request.stream)
                    d.addCallbacks(updateArgs, error)
                elif ctype.mediaType in ('application', 'text'
                                         ) and ctype.mediaSubtype == 'json':
                    d = stream.readStream(request.stream, updateJson)
                    d.addErrback(error)
                else:
                    raise http.HTTPError(responsecode.BAD_REQUEST)

        return d.addCallback(lambda res: self.render(request))
Пример #15
0
 def error(f):
     f.trap(fileupload.MimeFormatError)
     raise http.HTTPError(responsecode.BAD_REQUEST)
Пример #16
0
def parsePOSTData(request,
                  maxMem=100 * 1024,
                  maxFields=1024,
                  maxSize=10 * 1024 * 1024):
    """
    Parse data of a POST request.

    @param request: the request to parse.
    @type request: L{twisted.web2.http.Request}.
    @param maxMem: maximum memory used during the parsing of the data.
    @type maxMem: C{int}
    @param maxFields: maximum number of form fields allowed.
    @type maxFields: C{int}
    @param maxSize: maximum size of file upload allowed.
    @type maxSize: C{int}

    @return: a deferred that will fire when the parsing is done. The deferred
        itself doesn't hold a return value, the request is modified directly.
    @rtype: C{defer.Deferred}
    """
    if request.stream.length == 0:
        return defer.succeed(None)

    parser = None
    ctype = request.headers.getHeader('content-type')

    if ctype is None:
        return defer.succeed(None)

    def updateArgs(data):
        args = data
        request.args.update(args)

    def updateArgsAndFiles(data):
        args, files = data
        request.args.update(args)
        request.files.update(files)

    def error(f):
        f.trap(fileupload.MimeFormatError)
        raise http.HTTPError(
            http.StatusResponse(responsecode.BAD_REQUEST, str(f.value)))

    if (ctype.mediaType == 'application'
            and ctype.mediaSubtype == 'x-www-form-urlencoded'):
        d = fileupload.parse_urlencoded(request.stream)
        d.addCallbacks(updateArgs, error)
        return d
    elif (ctype.mediaType == 'multipart'
          and ctype.mediaSubtype == 'form-data'):
        boundary = ctype.params.get('boundary')
        if boundary is None:
            return defer.fail(
                http.HTTPError(
                    http.StatusResponse(
                        responsecode.BAD_REQUEST,
                        "Boundary not specified in Content-Type.")))
        d = fileupload.parseMultipartFormData(request.stream, boundary, maxMem,
                                              maxFields, maxSize)
        d.addCallbacks(updateArgsAndFiles, error)
        return d
    else:
        return defer.fail(
            http.HTTPError(
                http.StatusResponse(
                    responsecode.BAD_REQUEST, "Invalid content-type: %s/%s" %
                    (ctype.mediaType, ctype.mediaSubtype))))
Пример #17
0
 def error(f):
     raise http.HTTPError(responsecode.BAD_REQUEST)
Пример #18
0
#
#     def __init__(self, path):
#         self.path = path
#
#     def renderHTTP(self, request):
#         request.startedWriting = 1
#         return File(self.path)
#
#     def locateChild(self, request):
#         return None, ()

##
# Utilities
##

dangerousPathError = http.HTTPError(
    responsecode.NOT_FOUND)  #"Invalid request URL."


def isDangerous(path):
    return path == '..' or '/' in path or os.sep in path


def addSlash(request):
    return "http%s://%s%s/" % (request.isSecure() and 's'
                               or '', request.getHeader("host"),
                               (request.uri.split('?')[0]))


def loadMimeTypes(mimetype_locations=['/etc/mime.types']):
    """
    Multiple file locations containing mime-types can be passed as a list.
Пример #19
0
 def error(f):
     f.trap(fileupload.MimeFormatError)
     raise http.HTTPError(
         http.StatusResponse(responsecode.BAD_REQUEST, str(f.value)))