diff --git a/djangodav/fs/resources.py b/djangodav/fs/resources.py index 5584efe..0b02bb7 100644 --- a/djangodav/fs/resources.py +++ b/djangodav/fs/resources.py @@ -18,21 +18,13 @@ # # You should have received a copy of the GNU Affero General Public License # along with DjangoDav. If not, see <http://www.gnu.org/licenses/>. -import hashlib -import mimetypes -from sys import getfilesystemencoding -import os import datetime +import os import shutil -import urllib - -from django.http import HttpResponse -from django.utils.http import http_date +from sys import getfilesystemencoding from djangodav.base.resources import BaseDavResource -from djangodav.responses import ResponseException -from djangodav.utils import safe_join, url_join - +from djangodav.utils import url_join fs_encoding = getfilesystemencoding() @@ -43,6 +35,8 @@ class BaseFSDavResource(BaseDavResource): python's os library to do most of the work.""" root = None + quote = False + prefix = "/" def get_abs_path(self): """Return the absolute path of the resource. Used internally to interface with @@ -129,33 +123,3 @@ def write(self, request): class DummyFSDAVResource(DummyReadFSDavResource, DummyWriteFSDavResource, BaseFSDavResource): pass - - -class SendFileFSDavResource(BaseFSDavResource): - quote = False - - def read(self): - response = HttpResponse() - full_path = self.get_abs_path().encode('utf-8') - if self.quote: - full_path = urllib.quote(full_path) - response['X-SendFile'] = full_path - response['Content-Type'] = mimetypes.guess_type(self.displayname) - response['Content-Length'] = self.getcontentlength - response['Last-Modified'] = http_date(self.getlastmodified) - response['ETag'] = self.getetag - raise ResponseException(response) - - -class RedirectFSDavResource(BaseFSDavResource): - prefix = "/" - - def read(self): - response = HttpResponse() - response['X-Accel-Redirect'] = url_join(self.prefix, self.get_path().encode('utf-8')) - response['X-Accel-Charset'] = 'utf-8' - response['Content-Type'] = mimetypes.guess_type(self.displayname) - response['Content-Length'] = self.getcontentlength - response['Last-Modified'] = http_date(self.getlastmodified) - response['ETag'] = self.getetag - raise ResponseException(response) diff --git a/djangodav/responses.py b/djangodav/responses.py index a31e4ed..0b9e529 100644 --- a/djangodav/responses.py +++ b/djangodav/responses.py @@ -41,6 +41,14 @@ def __init__(self, response, *args, **kwargs): self.response = response +class AsSendFileFS(Exception): + pass + + +class RedirectFSException(Exception): + pass + + class HttpResponsePreconditionFailed(HttpResponse): status_code = httplib.PRECONDITION_FAILED diff --git a/djangodav/views/views.py b/djangodav/views/views.py index 7cc46ca..672150a 100644 --- a/djangodav/views/views.py +++ b/djangodav/views/views.py @@ -6,23 +6,30 @@ from sys import version_info as python_version from django.utils.timezone import now from lxml import etree +import mimetypes +import urllib from django.http import HttpResponseForbidden, HttpResponseNotAllowed, HttpResponseBadRequest, \ - HttpResponseNotModified, HttpResponseRedirect, Http404 + HttpResponseNotModified, HttpResponseRedirect, Http404, HttpResponse from django.utils.decorators import method_decorator from django.utils.functional import cached_property -from django.utils.http import parse_etags +from django.utils.http import parse_etags, http_date from django.shortcuts import render_to_response from django.views.decorators.csrf import csrf_exempt from django.views.generic import View -from djangodav.responses import ResponseException, HttpResponsePreconditionFailed, HttpResponseCreated, HttpResponseNoContent, \ +from djangodav.responses import HttpResponsePreconditionFailed, HttpResponseCreated, HttpResponseNoContent, \ HttpResponseConflict, HttpResponseMediatypeNotSupported, HttpResponseBadGateway, \ - HttpResponseMultiStatus, HttpResponseLocked, HttpResponse + HttpResponseMultiStatus, HttpResponseLocked, RedirectFSException, ResponseException, AsSendFileFS from djangodav.utils import WEBDAV_NSMAP, D, url_join, get_property_tag_list, rfc1123_date from djangodav import VERSION as djangodav_version from django import VERSION as django_version, get_version +try: + import sendfile +except ImportError: + sendfile = None + PATTERN_IF_DELIMITER = re.compile(r'(<([^>]+)>)|(\(([^\)]+)\))') class DavView(View): @@ -190,7 +197,24 @@ def get(self, request, path, head=False, *args, **kwargs): response['ETag'] = self.resource.getetag if not head: response['Content-Length'] = self.resource.getcontentlength - response.content = self.resource.read() + try: + response.content = self.resource.read() + except AsSendFileFS: + assert sendfile is not None, "django-sendfile is not installed." + full_path = self.resource.get_abs_path() + if self.resource.quote: + full_path = urllib.quote(full_path) + response = sendfile.sendfile(request, full_path) + return response + except RedirectFSException: + response = HttpResponse() + response['X-Accel-Redirect'] = url_join(self.resource.prefix, self.resource.get_path().encode('utf-8')) + response['X-Accel-Charset'] = 'utf-8' + response['Content-Type'] = mimetypes.guess_type(self.resource.displayname) + response['Content-Length'] = self.resource.getcontentlength + response['Last-Modified'] = http_date(self.resource.getlastmodified) + response['ETag'] = self.resource.getetag + raise ResponseException(response) elif not head: response = render_to_response(self.template_name, dict(resource=self.resource, base_url=self.base_url)) response['Last-Modified'] = self.resource.getlastmodified