Skip to content

Instantly share code, notes, and snippets.

@voidfiles
Created March 24, 2010 04:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save voidfiles/341991 to your computer and use it in GitHub Desktop.
Save voidfiles/341991 to your computer and use it in GitHub Desktop.
"""
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