blob: 644c1b85b199404e88ed377575769ba5bfbfce57 [file] [log] [blame]
# Copyright 2008 the Melange authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Blobstore Django helpers.
These helpers are used to handle uploading and downloading appengine blobs.
With due credits, this is not Melange code. This was shamelessly
flicked from http://appengine-cookbook.appspot.com/recipe/blobstore-get_uploads-helper-function-for-django-request/
Credits and big thanks to to: sebastian.serrano and emi420
"""
import cgi
import logging
from django import http
from google.appengine.ext import blobstore
from soc.logic import exceptions
def _parseField(request, key, field):
"""Parses one field.
Handles BlobInfo objects and adds the 'name' field for Django.
"""
if isinstance(field, cgi.FieldStorage) and 'blob-key' in field.type_options:
blob_info = blobstore.parse_blob_info(field)
uploads = request.__uploads.setdefault(key, [])
uploads.append(blob_info)
# Put the BlobInfo in the POST data and format it for Django by
# adding the name property.
blob_info.name = blob_info.filename
request.file_uploads[key] = blob_info
elif isinstance(field, list):
request.POST[key] = [f.value for f in field]
else:
request.POST[key] = field.value
def cacheUploads(request):
"""Caches uploads in the request.__uploads field.
Also recreates the POST dictionary.
The __uploads attribute in the request object is used only to cache
the file uploads so that we do not have to go through the process of
reading HTTP request original file if it has already been read in
the same request.
Args:
request: a django Request object
"""
if hasattr(request, '__uploads'):
return
wsgi_input = request.META['wsgi.input']
wsgi_input.seek(0)
fields = cgi.FieldStorage(wsgi_input, environ=request.META)
request.POST = {}
request.file_uploads = {}
request.__uploads = {}
for key in fields.keys():
field = fields[key]
_parseField(request, key, field)
def getUploads(request, field_name=None):
"""Get uploads sent to this handler.
Args:
field_name: Only select uploads that were sent as a specific field
Returns:
A list of BlobInfo records corresponding to each upload
Empty list if there are no blob-info records for field_name
"""
results = []
cacheUploads(request)
if field_name:
return request.file_uploads.get(field_name, [])
for uploads in request.__uploads.itervalues():
results += uploads
return results
def sendBlob(blob_info):
"""Constructs a response that App Engine will interpret as a blob send.
The returned http.HttpResponse will have a "Content-Disposition" header
based on blob_info's stored file name, a "Content-Type" header based on
blob_info's stored content type, and a blobstore.BLOB_KEY_HEADER header
storing blob key of the blob to be sent to the user.
The returned http.HttpResponse may also have other headers set.
Args:
blob_info: BlobInfo record representing the blob to be received by
the user.
Returns:
An http.HttpResponse object with at least "Content-Type",
"Content-Disposition", and blobstore.BLOB_KEY_HEADER headers set.
Raises:
exceptions.BadRequest: If blob_info is missing a file name.
"""
logging.debug(blob_info)
assert isinstance(blob_info, blobstore.BlobInfo)
CONTENT_DISPOSITION = 'attachment; filename="%s"'
content_type = blob_info.content_type
filename = blob_info.filename
if isinstance(content_type, unicode):
content_type = content_type.encode('utf-8')
if not filename:
raise exceptions.BadRequest('No filename in blob_info.')
if isinstance(filename, unicode):
filename = filename.encode('utf-8')
response = http.HttpResponse(content_type=content_type)
# We set the cache control to disable all kinds of caching hoping
# that Appengine does not cache the blob keys in the header if we
# set this.
response['Cache-Control'] = (
'no-store, no-cache, must-revalidate, post-check=0, pre-check=0')
response['Content-Disposition'] = CONTENT_DISPOSITION % filename
response[blobstore.BLOB_KEY_HEADER] = str(blob_info.key())
return response