diff --git a/README.rst b/README.rst
index db75719..3bef411 100644
--- a/README.rst
+++ b/README.rst
@@ -1,3 +1,58 @@
+This is a modified version of itty.py which attempts to add support for the HTTP 'Accept:' request header.
+
+example code:
+
+::
+
+ @get('/')
+ @accept('text/plain')
+ def index(request):
+ return "Hello, World!\n"
+
+ @get('/')
+ @accept('text/xml')
+ def index(request):
+ return 'Hello, World!\n'
+
+ @get('/')
+ @accept('application/json')
+ def index(request):
+ return '{ "greeting": "Hello, World!" }\n'
+
+ @get('/')
+ def index(request):
+ return "
Hello, World!\n"
+
+
+output:
+
+::
+
+ $ wget -q -O - --header='Accept: text/plain' http://localhost:8080
+ Hello, World!
+
+ $ wget -q -O - --header='Accept: text/xml' http://localhost:8080
+ Hello, World!
+
+ $ wget -q -O - --header='Accept: application/json' http://localhost:8080
+ { "greeting": "Hello, World!" }
+
+ $ wget -q -O - --header='Accept: text/html' http://localhost:8080
+ Hello, World!
+
+
+This is just a first stab to flesh out the idea.
+
+Limitations (i.e. things which could be improved upon):
+
+* You have to define your methods in order from most specific to least specific.
+* Wildcards and 'q' aren't supported yet.
+
+Feel free to take this idea and run with it. Have fun!
+Jason Pepas
+jason@pepas.com
+
+
=======
itty.py
=======
diff --git a/itty.py b/itty.py
index d4d179b..4656ff3 100644
--- a/itty.py
+++ b/itty.py
@@ -312,16 +312,37 @@ def handle_error(exception, request=None):
return not_found(request, exception)
+def method_supports_mime_type_in_accept_header(method, accept_string):
+ """Determine if the MIME types supported by the method match those in the Accept header."""
+ if hasattr(method, 'accepted_mime_types') == False:
+ # if an @accept() decorator hasn't been used, we assume */*
+ return True
+
+ parts = accept_string.split(',')
+ mime_types_accepted_by_requester = [part.split(';')[0] for part in parts]
+ for mime_type in mime_types_accepted_by_requester:
+ if mime_type in method.accepted_mime_types:
+ return True
+ return False
+
+
def find_matching_url(request):
"""Searches through the methods who've registed themselves with the HTTP decorators."""
if not request.method in REQUEST_MAPPINGS:
raise NotFound("The HTTP request method '%s' is not supported." % request.method)
- for url_set in REQUEST_MAPPINGS[request.method]:
- match = url_set[0].search(request.path)
+ for method in REQUEST_MAPPINGS[request.method]:
+ match = method.re_url.search(request.path)
- if match is not None:
- return (url_set, match.groupdict())
+ if match == None:
+ continue
+
+ if hasattr(request, 'HTTP_ACCEPT') == True:
+ if method_supports_mime_type_in_accept_header(method, request.HTTP_ACCEPT) == False:
+ continue
+
+ url_set = (method.re_url, method.url, method)
+ return (url_set, match.groupdict())
raise NotFound("Sorry, nothing here.")
@@ -405,8 +426,9 @@ def get(url):
"""Registers a method as capable of processing GET requests."""
def wrapped(method):
# Register.
- re_url = re.compile("^%s$" % add_slash(url))
- REQUEST_MAPPINGS['GET'].append((re_url, url, method))
+ method.url = url
+ method.re_url = re.compile("^%s$" % add_slash(url))
+ REQUEST_MAPPINGS['GET'].append(method)
return method
return wrapped
@@ -415,8 +437,9 @@ def post(url):
"""Registers a method as capable of processing POST requests."""
def wrapped(method):
# Register.
- re_url = re.compile("^%s$" % add_slash(url))
- REQUEST_MAPPINGS['POST'].append((re_url, url, method))
+ method.url = url
+ method.re_url = re.compile("^%s$" % add_slash(url))
+ REQUEST_MAPPINGS['POST'].append(method)
return method
return wrapped
@@ -425,8 +448,9 @@ def put(url):
"""Registers a method as capable of processing PUT requests."""
def wrapped(method):
# Register.
- re_url = re.compile("^%s$" % add_slash(url))
- REQUEST_MAPPINGS['PUT'].append((re_url, url, method))
+ method.url = url
+ method.re_url = re.compile("^%s$" % add_slash(url))
+ REQUEST_MAPPINGS['PUT'].append(method)
new.status = 201
return method
return wrapped
@@ -436,8 +460,9 @@ def delete(url):
"""Registers a method as capable of processing DELETE requests."""
def wrapped(method):
# Register.
- re_url = re.compile("^%s$" % add_slash(url))
- REQUEST_MAPPINGS['DELETE'].append((re_url, url, method))
+ method.url = url
+ method.re_url = re.compile("^%s$" % add_slash(url))
+ REQUEST_MAPPINGS['DELETE'].append(method)
return method
return wrapped
@@ -451,6 +476,16 @@ def wrapped(method):
return wrapped
+def accept(mime_type):
+ """Specifies which MIME types a method handles."""
+ def wrapped(method):
+ if method.__dict__.has_key('accepted_mime_types') is False:
+ method.accepted_mime_types = []
+ method.accepted_mime_types.append(mime_type)
+ return method
+ return wrapped
+
+
# Error handlers
@error(403)