@@ -27,6 +27,7 @@ from nilmdb.server.serverutil import ( | |||
json_error_page, | |||
cherrypy_start, | |||
cherrypy_stop, | |||
bool_param, | |||
) | |||
# Add CORS_allow tool | |||
@@ -221,6 +222,8 @@ class Stream(NilmApp): | |||
little-endian and matches the database types (including an | |||
int64 timestamp). | |||
""" | |||
binary = bool_param(binary) | |||
# Important that we always read the input before throwing any | |||
# errors, to keep lengths happy for persistent connections. | |||
# Note that CherryPy 3.2.2 has a bug where this fails for GET | |||
@@ -345,6 +348,10 @@ class Stream(NilmApp): | |||
little-endian and matches the database types (including an | |||
int64 timestamp). | |||
""" | |||
binary = bool_param(binary) | |||
markup = bool_param(markup) | |||
count = bool_param(count) | |||
(start, end) = self._get_times(start, end) | |||
# Check path and get layout | |||
@@ -7,6 +7,21 @@ import os | |||
import decorator | |||
import simplejson as json | |||
# Helper to parse parameters into booleans | |||
def bool_param(s): | |||
"""Return a bool indicating whether parameter 's' was True or False, | |||
supporting a few different types for 's'.""" | |||
try: | |||
ss = s.lower() | |||
if ss in [ "0", "false", "f", "no", "n" ]: | |||
return False | |||
if ss in [ "1", "true", "t", "yes", "y" ]: | |||
return True | |||
except Exception: | |||
return bool(s) | |||
raise cherrypy.HTTPError("400 Bad Request", | |||
"can't parse parameter: " + ss) | |||
# Decorators | |||
def chunked_response(func): | |||
"""Decorator to enable chunked responses.""" | |||
@@ -1,7 +1,14 @@ | |||
import sys | |||
if sys.version_info[0] >= 3: # pragma: no cover (future Python3 compat) | |||
text_type = str | |||
else: | |||
text_type = unicode | |||
def encode(u): | |||
"""Try to encode something from Unicode to a string using the | |||
default encoding. If it fails, try encoding as UTF-8.""" | |||
if not isinstance(u, unicode): | |||
if not isinstance(u, text_type): | |||
return u | |||
try: | |||
return u.encode() | |||
@@ -11,7 +18,7 @@ def encode(u): | |||
def decode(s): | |||
"""Try to decode someting from string to Unicode using the | |||
default encoding. If it fails, try decoding as UTF-8.""" | |||
if isinstance(s, unicode): | |||
if isinstance(s, text_type): | |||
return s | |||
try: | |||
return s.decode() | |||
@@ -392,27 +392,38 @@ class TestClient(object): | |||
headers()) | |||
# Extract | |||
x = http.get("stream/extract", | |||
{ "path": "/newton/prep", | |||
"start": "123", | |||
"end": "124" }) | |||
x = http.get("stream/extract", { "path": "/newton/prep", | |||
"start": "123", "end": "124" }) | |||
if "transfer-encoding: chunked" not in headers(): | |||
warnings.warn("Non-chunked HTTP response for /stream/extract") | |||
if "content-type: text/plain;charset=utf-8" not in headers(): | |||
raise AssertionError("/stream/extract is not text/plain:\n" + | |||
headers()) | |||
x = http.get("stream/extract", | |||
{ "path": "/newton/prep", | |||
"start": "123", | |||
"end": "124", | |||
"binary": "1" }) | |||
x = http.get("stream/extract", { "path": "/newton/prep", | |||
"start": "123", "end": "124", | |||
"binary": "1" }) | |||
if "transfer-encoding: chunked" not in headers(): | |||
warnings.warn("Non-chunked HTTP response for /stream/extract") | |||
if "content-type: application/octet-stream" not in headers(): | |||
raise AssertionError("/stream/extract is not binary:\n" + | |||
headers()) | |||
# Make sure a binary of "0" is really off | |||
x = http.get("stream/extract", { "path": "/newton/prep", | |||
"start": "123", "end": "124", | |||
"binary": "0" }) | |||
if "content-type: application/octet-stream" in headers(): | |||
raise AssertionError("/stream/extract is not text:\n" + | |||
headers()) | |||
# Invalid parameters | |||
with assert_raises(ClientError) as e: | |||
x = http.get("stream/extract", { "path": "/newton/prep", | |||
"start": "123", "end": "124", | |||
"binary": "asdfasfd" }) | |||
in_("can't parse parameter", str(e.exception)) | |||
client.close() | |||
def test_client_08_unicode(self): | |||