Created
March 24, 2010 04:41
-
-
Save voidfiles/341991 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
I use this as a pull cache/pseudo-CDN for a production environment. I use this as a fallback static file server, if the file doesn't exist already on the server. If my server doesn't have a file, like an image, I then pull the file from the fallback server, or origin server. This can be my box, or more likely if I am pulling from a 3rd party site, I can cache the file on my servers, instead of having to constantly hit the other site. | |
I put this in my apache .htaccess file | |
RewriteCond %{REQUEST_FILENAME} !-f | |
RewriteRule ^(.*)$ dispatch.fcgi/$1 [QSA,L] | |
This serves the file if it exists else, it falls back on my django fcgi. | |
I use this because my website http://staytuned.in is hosted on http://www.dreamhost.com | |
improved static fallback using httplib2 | |
checks to make sure return code is 200 before storeing the file | |
file: static_fallback.py | |
""" | |
import mimetypes | |
import os | |
import posixpath | |
import httplib2 | |
import urllib | |
import django | |
from django.conf import settings | |
from django.http import Http404, HttpResponse | |
from django.views import static | |
def serve(request, path, document_root=None, show_indexes=False, cache=True, fallback_server=None): | |
""" | |
Serve static files using Django's static file function but if it returns a | |
404, then attempt to find the file on the fallback_server. Optionally and by | |
default, cache the file locally. | |
To use, put a URL pattern such as:: | |
(r'^(?P<path>.*)$', 'static_fallback.serve', {'document_root' : '/path/to/my/files/'}) | |
in your URLconf. You must provide the ``document_root`` param (required by | |
Django). You may also set ``show_indexes`` to ``True`` if you'd like to | |
serve a basic index of the directory. These parameters are passed through | |
directly to django.views.static.serve. You should see the doc_string there | |
for details. | |
Passing cache to True (default) copies the file locally. | |
Be sure to set settings.FALLBACK_STATIC_URL to something like: | |
FALLBACK_STATIC_URL = 'http://myprodsite.com' | |
Alternatively, you can also tell it the fallback server as a parameter | |
sent in the URLs. | |
fallback_server - should have a closing / | |
Author: Ed Menendez (ed@menendez.com) | |
Concept: Johnny Dobbins | |
Revisions: Alex Kessinger (alex@alexkessinger.net) | |
""" | |
# This was mostly copied from Django's version. We need the filepath for | |
# caching and it also serves as an optimization. If the file is not found | |
# then there's no reason to go through the Django process. | |
try: | |
fallback_server = settings.FALLBACK_STATIC_URL | |
except AttributeError: | |
print u"You're using static_fallback.serve to serve static content " + \ | |
"however settings.FALLBACK_STATIC_URL has not been set." | |
# Save this for later to pass to Django. | |
h = httplib2.Http(None) | |
original_path = path | |
path = posixpath.normpath(urllib.unquote(path)) | |
path = path.lstrip('/') | |
newpath = '' | |
for part in path.split('/'): | |
if not part: | |
# Strip empty path components. | |
continue | |
drive, part = os.path.splitdrive(part) | |
head, part = os.path.split(part) | |
if part in (os.curdir, os.pardir): | |
# Strip '.' and '..' in path. | |
continue | |
newpath = os.path.join(newpath, part).replace('\\', '/') | |
if newpath and path != newpath: | |
return HttpResponseRedirect(newpath) # RETURN | |
fullpath = os.path.join(document_root, newpath) | |
# End of the "mostly from Django" section. | |
print fullpath | |
try: | |
# Don't bother trying the Django function if the file isn't there. | |
if not os.path.isdir(fullpath) and not os.path.exists(fullpath): | |
raise Http404, '"%s" does not exist' % fullpath # RAISE | |
else: | |
# Pass through cleanly to Django's verson | |
return static.serve( # RETURN | |
request, original_path, document_root, show_indexes) | |
except Http404: | |
if fallback_server: | |
# Attempt to find it on the remote server. | |
fq_url = '%s%s' % (fallback_server, path) | |
try: | |
resp, content = h.request(fq_url, "GET") | |
print resp.status | |
print (resp.status != "200") | |
if int(resp.status) != 200: | |
raise Http404, '"%s" not found' % fq_url # RAISE | |
except: | |
# Naive to assume a 404 - ed | |
raise Http404, '"%s" http error' % fq_url # RAISE | |
else: | |
# Found the doc. Return it to response. | |
mimetype = mimetypes.guess_type(fq_url) | |
# str forces httplib2 to finish download before we try and store. | |
content = str(content) | |
# Do we need to cache the file? | |
if cache: | |
f = open(fullpath, 'wb+') | |
f.write(content) | |
f.close() | |
# Success! We have the file. Send it back. | |
return HttpResponse(content, mimetype=mimetype) # RETURN | |
else: | |
# No fallback_server was defined. So, it's really a 404 now. | |
raise Http404 # RAISE |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment