Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAleksey Lim <alsroot@sugarlabs.org>2012-03-19 22:54:32 (GMT)
committer Aleksey Lim <alsroot@sugarlabs.org>2012-03-19 22:54:32 (GMT)
commite0a8b9cf85310707f4ecd2a39b777bf7391c2596 (patch)
treea5ea028acf076224dbdd12375d297623c233ae00
parent09341fe15e9bfff10bc357dcabeee915ced76d9d (diff)
Tune BLOBs support:
* handle streams; * upload with url; * download redirect.
-rw-r--r--restful_document/__init__.py2
-rw-r--r--restful_document/document.py29
-rw-r--r--restful_document/env.py27
-rw-r--r--restful_document/router.py11
-rw-r--r--restful_document/user.py2
5 files changed, 49 insertions, 22 deletions
diff --git a/restful_document/__init__.py b/restful_document/__init__.py
index ebc944e..f2b9d63 100644
--- a/restful_document/__init__.py
+++ b/restful_document/__init__.py
@@ -30,6 +30,6 @@ from restful_document.user import \
from restful_document.env import \
principal, request, responce, \
- HTTPError, BadRequest, Unauthorized, Forbidden, NotFound, \
+ HTTPStatus, SeeOther, BadRequest, Unauthorized, Forbidden, NotFound, \
host, port, debug, foreground, logdir, rundir, trust_users, \
keyfile, certfile, master, auth
diff --git a/restful_document/document.py b/restful_document/document.py
index 8a982d2..32fdc56 100644
--- a/restful_document/document.py
+++ b/restful_document/document.py
@@ -13,6 +13,8 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
+import logging
+import urllib2
from gettext import gettext as _
import active_document as ad
@@ -23,6 +25,8 @@ from restful_document import env
LAYERS = ['public', 'deleted']
+_logger = logging.getLogger('rd.document')
+
def restful_method(**kwargs):
@@ -66,12 +70,15 @@ class Document(ad.Document):
return {'total': total.value, 'result': result}
@restful_method(method='PUT')
- def restful_put(self, prop=None):
+ def restful_put(self, prop=None, url=None):
if prop is None:
self.update(self.guid, env.request.content)
elif isinstance(self.metadata[prop], ad.BlobProperty):
- self.set_blob(prop, env.request.content_stream,
- env.request.content_length)
+ if url is not None:
+ self.recv_blob(prop, url)
+ else:
+ self.set_blob(prop, env.request.content_stream,
+ env.request.content_length)
else:
self[prop] = env.request.content
self.post()
@@ -94,10 +101,7 @@ class Document(ad.Document):
reply.append(name)
return self.all_properties(reply)
elif isinstance(self.metadata[prop], ad.BlobProperty):
- stat = self.stat_blob(prop)
- env.responce['Content-Type'] = self.metadata[prop].mime_type
- env.responce['Content-Length'] = stat['size']
- return self.get_blob(prop)
+ return self.send_blob(prop)
else:
return self[prop]
@@ -106,6 +110,17 @@ class Document(ad.Document):
enforce(prop, _('Property name is not specified'))
return self.stat_blob(prop)
+ def recv_blob(self, prop, url):
+ _logger.info(_('Download BLOB for "%s" from "%s"'), prop, url)
+ stream = urllib2.urlopen(url)
+ self.set_blob(prop, stream)
+
+ def send_blob(self, prop):
+ stat = self.stat_blob(prop)
+ env.responce['Content-Type'] = self.metadata[prop].mime_type
+ env.responce['Content-Length'] = stat['size'] if stat else 0
+ return self.get_blob(prop)
+
def all_properties(self, reply):
result = {}
for prop_name in (reply or ['guid']):
diff --git a/restful_document/env.py b/restful_document/env.py
index e9c4dbf..b8a619b 100644
--- a/restful_document/env.py
+++ b/restful_document/env.py
@@ -97,34 +97,43 @@ def pop_list(name, kwargs, default=_default):
return value
-class HTTPError(Exception):
+class HTTPStatus(Exception):
- status = '500 Internal Server Error'
+ status = None
+ headers = None
+ result = None
+
+
+class SeeOther(HTTPStatus):
+
+ status = '303 See Other'
headers = {}
+ result = ''
+ def __init__(self, url):
+ HTTPStatus.__init__(self)
+ self.headers['Location'] = url
-class BadRequest(HTTPError):
+
+class BadRequest(HTTPStatus):
status = '400 Bad Request'
- headers = {}
-class Unauthorized(HTTPError):
+class Unauthorized(HTTPStatus):
status = '401 Unauthorized'
headers = {'WWW-Authenticate': 'Sugar'}
-class Forbidden(HTTPError):
+class Forbidden(HTTPStatus):
status = '403 Forbidden'
- headers = {}
-class NotFound(HTTPError):
+class NotFound(HTTPStatus):
status = '404 Not Found'
- headers = {}
class Request(threading.local):
diff --git a/restful_document/router.py b/restful_document/router.py
index 5848dd0..486d52a 100644
--- a/restful_document/router.py
+++ b/restful_document/router.py
@@ -49,6 +49,7 @@ class Router(object):
env.request.method, env.request.url,
env.request.content or '(no sent data)')
+ result = None
try:
_authenticate()
@@ -63,16 +64,18 @@ class Router(object):
util.exception()
env.responce.status = env.Forbidden.status
env.responce.update(env.Forbidden.headers)
- elif isinstance(error, env.HTTPError):
+ elif isinstance(error, env.HTTPStatus):
env.responce.status = error.status
- env.responce.update(error.headers)
+ env.responce.update(error.headers or {})
+ result = error.result
else:
util.exception(_('Error while processing "%s" request'),
env.request.url)
env.responce.status = '500 Internal Server Error'
- env.responce['Content-Type'] = 'application/json'
- result = {'error': str(error), 'request': env.request.url}
+ if result is None:
+ env.responce['Content-Type'] = 'application/json'
+ result = {'error': str(error), 'request': env.request.url}
start_response(env.responce.status, env.responce.items())
if isinstance(result, types.GeneratorType):
diff --git a/restful_document/user.py b/restful_document/user.py
index d7d46d5..d584d5f 100644
--- a/restful_document/user.py
+++ b/restful_document/user.py
@@ -27,7 +27,7 @@ from restful_document import env
from restful_document.document import Document, restful_method
-_logger = logging.getLogger('sugar_stats')
+_logger = logging.getLogger('rd.user')
class User(Document):