# HG changeset patch # User paulb # Date 1082848118 0 # Node ID 68713268513939dc00fa3982151f45a0cd3e4f7c # Parent e22e5358fd92230be70c9edf846fc67f26873bea [project @ 2004-04-24 23:08:38 by paulb] Improved header handling in BaseHTTPRequestHandler. Added cookie support to various modules. diff -r e22e5358fd92 -r 687132685139 WebStack/BaseHTTPRequestHandler.py --- a/WebStack/BaseHTTPRequestHandler.py Sat Apr 24 20:34:47 2004 +0000 +++ b/WebStack/BaseHTTPRequestHandler.py Sat Apr 24 23:08:38 2004 +0000 @@ -8,6 +8,7 @@ from Helpers.Request import MessageBodyStream from Helpers.Auth import UserInfo from cgi import parse_qs, FieldStorage +import Cookie from StringIO import StringIO class Transaction(Generic.Transaction): @@ -30,7 +31,12 @@ self.content_type = None self.response_code = 200 self.content = StringIO() - self.headers = {} + self.headers_out = {} + self.cookies_out = Cookie.SimpleCookie() + + # Define the incoming cookies. + + self.cookies_in = Cookie.SimpleCookie(self.get_headers().get("cookie")) def commit(self): @@ -42,8 +48,15 @@ self.trans.send_response(self.response_code) if self.content_type is not None: self.trans.send_header("Content-Type", self.format_content_type(self.content_type)) - for header, value in self.headers.items(): + + for header, value in self.headers_out.items(): self.trans.send_header(self.format_header_value(header), self.format_header_value(value)) + + # NOTE: May not be using the appropriate method. + + for morsel in self.cookies_out.values(): + self.trans.send_header("Set-Cookie", morsel.OutputString()) + self.trans.end_headers() self.content.seek(0) self.trans.wfile.write(self.content.read()) @@ -95,8 +108,7 @@ request, along with the charset employed. """ - return self.parse_content_type(self.trans.headers.get("Content-type") or - self.trans.headers.get("Content-Type")) + return self.parse_content_type(self.trans.headers.get("content-type")) def get_content_charsets(self): @@ -104,7 +116,7 @@ Returns the character set preferences. """ - return self.parse_content_preferences(self.trans.headers.get("Accept-Charset")) + return self.parse_content_preferences(self.trans.headers.get("accept-charset")) def get_content_languages(self): @@ -113,7 +125,7 @@ the transaction. """ - return self.parse_content_preferences(self.trans.headers.get("Accept-Language")) + return self.parse_content_preferences(self.trans.headers.get("accept-language")) def get_path(self): @@ -200,12 +212,35 @@ Returns a username as a string or None if no user is defined. """ - auth_header = self.get_headers().get("Authorization") + auth_header = self.get_headers().get("authorization") if auth_header: return UserInfo(auth_header).username else: return None + def get_cookies(self): + + """ + A framework-specific method which obtains cookie information from the + request. + + Returns a dictionary mapping cookie names to cookie objects. + """ + + return self.cookies_in + + def get_cookie(self, cookie_name): + + """ + A framework-specific method which obtains cookie information from the + request. + + Returns a cookie object for the given 'cookie_name' or None if no such + cookie exists. + """ + + return self.cookies_in.get(cookie_name) + # Response-related methods. def get_response_stream(self): @@ -245,7 +280,7 @@ # The header is not written out immediately due to the buffering in use. - self.headers[header] = value + self.headers_out[header] = value def set_content_type(self, content_type): @@ -260,4 +295,50 @@ self.content_type = content_type + def set_cookie(self, cookie): + + """ + A framework-specific method which stores the given 'cookie' object in + the response. + """ + + # NOTE: If multiple cookies of the same name could be specified, this + # NOTE: could need changing. + + self.cookies_out[cookie.name] = cookie.value + + def set_cookie_value(self, name, value, path=None, expires=None): + + """ + A framework-specific method which stores a cookie with the given 'name' + and 'value' in the response. + + The optional 'path' is a string which specifies the scope of the cookie, + and the optional 'expires' parameter is a value compatible with the + time.time function, and indicates the expiry date/time of the cookie. + """ + + self.cookies_out[name] = value + if path is not None: + self.cookies_out[name]["path"] = path + if expires is not None: + self.cookies_out[name]["expires"] = expires + + def delete_cookie(self, cookie_name): + + """ + A framework-specific method which adds to the response a request that + the cookie with the given 'cookie_name' be deleted/discarded by the + client. + """ + + # Create a special cookie, given that we do not know whether the browser + # has been sent the cookie or not. + # NOTE: Magic discovered in Webware. + + self.cookies_out[cookie_name] = "" + self.cookies_out[cookie_name]["path"] = "/" + self.cookies_out[cookie_name]["expires"] = 0 + self.cookies_out[cookie_name]["max-age"] = 0 + # vim: tabstop=4 expandtab shiftwidth=4 diff -r e22e5358fd92 -r 687132685139 WebStack/Generic.py --- a/WebStack/Generic.py Sat Apr 24 20:34:47 2004 +0000 +++ b/WebStack/Generic.py Sat Apr 24 23:08:38 2004 +0000 @@ -145,7 +145,8 @@ def get_headers(self): """ - A framework-specific method which returns all request headers. + A framework-specific method which returns all request headers as a + dictionary-like object mapping header names to values. """ raise NotImplementedError, "get_headers" @@ -245,6 +246,8 @@ """ A framework-specific method which extracts user information from the transaction. + + Returns a username as a string or None if no user is defined. """ raise NotImplementedError, "get_user" diff -r e22e5358fd92 -r 687132685139 WebStack/JavaServlet.py --- a/WebStack/JavaServlet.py Sat Apr 24 20:34:47 2004 +0000 +++ b/WebStack/JavaServlet.py Sat Apr 24 23:08:38 2004 +0000 @@ -6,6 +6,8 @@ import Generic from StringIO import StringIO +from Helpers.Request import Cookie +import javax.servlet.http.Cookie class Stream: @@ -54,6 +56,14 @@ self.response = response self.status = None + # Remember the cookies received in the request. + # NOTE: Discarding much of the information received. + + self.cookies_in = {} + for cookie in self.request.getCookies(): + cookie_name = cookie.getName() + self.cookies_in[cookie_name] = Cookie(cookie_name, cookie.getValue()) + def commit(self): """ @@ -225,6 +235,29 @@ return self.request.getRemoteUser() + def get_cookies(self): + + """ + A framework-specific method which obtains cookie information from the + request. + + Returns a dictionary mapping cookie names to cookie objects. + """ + + return self.cookies_in + + def get_cookie(self, cookie_name): + + """ + A framework-specific method which obtains cookie information from the + request. + + Returns a cookie object for the given 'cookie_name' or None if no such + cookie exists. + """ + + return self.cookies_in.get(cookie_name) + # Response-related methods. def get_response_stream(self): @@ -272,4 +305,52 @@ return self.response.setHeader("Content-Type", self.format_content_type(content_type)) + # Higher level response-related methods. + + def set_cookie(self, cookie): + + """ + A framework-specific method which stores the given 'cookie' object in + the response. + """ + + new_cookie = javax.servlet.http.Cookie(cookie.name, cookie.value) + self.response.addCookie(new_cookie) + + def set_cookie_value(self, name, value, path=None, expires=None): + + """ + A framework-specific method which stores a cookie with the given 'name' + and 'value' in the response. + + The optional 'path' is a string which specifies the scope of the cookie, + and the optional 'expires' parameter is a value compatible with the + time.time function, and indicates the expiry date/time of the cookie. + """ + + cookie = javax.servlet.http.Cookie(name, value) + if path is not None: + cookie.setPath(path) + + # NOTE: The expires parameter seems not to be supported. + + self.response.addCookie(cookie) + + def delete_cookie(self, cookie_name): + + """ + A framework-specific method which adds to the response a request that + the cookie with the given 'cookie_name' be deleted/discarded by the + client. + """ + + # Create a special cookie, given that we do not know whether the browser + # has been sent the cookie or not. + # NOTE: Magic discovered in Webware. + + cookie = javax.servlet.http.Cookie(cookie_name, "") + cookie.setPath("/") + cookie.setMaxAge(0) + self.response.addCookie(cookie) + # vim: tabstop=4 expandtab shiftwidth=4 diff -r e22e5358fd92 -r 687132685139 WebStack/Webware.py --- a/WebStack/Webware.py Sat Apr 24 20:34:47 2004 +0000 +++ b/WebStack/Webware.py Sat Apr 24 23:08:38 2004 +0000 @@ -8,6 +8,7 @@ from cgi import parse_qs import StringIO from Helpers import Environment +from Helpers.Request import Cookie class Transaction(Generic.Transaction): @@ -192,6 +193,35 @@ except KeyError, exc: return None + def get_cookies(self): + + """ + A framework-specific method which obtains cookie information from the + request. + + Returns a dictionary mapping cookie names to cookie objects. + """ + + cookies = {} + for name, value in self.trans.request().cookies().items(): + cookies[name] = Cookie(name, value) + return cookies + + def get_cookie(self, cookie_name): + + """ + A framework-specific method which obtains cookie information from the + request. + + Returns a cookie object for the given 'cookie_name' or None if no such + cookie exists. + """ + + try: + return Cookie(cookie_name, self.trans.request().cookie(cookie_name)) + except KeyError: + return None + # Response-related methods. def get_response_stream(self): @@ -247,4 +277,38 @@ return self.trans.response().setHeader("Content-Type", self.format_content_type(content_type)) + # Higher level response-related methods. + + def set_cookie(self, cookie): + + """ + A framework-specific method which stores the given 'cookie' object in + the response. + """ + + self.trans.response().addCookie(cookie) + + def set_cookie_value(self, name, value, path=None, expires=None): + + """ + A framework-specific method which stores a cookie with the given 'name' + and 'value' in the response. + + The optional 'path' is a string which specifies the scope of the cookie, + and the optional 'expires' parameter is a value compatible with the + time.time function, and indicates the expiry date/time of the cookie. + """ + + self.trans.response().setCookie(name, value, path, expires) + + def delete_cookie(self, cookie_name): + + """ + A framework-specific method which adds to the response a request that + the cookie with the given 'cookie_name' be deleted/discarded by the + client. + """ + + self.trans.response().delCookie(cookie_name) + # vim: tabstop=4 expandtab shiftwidth=4