diff options
author | Aleksey Lim <alsroot@sugarlabs.org> | 2012-03-19 22:54:32 (GMT) |
---|---|---|
committer | Aleksey Lim <alsroot@sugarlabs.org> | 2012-03-19 22:54:32 (GMT) |
commit | e0a8b9cf85310707f4ecd2a39b777bf7391c2596 (patch) | |
tree | a5ea028acf076224dbdd12375d297623c233ae00 | |
parent | 09341fe15e9bfff10bc357dcabeee915ced76d9d (diff) |
Tune BLOBs support:
* handle streams;
* upload with url;
* download redirect.
-rw-r--r-- | restful_document/__init__.py | 2 | ||||
-rw-r--r-- | restful_document/document.py | 29 | ||||
-rw-r--r-- | restful_document/env.py | 27 | ||||
-rw-r--r-- | restful_document/router.py | 11 | ||||
-rw-r--r-- | restful_document/user.py | 2 |
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): |