def __call__(self, environ, start_response):
        path = environ["PATH_INFO"]

        davres = None
        if environ["wsgidav.provider"]:
            davres = environ["wsgidav.provider"].getResourceInst(path, environ)

        if environ["REQUEST_METHOD"] in ("GET", "HEAD") and davres and davres.isCollection:

            #            if "mozilla" not in environ.get("HTTP_USER_AGENT").lower():
            #                # issue 14: Nautilus sends GET on collections
            #                # http://code.google.com/p/wsgidav/issues/detail?id=14
            #                util.status("Directory browsing disabled for agent '%s'" % environ.get("HTTP_USER_AGENT"))
            #                self._fail(HTTP_NOT_IMPLEMENTED)
            #                return self._application(environ, start_response)

            if util.getContentLength(environ) != 0:
                self._fail(HTTP_MEDIATYPE_NOT_SUPPORTED, "The server does not handle any body content.")

            if environ["REQUEST_METHOD"] == "HEAD":
                return util.sendStatusResponse(environ, start_response, HTTP_OK)

            # Support DAV mount (http://www.ietf.org/rfc/rfc4709.txt)
            dirConfig = environ["wsgidav.config"].get("dir_browser", {})
            if dirConfig.get("davmount") and "davmount" in environ.get("QUERY_STRING"):
                #                collectionUrl = davres.getHref()
                collectionUrl = util.makeCompleteUrl(environ)
                collectionUrl = collectionUrl.split("?")[0]
                res = """
                    <dm:mount xmlns:dm="http://purl.org/NET/webdav/mount">
                        <dm:url>%s</dm:url>
                    </dm:mount>""" % (
                    collectionUrl
                )
                # TODO: support <dm:open>%s</dm:open>

                start_response(
                    "200 OK",
                    [
                        ("Content-Type", "application/davmount+xml"),
                        ("Content-Length", str(len(res))),
                        ("Cache-Control", "private"),
                        ("Date", util.getRfc1123Time()),
                    ],
                )
                return [res]

            # Profile calls
            #            if True:
            #                from cProfile import Profile
            #                profile = Profile()
            #                profile.runcall(self._listDirectory, environ, start_response)
            #                # sort: 0:"calls",1:"time", 2: "cumulative"
            #                profile.print_stats(sort=2)
            return self._listDirectory(davres, environ, start_response)

        return self._application(environ, start_response)
    def __call__(self, environ, start_response):
        path = environ["PATH_INFO"]

        davres = None
        if environ["wsgidav.provider"]:
            davres = environ["wsgidav.provider"].getResourceInst(path, environ)

        if environ["REQUEST_METHOD"] in (
                "GET", "HEAD") and davres and davres.isCollection:

            #            if "mozilla" not in environ.get("HTTP_USER_AGENT").lower():
            #                # issue 14: Nautilus sends GET on collections
            #                # http://code.google.com/p/wsgidav/issues/detail?id=14
            #                util.status("Directory browsing disabled for agent '%s'" % environ.get("HTTP_USER_AGENT"))
            #                self._fail(HTTP_NOT_IMPLEMENTED)
            #                return self._application(environ, start_response)

            if util.getContentLength(environ) != 0:
                self._fail(HTTP_MEDIATYPE_NOT_SUPPORTED,
                           "The server does not handle any body content.")

            if environ["REQUEST_METHOD"] == "HEAD":
                return util.sendStatusResponse(environ, start_response,
                                               HTTP_OK)

            # Support DAV mount (http://www.ietf.org/rfc/rfc4709.txt)
            dirConfig = environ["wsgidav.config"].get("dir_browser", {})
            if dirConfig.get("davmount") and "davmount" in environ.get(
                    "QUERY_STRING"):
                #                collectionUrl = davres.getHref()
                collectionUrl = util.makeCompleteUrl(environ)
                collectionUrl = collectionUrl.split("?")[0]
                res = """
                    <dm:mount xmlns:dm="http://purl.org/NET/webdav/mount">
                        <dm:url>%s</dm:url>
                    </dm:mount>""" % (collectionUrl)
                # TODO: support <dm:open>%s</dm:open>

                start_response("200 OK", [
                    ("Content-Type", "application/davmount+xml"),
                    ("Content-Length", str(len(res))),
                    ("Cache-Control", "private"),
                    ("Date", util.getRfc1123Time()),
                ])
                return [res]

            # Profile calls
#            if True:
#                from cProfile import Profile
#                profile = Profile()
#                profile.runcall(self._listDirectory, environ, start_response)
#                # sort: 0:"calls",1:"time", 2: "cumulative"
#                profile.print_stats(sort=2)
            return self._listDirectory(davres, environ, start_response)

        return self._application(environ, start_response)
Beispiel #3
0
        def _start_response_wrapper(status, response_headers, exc_info=None):
            # Postprocess response headers
            headerDict = {}
            for header, value in response_headers:
                if header.lower() in headerDict:
                    util.warn("Duplicate header in response: %s" % header)
                headerDict[header.lower()] = value

            # Check if we should close the connection after this request.
            # http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4
            forceCloseConnection = False
            currentContentLength = headerDict.get("content-length")
            statusCode = int(status.split(" ", 1)[0])
            contentLengthRequired = (environ["REQUEST_METHOD"] != "HEAD"
                                     and statusCode >= 200
                                     and not statusCode in (204, 304))
            #            print environ["REQUEST_METHOD"], statusCode, contentLengthRequired
            if contentLengthRequired and currentContentLength in (None, ""):
                # A typical case: a GET request on a virtual resource, for which
                # the provider doesn't know the length
                util.warn(
                    "Missing required Content-Length header in %s-response: closing connection"
                    % statusCode)
                forceCloseConnection = True
            elif not type(currentContentLength) is str:
                util.warn(
                    "Invalid Content-Length header in response (%r): closing connection"
                    % headerDict.get("content-length"))
                forceCloseConnection = True

            # HOTFIX for Vista and Windows 7 (GC issue 13, issue 23)
            # It seems that we must read *all* of the request body, otherwise
            # clients may miss the response.
            # For example Vista MiniRedir didn't understand a 401 response,
            # when trying an anonymous PUT of big files. As a consequence, it
            # doesn't retry with credentials and the file copy fails.
            # (XP is fine however).
            util.readAndDiscardInput(environ)

            # Make sure the socket is not reused, unless we are 100% sure all
            # current input was consumed
            if (util.getContentLength(environ) != 0
                    and not environ.get("wsgidav.all_input_read")):
                util.warn(
                    "Input stream not completely consumed: closing connection")
                forceCloseConnection = True

            if forceCloseConnection and headerDict.get(
                    "connection") != "close":
                util.warn("Adding 'Connection: close' header")
                response_headers.append(("Connection", "close"))

            # Log request
            if self._verbose >= 1:
                userInfo = environ.get("http_authenticator.username")
                if not userInfo:
                    userInfo = "(anonymous)"
                threadInfo = ""
                if self._verbose >= 1:
                    threadInfo = "<%s> " % threading._get_ident()
                extra = []
                if "HTTP_DESTINATION" in environ:
                    extra.append('dest="%s"' % environ.get("HTTP_DESTINATION"))
                if environ.get("CONTENT_LENGTH", "") != "":
                    extra.append("length=%s" % environ.get("CONTENT_LENGTH"))
                if "HTTP_DEPTH" in environ:
                    extra.append("depth=%s" % environ.get("HTTP_DEPTH"))
                if "HTTP_RANGE" in environ:
                    extra.append("range=%s" % environ.get("HTTP_RANGE"))
                if "HTTP_OVERWRITE" in environ:
                    extra.append("overwrite=%s" %
                                 environ.get("HTTP_OVERWRITE"))
                if self._verbose >= 1 and "HTTP_EXPECT" in environ:
                    extra.append('expect="%s"' % environ.get("HTTP_EXPECT"))
                if self._verbose >= 2 and "HTTP_CONNECTION" in environ:
                    extra.append('connection="%s"' %
                                 environ.get("HTTP_CONNECTION"))
                if self._verbose >= 2 and "HTTP_USER_AGENT" in environ:
                    extra.append('agent="%s"' % environ.get("HTTP_USER_AGENT"))
                if self._verbose >= 2 and "HTTP_TRANSFER_ENCODING" in environ:
                    extra.append('transfer-enc=%s' %
                                 environ.get("HTTP_TRANSFER_ENCODING"))
                if self._verbose >= 1:
                    extra.append('elap=%.3fsec' % (time.time() - start_time))
                extra = ", ".join(extra)

                util.log('%s - %s - "%s" %s -> %s' %
                         (environ.get("REMOTE_ADDR", ""), userInfo,
                          environ.get("REQUEST_METHOD") + " " +
                          environ.get("PATH_INFO", ""), extra, status))

            return start_response(status, response_headers, exc_info)
Beispiel #4
0
        def _start_response_wrapper(status, response_headers, exc_info=None):
            # Postprocess response headers
            headerDict = {}
            for header, value in response_headers:
                if header.lower() in headerDict:
                    util.warn("Duplicate header in response: %s" % header)
                headerDict[header.lower()] = value

            # Check if we should close the connection after this request. 
            # http://www.w3.org/Protocols/rfc2616/rfc2616-sec4.html#sec4.4
            forceCloseConnection = False
            currentContentLength = headerDict.get("content-length") 
            statusCode = int(status.split(" ", 1)[0]) 
            contentLengthRequired = (environ["REQUEST_METHOD"] != "HEAD" 
                                     and statusCode >= 200
                                     and not statusCode in (204, 304))  
#            print environ["REQUEST_METHOD"], statusCode, contentLengthRequired
            if contentLengthRequired and currentContentLength in (None, ""):
                # A typical case: a GET request on a virtual resource, for which  
                # the provider doesn't know the length 
                util.warn("Missing required Content-Length header in %s-response: closing connection" % statusCode)
                forceCloseConnection = True
            elif not type(currentContentLength) is str:
                util.warn("Invalid Content-Length header in response (%r): closing connection" % headerDict.get("content-length"))
                forceCloseConnection = True
            
            # HOTFIX for Vista and Windows 7 (GC issue 13, issue 23)
            # It seems that we must read *all* of the request body, otherwise
            # clients may miss the response.
            # For example Vista MiniRedir didn't understand a 401 response, 
            # when trying an anonymous PUT of big files. As a consequence, it
            # doesn't retry with credentials and the file copy fails. 
            # (XP is fine however).
            util.readAndDiscardInput(environ)

            # Make sure the socket is not reused, unless we are 100% sure all 
            # current input was consumed
            if(util.getContentLength(environ) != 0 
               and not environ.get("wsgidav.all_input_read")):
                util.warn("Input stream not completely consumed: closing connection")
                forceCloseConnection = True
                
            if forceCloseConnection and headerDict.get("connection") != "close":    
                util.warn("Adding 'Connection: close' header")
                response_headers.append(("Connection", "close"))
            
            # Log request
            if self._verbose >= 1:
                userInfo = environ.get("http_authenticator.username")
                if not userInfo:
                    userInfo = "(anonymous)"
                threadInfo = ""
                if self._verbose >= 1:
                    threadInfo = "<%s> " % threading._get_ident()
                extra = []
                if "HTTP_DESTINATION" in environ:
                    extra.append('dest="%s"' % environ.get("HTTP_DESTINATION"))
                if environ.get("CONTENT_LENGTH", "") != "":
                    extra.append("length=%s" % environ.get("CONTENT_LENGTH"))
                if "HTTP_DEPTH" in environ:
                    extra.append("depth=%s" % environ.get("HTTP_DEPTH"))
                if "HTTP_RANGE" in environ:
                    extra.append("range=%s" % environ.get("HTTP_RANGE"))
                if "HTTP_OVERWRITE" in environ:
                    extra.append("overwrite=%s" % environ.get("HTTP_OVERWRITE"))
                if self._verbose >= 1 and "HTTP_EXPECT" in environ:
                    extra.append('expect="%s"' % environ.get("HTTP_EXPECT"))
                if self._verbose >= 2 and "HTTP_CONNECTION" in environ:
                    extra.append('connection="%s"' % environ.get("HTTP_CONNECTION"))
                if self._verbose >= 2 and "HTTP_USER_AGENT" in environ:
                    extra.append('agent="%s"' % environ.get("HTTP_USER_AGENT"))
                if self._verbose >= 2 and "HTTP_TRANSFER_ENCODING" in environ:
                    extra.append('transfer-enc=%s' % environ.get("HTTP_TRANSFER_ENCODING"))
                if self._verbose >= 1:
                    extra.append('elap=%.3fsec' % (time.time() - start_time))
                extra = ", ".join(extra)
                        
#               This is the CherryPy format:     
#                127.0.0.1 - - [08/Jul/2009:17:25:23] "GET /loginPrompt?redirect=/renderActionList%3Frelation%3Dpersonal%26key%3D%26filter%3DprivateSchedule&reason=0 HTTP/1.1" 200 1944 "http://127.0.0.1:8002/command?id=CMD_Schedule" "Mozilla/5.0 (Windows; U; Windows NT 6.0; de; rv:1.9.1) Gecko/20090624 Firefox/3.5"
#                print >>sys.stderr, '%s - %s - [%s] "%s" %s -> %s' % (
                print >>sys.stdout, '%s - %s - [%s] "%s" %s -> %s' % (
                                        threadInfo + environ.get("REMOTE_ADDR",""),                                                         
                                        userInfo,
                                        util.getLogTime(), 
                                        environ.get("REQUEST_METHOD") + " " + environ.get("PATH_INFO", ""),
                                        extra, 
                                        status,
#                                        response_headers.get(""), # response Content-Length
                                        # referer
                                     )
 
            return start_response(status, response_headers, exc_info)