--- a/web/http_headers.py Wed Mar 12 16:02:44 2014 +0100
+++ b/web/http_headers.py Fri Mar 14 11:20:53 2014 +0100
@@ -8,6 +8,7 @@
from calendar import timegm
import base64
import re
+import urlparse
def dashCapitalize(s):
''' Capitalize a string, making sure to treat - as a word seperator '''
@@ -388,6 +389,35 @@
raise ValueError('single value required, not %s' % seq)
return seq[0]
+def parseHTTPMethod(method):
+ """Ensure a HTTP method is valid according the rfc2616, but extension-method ones"""
+ method = method.strip()
+ if method not in ("OPTIONS", "GET", "HEAD", "POST", "PUT", "DELETE",
+ "TRACE", "CONNECT"):
+ raise ValueError('Unsupported HTTP method %s' % method)
+ return method
+
+def parseAllowOrigin(origin):
+ """Ensure origin is a valid URL-base stuff, or null"""
+ if origin == 'null':
+ return origin
+ p = urlparse.urlparse(origin)
+ if p.params or p.query or p.username or p.path not in ('', '/'):
+ raise ValueError('Incorrect Accept-Control-Allow-Origin value %s' % origin)
+ if p.scheme not in ('http', 'https'):
+ raise ValueError('Unsupported Accept-Control-Allow-Origin URL scheme %s' % origin)
+ if not p.netloc:
+ raise ValueError('Accept-Control-Allow-Origin: host name cannot be unset (%s)' % origin)
+ return origin
+
+def parseAllowCreds(cred):
+ """Can be "true" """
+ if cred:
+ cred = cred.lower()
+ if cred and cred != 'true':
+ raise ValueError('Accept-Control-Allow-Credentials can only be "true" (%s)' % cred)
+ return cred
+
##### Generation utilities
def quoteString(s):
return '"%s"' % s.replace('\\', '\\\\').replace('"', '\\"')
@@ -1454,6 +1484,12 @@
'Accept-Charset': (tokenize, listParser(parseAcceptQvalue), dict, addDefaultCharset),
'Accept-Encoding':(tokenize, listParser(parseAcceptQvalue), dict, addDefaultEncoding),
'Accept-Language':(tokenize, listParser(parseAcceptQvalue), dict),
+ 'Access-Control-Allow-Origin': (last, parseAllowOrigin,),
+ 'Access-Control-Allow-Credentials': (last, parseAllowCreds,),
+ 'Access-Control-Allow-Methods': (tokenize, listParser(parseHTTPMethod), list),
+ 'Access-Control-Request-Method': (parseHTTPMethod, ),
+ 'Access-Control-Request-Headers': (filterTokens, ),
+ 'Access-Control-Expose-Headers': (filterTokens, ),
'Authorization': (last, parseAuthorization),
'Cookie':(parseCookie,),
'Expect':(tokenize, listParser(parseExpect), dict),
@@ -1465,6 +1501,7 @@
'If-Range':(parseIfRange,),
'If-Unmodified-Since':(last,parseDateTime),
'Max-Forwards':(last,int),
+ 'Origin': (last,),
# 'Proxy-Authorization':str, # what is "credentials"
'Range':(tokenize, parseRange),
'Referer':(last,str), # TODO: URI object?
@@ -1477,11 +1514,15 @@
'Accept-Charset': (iteritems, listGenerator(generateAcceptQvalue),singleHeader),
'Accept-Encoding': (iteritems, removeDefaultEncoding, listGenerator(generateAcceptQvalue),singleHeader),
'Accept-Language': (iteritems, listGenerator(generateAcceptQvalue),singleHeader),
+ 'Access-Control-Request-Method': (unique, str, singleHeader, ),
+ 'Access-Control-Expose-Headers': (listGenerator(str), ),
+ 'Access-Control-Allow-Headers': (listGenerator(str), ),
'Authorization': (generateAuthorization,), # what is "credentials"
'Cookie':(generateCookie,singleHeader),
'Expect':(iteritems, listGenerator(generateExpect), singleHeader),
'From':(unique, str,singleHeader),
'Host':(unique, str,singleHeader),
+ 'Origin': (unique, str, singleHeader),
'If-Match':(listGenerator(generateStarOrETag), singleHeader),
'If-Modified-Since':(generateDateTime,singleHeader),
'If-None-Match':(listGenerator(generateStarOrETag), singleHeader),