# HG changeset patch # User paulb # Date 1080253225 0 # Node ID 2eaaace1680e21683d3e2971f6ac53d93b0ca7ce # Parent 54ea1aac563e69d9f3925cc66bcf78231bbf1642 [project @ 2004-03-25 22:20:25 by paulb] Added unsuccessful JavaServlet features. Added a note about header values when retrieved for all headers. diff -r 54ea1aac563e -r 2eaaace1680e WebStack/BaseHTTPRequestHandler.py --- a/WebStack/BaseHTTPRequestHandler.py Thu Mar 25 22:19:41 2004 +0000 +++ b/WebStack/BaseHTTPRequestHandler.py Thu Mar 25 22:20:25 2004 +0000 @@ -71,6 +71,8 @@ """ A framework-specific method which returns all request headers. + NOTE: If duplicate header names are permitted, then this interface will + NOTE: need to change. """ return self.trans.headers diff -r 54ea1aac563e -r 2eaaace1680e WebStack/JavaServlet.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebStack/JavaServlet.py Thu Mar 25 22:20:25 2004 +0000 @@ -0,0 +1,263 @@ +#!/usr/bin/env python + +""" +Java Servlet classes. +""" + +import Generic +from StringIO import StringIO + +class Stream: + + """ + Wrapper around java.io.BufferedReader. + """ + + def __init__(self, stream): + + "Initialise the stream with the given underlying 'stream'." + + self.stream = stream + + def read(self): + + "Read the entire message, returning it as a string." + + characters = StringIO() + while 1: + c = self.stream.read() + if c == -1: + return characters.getvalue() + else: + characters.write(chr(c)) + + def readline(self): + + "Read a line from the stream, returning it as a string." + + return self.stream.readLine() + +class Transaction(Generic.Transaction): + + """ + Java Servlet transaction interface. + """ + + def __init__(self, request, response): + + """ + Initialise the transaction using the Java Servlet HTTP 'request' and + 'response'. + """ + + self.request = request + self.response = response + self.status = None + + # Request-related methods. + + def get_request_stream(self): + + """ + A framework-specific method which returns the request stream for + the transaction. + """ + + return Stream(self.request.getReader()) + + def get_request_method(self): + + """ + A framework-specific method which gets the request method. + """ + + return self.request.getMethod() + + def get_headers(self): + + """ + A framework-specific method which returns all request headers. + NOTE: If duplicate header names are permitted, then this interface will + NOTE: need to change. + """ + + headers = {} + header_names = self.request.getHeaderNames() + if header_names: + for header_name in header_names: + + # NOTE: Retrieve only a single value (not using getHeaders). + + headers[header_name] = self.request.getHeader(header_name) + + return headers + + def get_header_values(self, key): + + """ + A framework-specific method which returns a list of all request header + values associated with the given 'key'. Note that according to RFC 2616, + 'key' is treated as a case-insensitive string. + """ + + return self.request.getHeaders(key) + + def get_content_type(self): + + """ + A framework-specific method which gets the content type specified on the + request, along with the charset employed. + """ + + content_types = self.get_header_values("Content-Type") + if len(content_types) >= 1: + return self.parse_content_type(content_types[0]) + else: + return None + + def get_content_charsets(self): + + """ + Returns the character set preferences. + """ + + accept_charsets = self.get_header_values("Accept-Charset") + if len(accept_charsets) >= 1: + return self.parse_content_preferences(accept_charsets[0]) + else: + return None + + def get_content_languages(self): + + """ + A framework-specific method which extracts language information from + the transaction. + """ + + accept_languages = self.get_header_values("Accept-Language") + if len(accept_languages) >= 1: + return self.parse_content_preferences(accept_languages[0]) + else: + return None + + def get_path(self): + + """ + A framework-specific method which gets the entire path from the request. + """ + + return self.request.getServletPath() + + def get_path_info(self): + + """ + A framework-specific method which gets the "path info" (the part of the + URL after the resource name handling the current request) from the + request. + """ + + return self.request.getPathInfo() + + def get_query_string(self): + + """ + A framework-specific method which gets the query string from the path in + the request. + """ + + return self.request.getQueryString() + + # Higher level request-related methods. + + def get_fields_from_path(self): + + """ + A framework-specific method which extracts the form fields from the + path specified in the transaction. The underlying framework may refuse + to supply fields from the path if handling a POST transaction. + + Returns a dictionary mapping field names to lists of values (even if a + single value is associated with any given field name). + + NOTE: There may not be a reliable means of extracting only the fields + NOTE: from the path. + """ + + return self.get_fields_from_body() + + def get_fields_from_body(self): + + """ + A framework-specific method which extracts the form fields from the + message body in the transaction. + + Returns a dictionary mapping field names to lists of values (even if a + single value is associated with any given field name). + + NOTE: There may not be a reliable means of extracting only the fields + NOTE: from the message body. + """ + + parameter_map = self.request.getParameterMap() + fields = {} + for key in parameter_map.keySet(): + fields[key] = parameter_map[key] + return fields + + def get_user(self): + + """ + A framework-specific method which extracts user information from the + transaction. + """ + + return self.request.getRemoteUser() + + # Response-related methods. + + def get_response_stream(self): + + """ + A framework-specific method which returns the response stream for + the transaction. + """ + + return self.response.getWriter() + + def get_response_code(self): + + """ + Get the response code associated with the transaction. If no response + code is defined, None is returned. + """ + + return self.status + + def set_response_code(self, response_code): + + """ + Set the 'response_code' using a numeric constant defined in the HTTP + specification. + """ + + self.status = response_code + self.response.setStatus(self.status) + + def set_header_value(self, header, value): + + """ + Set the HTTP 'header' with the given 'value'. + """ + + self.response.setHeader(self.format_header_value(header), self.format_header_value(value)) + + def set_content_type(self, content_type): + + """ + A framework-specific method which sets the 'content_type' for the + response. + """ + + return self.response.setHeader("Content-Type", self.format_content_type(content_type)) + +# vim: tabstop=4 expandtab shiftwidth=4 diff -r 54ea1aac563e -r 2eaaace1680e WebStack/ModPython.py --- a/WebStack/ModPython.py Thu Mar 25 22:19:41 2004 +0000 +++ b/WebStack/ModPython.py Thu Mar 25 22:20:25 2004 +0000 @@ -44,6 +44,8 @@ """ A framework-specific method which returns all request headers. + NOTE: If duplicate header names are permitted, then this interface will + NOTE: need to change. """ return self.trans.headers_in diff -r 54ea1aac563e -r 2eaaace1680e WebStack/Twisted.py --- a/WebStack/Twisted.py Thu Mar 25 22:19:41 2004 +0000 +++ b/WebStack/Twisted.py Thu Mar 25 22:20:25 2004 +0000 @@ -43,6 +43,8 @@ """ A framework-specific method which returns all request headers. + NOTE: If duplicate header names are permitted, then this interface will + NOTE: need to change. """ return self.trans.received_headers diff -r 54ea1aac563e -r 2eaaace1680e WebStack/Webware.py --- a/WebStack/Webware.py Thu Mar 25 22:19:41 2004 +0000 +++ b/WebStack/Webware.py Thu Mar 25 22:20:25 2004 +0000 @@ -55,11 +55,21 @@ """ A framework-specific method which returns all request headers. + NOTE: If duplicate header names are permitted, then this interface will + NOTE: need to change. """ - # NOTE: Webware doesn't really provide access to headers in the request. + # Use the Webware environment and some assumptions about variable names. + # NOTE: Using lower case for the header names. - return {} + env = self.trans.request().environ() + headers = {} + for cgi_key, value in env.items(): + if cgi_key.startswith("HTTP_"): + header_name = cgi_key[len("HTTP_"):].replace("_", "-").lower() + headers[header_name] = value + + return headers def get_header_values(self, key): @@ -69,9 +79,14 @@ 'key' is treated as a case-insensitive string. """ - # NOTE: Webware doesn't really provide access to headers in the request. + # Use the Webware environment and some assumptions about variable names. - return [] + env = self.trans.request().environ() + cgi_key = "HTTP_" + key.replace("-", "_").upper() + if env.has_key(cgi_key): + return [env[cgi_key]] + else: + return [] def get_content_type(self): @@ -117,10 +132,7 @@ request. """ - # NOTE: Webware does not seem to prefix the "path info" in a way - # NOTE: consistent with the other frameworks. - - return "/" + self.trans.request().pathInfo() + return self.trans.request().extraURLPath() def get_query_string(self):