diff options
author | cce <devnull@localhost> | 2005-12-26 05:18:21 +0000 |
---|---|---|
committer | cce <devnull@localhost> | 2005-12-26 05:18:21 +0000 |
commit | a438d9ab87e23a55b6c73f6919c6c696e2d0ba0b (patch) | |
tree | 7c8b58ff3ba8452e11afe610dababe536b46de3c /paste/httpheaders.py | |
parent | 77ae5e47e7f30637c0063df23d90fd4459960526 (diff) | |
download | paste-a438d9ab87e23a55b6c73f6919c6c696e2d0ba0b.tar.gz |
- making HTTPHeader not be a string object so that it isn't
accidently used as a key in an WSGI or header tuple
- distinguishing between multi-value (but single-line) and
multi-entry headers such as WWW-Authenticate and Set-Cookie
as discussed on the Web-Sig
- removed 'dict' like stuff from environ wrapper so that it
isn't accidently used as an environ replacement
Diffstat (limited to 'paste/httpheaders.py')
-rw-r--r-- | paste/httpheaders.py | 187 |
1 files changed, 103 insertions, 84 deletions
diff --git a/paste/httpheaders.py b/paste/httpheaders.py index 9b3aace..7ca81e8 100644 --- a/paste/httpheaders.py +++ b/paste/httpheaders.py @@ -32,10 +32,13 @@ It is planned that HTTPHeader will grow three methods: a WSGI ``response_headers`` list. """ -__all__ = ['get_header','HTTPHeader' ] +__all__ = ['get_header','known_headers','HTTPHeader' ] _headers = {} +def known_headers(): + return _headers.values() + def get_header(name, raiseError=True): """ This function finds the corresponding ``HTTPHeader`` for the @@ -49,132 +52,148 @@ def get_header(name, raiseError=True): raise NameError(name) return retval -class HTTPHeader(str): +class HTTPHeader(object): """ HTTP header field names in their normalized "common form" as given by their source specification. Constructor Arguments: - ``name`` This is the primary string value of the - header name and is meant to reflect the - "common form" of the header as provided in - its corresponding specification. - - ``category`` The kind of header field, one of: - - ``general`` - - ``request`` - - ``response`` - - ``entity`` - - ``version`` The version of HTTP with which the header - should be recognized (ie, don't send 1.1 - headers to a 1.0 client). - - ``singular`` This is a boolean value that indicates if only - one value for this header is allowed. The - default is ``False`` which allows several. + ``name`` This is the primary string value of the + header name and is meant to reflect the + "common form" of the header as provided in + its corresponding specification. + + ``category`` The kind of header field, one of: + - ``general`` + - ``request`` + - ``response`` + - ``entity`` + Category is there to follow the RFC's suggestion + that general headers go first and entity headers + go last. + + ``version`` The version of HTTP with which the header + should be recognized (ie, don't send 1.1 + headers to a 1.0 client). + + ``style`` The style of the header is one of three forms: + - ``singular`` (one entry, one value) + - ``multi-value`` (one entry, comma separated) + - ``multi-entry`` (values have their own entry) + Style is intended to inform wrappers about the + cardality and storage semantics for the header. The collected versions of initialized header instances are immediately registered and accessable through the ``get_header`` function. """ #@@: add field-name validation - def __new__(cls, name, category, version, singular): + def __new__(cls, name, category, version, style): self = get_header(name, raiseError=False) if self: # Allow the registration to happen again, but assert # that everything is identical. - assert self == name, \ + assert self.name == name, \ "duplicate registration with different capitalization" assert self.category == category, \ "duplicate registration with different category " assert self.version == version, \ "duplicate registration with different HTTP version" - assert self.singular == singular, \ + assert self.style == style, \ "duplicate registration with different value cardnality" assert cls == self.__class__, \ "duplicate registration with different class" else: assert version, "registration requires a HTTP Version" assert isinstance(version,str), "HTTP version is a string" - assert singular in (True,False), "singular must be boolean" - assert category in ('general','request','response','entity') - self = str.__new__(cls, name) + assert category in ('general', 'request', 'response', 'entity') + assert style in ('singular', 'multi-value', 'multi-entry') + self = object.__new__(cls) + self.name = name self.version = version - self.singular = singular + self.style = style self.category = category self._catsort = {'general': 1, 'request': 2, 'response': 2, 'entity': 3}[category] - assert self.lower() not in _headers - _headers[self.lower()] = self + assert self.name.lower() not in _headers + _headers[self.name.lower()] = self return self + def __str__(self): + return self.name + def __lt__(self, other): """ Re-define sorting so that general headers are first, followed by request/response headers, and then entity headers. The list.sort() methods use the less-than operator for this purpose. """ - if isinstance(other,HTTPHeader) and self._catsort != other._catsort: - return self._catsort < other._catsort - return str.__lt__(self, other) - + if isinstance(other,HTTPHeader): + if self._catsort != other._catsort: + return self._catsort < other._catsort + return self.name < other.name + return self.name < other + + def __repr__(self): + return '<%s %s>' % (self.__class__.__name__, self.name) # # For now, construct a minimalistic version of the field-names; at a # later date more complicated headers may sprout content constructors. +# This creates WSGI style HTTP_HEADER_NAME instances of HTTPHeader. # -for (name, category, version, singular, comment) in \ -(("Accept" , 'request' , '1.1', False, 'RFC 2616 $14.1' ) -,("Accept-Charset" , 'request' , '1.1', False, 'RFC 2616 $14.2' ) -,("Accept-Encoding" , 'request' , '1.1', False, 'RFC 2616 $14.3' ) -,("Accept-Language" , 'request' , '1.1', False, 'RFC 2616 $14.4' ) -,("Accept-Ranges" , 'response', '1.1', False, 'RFC 2616 $14.5' ) -,("Age" , 'response', '1.1', True , 'RFC 2616 $14.6' ) -,("Allow" , 'entity' , '1.0', False, 'RFC 2616 $14.7' ) -,("Authorization" , 'request' , '1.0', True , 'RFC 2616 $14.8' ) -,("Cache-Control" , 'general' , '1.1', False, 'RFC 2616 $14.9' ) -,("Cookie" , 'request' , '1.0', False, 'RFC 2109 / Netscape') -,("Connection" , 'general' , '1.1', False, 'RFC 2616 $14.10' ) -,("Content-Encoding" , 'entity' , '1.0', False, 'RFC 2616 $14.11' ) -,("Content-Language" , 'entity' , '1.1', False, 'RFC 2616 $14.12' ) -,("Content-Length" , 'entity' , '1.0', True , 'RFC 2616 $14.13' ) -,("Content-Location" , 'entity' , '1.1', True , 'RFC 2616 $14.14' ) -,("Content-MD5" , 'entity' , '1.1', True , 'RFC 2616 $14.15' ) -,("Content-Range" , 'entity' , '1.1', True , 'RFC 2616 $14.16' ) -,("Content-Type" , 'entity' , '1.0', True , 'RFC 2616 $14.17' ) -,("Date" , 'general' , '1.0', True , 'RFC 2616 $14.18' ) -,("ETag" , 'response', '1.1', True , 'RFC 2616 $14.19' ) -,("Expect" , 'request' , '1.1', False, 'RFC 2616 $14.20' ) -,("Expires" , 'entity' , '1.0', True , 'RFC 2616 $14.21' ) -,("From" , 'request' , '1.0', True , 'RFC 2616 $14.22' ) -,("Host" , 'request' , '1.1', True , 'RFC 2616 $14.23' ) -,("If-Match" , 'request' , '1.1', False, 'RFC 2616 $14.24' ) -,("If-Modified-Since" , 'request' , '1.0', True , 'RFC 2616 $14.25' ) -,("If-None-Match" , 'request' , '1.1', False, 'RFC 2616 $14.26' ) -,("If-Range" , 'request' , '1.1', True , 'RFC 2616 $14.27' ) -,("If-Unmodified-Since" , 'request' , '1.1', True , 'RFC 2616 $14.28' ) -,("Last-Modified" , 'entity' , '1.0', True , 'RFC 2616 $14.29' ) -,("Location" , 'response', '1.0', True , 'RFC 2616 $14.30' ) -,("Max-Forwards" , 'request' , '1.1', True , 'RFC 2616 $14.31' ) -,("Pragma" , 'general' , '1.0', False, 'RFC 2616 $14.32' ) -,("Proxy-Authenticate" , 'response', '1.1', False, 'RFC 2616 $14.33' ) -,("Proxy-Authorization" , 'request' , '1.1', True , 'RFC 2616 $14.34' ) -,("Range" , 'request' , '1.1', False, 'RFC 2616 $14.35' ) -,("Referer" , 'request' , '1.0', True , 'RFC 2616 $14.36' ) -,("Retry-After" , 'response', '1.1', True , 'RFC 2616 $14.37' ) -,("Server" , 'response', '1.0', True , 'RFC 2616 $14.38' ) -,("Set-Cookie" , 'response', '1.0', False, 'RFC 2109 / Netscape') -,("TE" , 'request' , '1.1', False, 'RFC 2616 $14.39' ) -,("Trailer" , 'general' , '1.1', False, 'RFC 2616 $14.40' ) -,("Transfer-Encoding" , 'general' , '1.1', False, 'RFC 2616 $14.41' ) -,("Upgrade" , 'general' , '1.1', False, 'RFC 2616 $14.42' ) -,("User-Agent" , 'request' , '1.0', True , 'RFC 2616 $14.43' ) -,("Vary" , 'response', '1.1', False, 'RFC 2616 $14.44' ) -,("Via" , 'general' , '1.1', False, 'RFC 2616 $14.45' ) -,("Warning" , 'general' , '1.1', False, 'RFC 2616 $14.46' ) -,("WWW-Authenticate" , 'response', '1.0', False, 'RFC 2616 $14.47' )): - head = HTTPHeader(name, category, version, singular) +for (name, category, version, style, comment) in \ +(("Accept" ,'request' ,'1.1','multi-value','RFC 2616 $14.1' ) +,("Accept-Charset" ,'request' ,'1.1','multi-value','RFC 2616 $14.2' ) +,("Accept-Encoding" ,'request' ,'1.1','multi-value','RFC 2616 $14.3' ) +,("Accept-Language" ,'request' ,'1.1','multi-value','RFC 2616 $14.4' ) +,("Accept-Ranges" ,'response','1.1','multi-value','RFC 2616 $14.5' ) +,("Age" ,'response','1.1','singular' ,'RFC 2616 $14.6' ) +,("Allow" ,'entity' ,'1.0','multi-value','RFC 2616 $14.7' ) +,("Authorization" ,'request' ,'1.0','singular' ,'RFC 2616 $14.8' ) +,("Cache-Control" ,'general' ,'1.1','multi-value','RFC 2616 $14.9' ) +,("Cookie" ,'request' ,'1.0','multi-value','RFC 2109/Netscape') +,("Connection" ,'general' ,'1.1','multi-value','RFC 2616 $14.10') +,("Content-Encoding" ,'entity' ,'1.0','multi-value','RFC 2616 $14.11') +,("Content-Language" ,'entity' ,'1.1','multi-value','RFC 2616 $14.12') +,("Content-Length" ,'entity' ,'1.0','singular' ,'RFC 2616 $14.13') +,("Content-Location" ,'entity' ,'1.1','singular' ,'RFC 2616 $14.14') +,("Content-MD5" ,'entity' ,'1.1','singular' ,'RFC 2616 $14.15') +,("Content-Range" ,'entity' ,'1.1','singular' ,'RFC 2616 $14.16') +,("Content-Type" ,'entity' ,'1.0','singular' ,'RFC 2616 $14.17') +,("Date" ,'general' ,'1.0','singular' ,'RFC 2616 $14.18') +,("ETag" ,'response','1.1','singular' ,'RFC 2616 $14.19') +,("Expect" ,'request' ,'1.1','multi-value','RFC 2616 $14.20') +,("Expires" ,'entity' ,'1.0','singular' ,'RFC 2616 $14.21') +,("From" ,'request' ,'1.0','singular' ,'RFC 2616 $14.22') +,("Host" ,'request' ,'1.1','singular' ,'RFC 2616 $14.23') +,("If-Match" ,'request' ,'1.1','multi-value','RFC 2616 $14.24') +,("If-Modified-Since" ,'request' ,'1.0','singular' ,'RFC 2616 $14.25') +,("If-None-Match" ,'request' ,'1.1','multi-value','RFC 2616 $14.26') +,("If-Range" ,'request' ,'1.1','singular' ,'RFC 2616 $14.27') +,("If-Unmodified-Since",'request' ,'1.1','singular' ,'RFC 2616 $14.28') +,("Last-Modified" ,'entity' ,'1.0','singular' ,'RFC 2616 $14.29') +,("Location" ,'response','1.0','singular' ,'RFC 2616 $14.30') +,("Max-Forwards" ,'request' ,'1.1','singular' ,'RFC 2616 $14.31') +,("Pragma" ,'general' ,'1.0','multi-value','RFC 2616 $14.32') +,("Proxy-Authenticate" ,'response','1.1','multi-value','RFC 2616 $14.33') +,("Proxy-Authorization",'request' ,'1.1','singular' ,'RFC 2616 $14.34') +,("Range" ,'request' ,'1.1','multi-value','RFC 2616 $14.35') +,("Referer" ,'request' ,'1.0','singular' ,'RFC 2616 $14.36') +,("Retry-After" ,'response','1.1','singular' ,'RFC 2616 $14.37') +,("Server" ,'response','1.0','singular' ,'RFC 2616 $14.38') +,("Set-Cookie" ,'response','1.0','multi-entry','RFC 2109/Netscape') +,("TE" ,'request' ,'1.1','multi-value','RFC 2616 $14.39') +,("Trailer" ,'general' ,'1.1','multi-value','RFC 2616 $14.40') +,("Transfer-Encoding" ,'general' ,'1.1','multi-value','RFC 2616 $14.41') +,("Upgrade" ,'general' ,'1.1','multi-value','RFC 2616 $14.42') +,("User-Agent" ,'request' ,'1.0','singular' ,'RFC 2616 $14.43') +,("Vary" ,'response','1.1','multi-value','RFC 2616 $14.44') +,("Via" ,'general' ,'1.1','multi-value','RFC 2616 $14.45') +,("Warning" ,'general' ,'1.1','multi-entry','RFC 2616 $14.46') +,("WWW-Authenticate" ,'response','1.0','multi-entry','RFC 2616 $14.47')): + head = HTTPHeader(name, category, version, style) head.__doc__ = comment pyname = 'HTTP_' + name.replace("-","_").upper() locals()[pyname] = head __all__.append(pyname) + |