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 '{}'" # .format(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>{}</dm:url> </dm:mount>""".format(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 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 = util.makeCompleteUrl(environ) collectionUrl = collectionUrl.split("?", 1)[0] res = """ <dm:mount xmlns:dm="http://purl.org/NET/webdav/mount"> <dm:url>{}</dm:url> </dm:mount>""".format(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] context = self._get_context(environ, davres) res = self.template.render(**context) res = compat.to_bytes(res) start_response("200 OK", [ ("Content-Type", "text/html"), ("Content-Length", str(len(res))), ("Cache-Control", "private"), ("Date", util.getRfc1123Time()), ]) return [res] return self.next_app(environ, start_response)
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.currentThread().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('%s - %s - [%s] "%s" %s -> %s' % ( threadInfo + environ.get("REMOTE_ADDR", ""), userInfo, util.getLogTime(), environ.get("REQUEST_METHOD") + " " + safeReEncode(environ.get("PATH_INFO", ""), sys.stdout.encoding or "ASCII"), extra, status, # response_headers.get(""), # response Content-Length # referer ), file=sys.stdout) return start_response(status, response_headers, exc_info)