Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/sugar_network/toolkit
diff options
context:
space:
mode:
Diffstat (limited to 'sugar_network/toolkit')
-rw-r--r--sugar_network/toolkit/__init__.py42
-rw-r--r--sugar_network/toolkit/http.py10
-rw-r--r--sugar_network/toolkit/router.py107
3 files changed, 74 insertions, 85 deletions
diff --git a/sugar_network/toolkit/__init__.py b/sugar_network/toolkit/__init__.py
index 4088e07..073ec4d 100644
--- a/sugar_network/toolkit/__init__.py
+++ b/sugar_network/toolkit/__init__.py
@@ -450,45 +450,6 @@ def svg_to_png(data, w, h):
return result
-class File(dict):
-
- AWAY = None
-
- def __init__(self, path=None, meta=None, digest=None):
- self.path = path
- self.digest = digest
- dict.__init__(self, meta or {})
- self._stat = None
- self._name = self.get('filename')
-
- @property
- def size(self):
- if self._stat is None:
- self._stat = os.stat(self.path)
- return self._stat.st_size
-
- @property
- def mtime(self):
- if self._stat is None:
- self._stat = os.stat(self.path)
- return int(self._stat.st_mtime)
-
- @property
- def name(self):
- if self._name is None:
- self._name = self.get('name') or self.digest or 'blob'
- mime_type = self.get('mime_type')
- if mime_type:
- import mimetypes
- if not mimetypes.inited:
- mimetypes.init()
- self._name += mimetypes.guess_extension(mime_type) or ''
- return self._name
-
- def __repr__(self):
- return '<File path=%r digest=%r>' % (self.path, self.digest)
-
-
def TemporaryFile(*args, **kwargs):
if 'dir' not in kwargs:
kwargs['dir'] = cachedir.value
@@ -843,6 +804,3 @@ def _nb_read(stream):
return ''
finally:
fcntl.fcntl(fd, fcntl.F_SETFL, orig_flags)
-
-
-File.AWAY = File()
diff --git a/sugar_network/toolkit/http.py b/sugar_network/toolkit/http.py
index 8d913ae..47f13bc 100644
--- a/sugar_network/toolkit/http.py
+++ b/sugar_network/toolkit/http.py
@@ -142,7 +142,7 @@ class Connection(object):
request = Request(method='HEAD', path=path_, **kwargs)
response = Response()
self.call(request, response)
- return response.meta
+ return response
def get(self, path_=None, query_=None, **kwargs):
reply = self.request('GET', path_, params=query_ or kwargs)
@@ -274,13 +274,11 @@ class Connection(object):
if 'transfer-encoding' in reply.headers:
# `requests` library handles encoding on its own
del reply.headers['transfer-encoding']
- for key, value in reply.headers.items():
- if key.startswith('x-sn-'):
- response.meta[key[5:]] = json.loads(value)
- elif not resend:
- response[key] = value
if resend:
response.relocations += 1
+ else:
+ for key, value in reply.headers.items():
+ response[key] = value
if not resend:
break
path = reply.headers['location']
diff --git a/sugar_network/toolkit/router.py b/sugar_network/toolkit/router.py
index b37eee4..00e5d8a 100644
--- a/sugar_network/toolkit/router.py
+++ b/sugar_network/toolkit/router.py
@@ -346,15 +346,35 @@ class Request(dict):
(self.method, self.path, self.cmd, dict(self))
-class Response(dict):
+class CaseInsensitiveDict(dict):
+
+ def __contains__(self, key):
+ return dict.__contains__(self, key.lower())
+
+ def __getitem__(self, key):
+ return self.get(key.lower())
+
+ def __setitem__(self, key, value):
+ return self.set(key.lower(), value)
+
+ def __delitem__(self, key, value):
+ self.remove(key.lower())
+
+ def get(self, key):
+ return dict.get(self, key)
+
+ def set(self, key, value):
+ dict.__setitem__(self, key, value)
+
+ def remove(self, key):
+ dict.__delitem__(self, key)
+
+
+class Response(CaseInsensitiveDict):
status = '200 OK'
relocations = 0
- def __init__(self, **kwargs):
- dict.__init__(self, kwargs)
- self.meta = {}
-
@property
def content_length(self):
return int(self.get('content-length') or '0')
@@ -394,26 +414,47 @@ class Response(dict):
return result
def __repr__(self):
- items = ['%s=%r' % i for i in self.items() + self.meta.items()]
+ items = ['%s=%r' % i for i in self.items()]
return '<Response %r>' % items
- def __contains__(self, key):
- dict.__contains__(self, key.lower())
- def __getitem__(self, key):
- return self.get(key.lower())
+class File(CaseInsensitiveDict):
- def __setitem__(self, key, value):
- return self.set(key.lower(), value)
+ AWAY = None
- def __delitem__(self, key, value):
- self.remove(key.lower())
+ class Digest(str):
+ pass
- def set(self, key, value):
- dict.__setitem__(self, key, value)
+ def __init__(self, path, digest=None, meta=None):
+ CaseInsensitiveDict.__init__(self)
+ self.path = path
+ self.digest = File.Digest(digest) if digest else None
+ if meta is not None:
+ for key, value in meta:
+ self[key] = value
+ self._stat = None
- def remove(self, key):
- dict.__delitem__(self, key)
+ @property
+ def size(self):
+ if self._stat is None:
+ self._stat = os.stat(self.path)
+ return self._stat.st_size
+
+ @property
+ def mtime(self):
+ if self._stat is None:
+ self._stat = os.stat(self.path)
+ return int(self._stat.st_mtime)
+
+ @property
+ def url(self):
+ if self is File.AWAY:
+ return ''
+ return self.get('location') or \
+ '%s/blobs/%s' % (this.request.static_prefix, self.digest)
+
+ def __repr__(self):
+ return '<File %r>' % self.url
class Router(object):
@@ -530,11 +571,8 @@ class Router(object):
except Exception, exception:
raise
else:
- if not response.content_type:
- if isinstance(result, toolkit.File):
- response.content_type = result.get('mime_type')
- if not response.content_type:
- response.content_type = route_.mime_type
+ if route_.mime_type and 'content-type' not in response:
+ response.set('content-type', route_.mime_type)
finally:
for i in self._postroutes:
i(request, response, result, exception)
@@ -563,18 +601,14 @@ class Router(object):
result = self.call(request, response)
- if isinstance(result, toolkit.File):
- if 'url' in result:
- raise http.Redirect(result['url'])
+ if isinstance(result, File):
+ response.update(result)
+ if 'location' in result:
+ raise http.Redirect(result['location'])
enforce(isfile(result.path), 'No such file')
- if request.if_modified_since and result.mtime and \
+ if request.if_modified_since and \
result.mtime <= request.if_modified_since:
raise http.NotModified()
- response.last_modified = result.mtime
- response.content_type = result.get('mime_type') or \
- 'application/octet-stream'
- response['Content-Disposition'] = \
- 'attachment; filename="%s"' % result.name
result = file(result.path, 'rb')
if not hasattr(result, 'read'):
@@ -592,7 +626,6 @@ class Router(object):
response.status = error.status
if error.headers:
response.update(error.headers)
- response.content_type = None
except Exception, error:
toolkit.exception('Error while processing %r request', request.url)
if isinstance(error, http.Status):
@@ -601,7 +634,7 @@ class Router(object):
else:
response.status = '500 Internal Server Error'
if request.method == 'HEAD':
- response.meta['error'] = str(error)
+ response.status = response.status[:4] + str(error)
else:
content = {'error': str(error), 'request': request.url}
response.content_type = 'application/json'
@@ -623,9 +656,6 @@ class Router(object):
if 'content-length' not in response:
response.content_length = len(content) if content else 0
- for key, value in response.meta.items():
- response.set('X-SN-%s' % toolkit.ascii(key), json.dumps(value))
-
if request.method == 'HEAD' and content is not None:
_logger.warning('Content from HEAD response is ignored')
content = None
@@ -859,3 +889,6 @@ class _Authorization(str):
password = None
signature = None
nonce = None
+
+
+File.AWAY = File(None)