Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

redone sendfile+redirect (+django-sendfile) #46

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 5 additions & 41 deletions djangodav/fs/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()

Expand All @@ -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
Expand Down Expand Up @@ -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)
8 changes: 8 additions & 0 deletions djangodav/responses.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
34 changes: 29 additions & 5 deletions djangodav/views/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down Expand Up @@ -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
Expand Down