# Copyright (C) 2013 Connor Hudson, Tim Radvan
"""Module for writing Snap! extensions.
See example.py for usage.
Handler functions should return unicode. Non-unicode strings are assumed to
be UTF-8 encoded.
"""
__version__ = '0.1.4'
import inspect
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
from urlparse import urlsplit, parse_qs
from SimpleHTTPServer import SimpleHTTPRequestHandler
from SocketServer import TCPServer
class SnapHandler(SimpleHTTPRequestHandler):
"""An HTTP handler with Flask-style routing."""
routes = {}
special = {
'true': True,
'True': True,
'false': False,
'False': False,
}
@classmethod
def prettify_arg(cls, value):
value = value.decode('utf-8')
value = cls.special.get(value, value)
if isinstance(value, bool):
return value
try:
return int(value)
except ValueError:
try:
return float(value)
except ValueError:
return value # str
def send_head(self):
split_url = urlsplit(self.path)
path = split_url.path
params = parse_qs(split_url.query)
params = dict((k, self.prettify_arg(v[0])) for (k, v) in params.items())
print 'params', params
is_browser = "text/html" in self.headers['Accept']
(status, mime_type, response) = self.get_response(path, params,
is_browser)
if isinstance(response, str):
response = response.decode('utf-8')
else:
response = unicode(response)
if is_browser and mime_type == "text/plain":
mime_type = "text/html"
response = u"""{response}""".format(title=path, response=response)
if isinstance(response, unicode):
response = response.encode('utf-8')
self.send_response(status)
self.send_header("Content-Type", mime_type)
self.send_header("Content-Length", str(len(response)))
self.send_header("Access-Control-Allow-Origin", "*")
self.end_headers()
return StringIO(response)
def get_response(self, path, params, is_browser):
mime_type = "text/plain"
if path in self.routes:
f = self.routes[path]
try:
response = f(**params)
if response is None:
response = ""
elif response is True:
response = "true"
elif response is False:
response = "false"
return (200, mime_type, response)
except KeyboardInterrupt:
raise
except TypeError, e:
for param in inspect.getargspec(f).args:
if param not in params:
response = "ERROR: Missing argument %r" % param
return (400, mime_type, response)
else:
raise
elif path == '/':
return self.index(is_browser)
elif path == '/crossdomain.xml':
return """