1 #!/usr/bin/env python 2 3 """ 4 Webware classes. 5 """ 6 7 import Generic 8 from cgi import parse_qs 9 import StringIO 10 11 class Transaction(Generic.Transaction): 12 13 """ 14 Webware transaction interface. 15 """ 16 17 def __init__(self, trans): 18 19 "Initialise the transaction using the Webware transaction 'trans'." 20 21 self.trans = trans 22 23 # Request-related methods. 24 25 def get_request_stream(self): 26 27 """ 28 A framework-specific method which returns the request stream for 29 the transaction. 30 """ 31 32 request = self.trans.request() 33 try: 34 stream = request.rawInput(rewind=1) 35 if stream is None: 36 return StringIO.StringIO("") 37 38 # NOTE: Dubious catch-all situation, but it is difficult to control 39 # NOTE: cases where Webware's internals themselves fail. 40 41 except: 42 return StringIO.StringIO("") 43 44 return stream 45 46 def get_request_method(self): 47 48 """ 49 A framework-specific method which gets the request method. 50 """ 51 52 return self.trans.request().method() 53 54 def get_headers(self): 55 56 """ 57 A framework-specific method which returns all request headers. 58 NOTE: If duplicate header names are permitted, then this interface will 59 NOTE: need to change. 60 """ 61 62 # Use the Webware environment and some assumptions about variable names. 63 # NOTE: Using lower case for the header names. 64 65 env = self.trans.request().environ() 66 headers = {} 67 for cgi_key, value in env.items(): 68 if cgi_key.startswith("HTTP_"): 69 header_name = cgi_key[len("HTTP_"):].replace("_", "-").lower() 70 headers[header_name] = value 71 72 return headers 73 74 def get_header_values(self, key): 75 76 """ 77 A framework-specific method which returns a list of all request header 78 values associated with the given 'key'. Note that according to RFC 2616, 79 'key' is treated as a case-insensitive string. 80 """ 81 82 # Use the Webware environment and some assumptions about variable names. 83 84 env = self.trans.request().environ() 85 cgi_key = "HTTP_" + key.replace("-", "_").upper() 86 if env.has_key(cgi_key): 87 return [env[cgi_key]] 88 else: 89 return [] 90 91 def get_content_type(self): 92 93 """ 94 A framework-specific method which gets the content type specified on the 95 request, along with the charset employed. 96 """ 97 98 return self.parse_content_type(self.trans.request().contentType()) 99 100 def get_content_charsets(self): 101 102 """ 103 Returns the character set preferences. 104 NOTE: Requires enhancements to HTTPRequest. 105 """ 106 107 return self.trans.request().contentCharsets() 108 109 def get_content_languages(self): 110 111 """ 112 A framework-specific method which extracts language information from 113 the transaction. 114 NOTE: Requires enhancements to HTTPRequest. 115 """ 116 117 return self.trans.request().contentLanguages() 118 119 def get_path(self): 120 121 """ 122 A framework-specific method which gets the entire path from the request. 123 """ 124 125 return self.trans.request().uri() 126 127 def get_path_info(self): 128 129 """ 130 A framework-specific method which gets the "path info" (the part of the 131 URL after the resource name handling the current request) from the 132 request. 133 """ 134 135 return self.trans.request().extraURLPath() 136 137 def get_query_string(self): 138 139 """ 140 A framework-specific method which gets the query string from the path in 141 the request. 142 """ 143 144 return self.trans.request().queryString() 145 146 # Higher level request-related methods. 147 148 def get_fields_from_path(self): 149 150 """ 151 A framework-specific method which extracts the form fields from the 152 path specified in the transaction. The underlying framework may refuse 153 to supply fields from the path if handling a POST transaction. 154 155 Returns a dictionary mapping field names to lists of values (even if a 156 single value is associated with any given field name). 157 """ 158 159 return parse_qs(self.get_query_string(), keep_blank_values=1) 160 161 def get_fields_from_body(self): 162 163 """ 164 A framework-specific method which extracts the form fields from the 165 message body in the transaction. 166 167 Returns a dictionary mapping field names to lists of values (even if a 168 single value is associated with any given field name). 169 """ 170 171 # Fix the non-list results. 172 173 fields = {} 174 for field_name, field_value in self.trans.request().fields().items(): 175 if type(field_value) == type([]): 176 fields[field_name] = field_value 177 else: 178 fields[field_name] = [field_value] 179 return fields 180 181 def get_user(self): 182 183 """ 184 A framework-specific method which extracts user information from the 185 transaction. 186 """ 187 188 # NOTE: Webware relies entirely on a CGI-style environment where the 189 # NOTE: actual headers are not available. Therefore, the Web server must 190 # NOTE: itself be set up to provide user support. 191 192 try: 193 return self.trans.request().remoteUser() 194 except KeyError, exc: 195 return None 196 197 # Response-related methods. 198 199 def get_response_stream(self): 200 201 """ 202 A framework-specific method which returns the response stream for 203 the transaction. 204 """ 205 206 return self.trans.response() 207 208 def get_response_code(self): 209 210 """ 211 Get the response code associated with the transaction. If no response 212 code is defined, None is returned. 213 """ 214 215 # NOTE: Webware treats the response code as just another header. 216 217 status = self.trans.response().header("Status", None) 218 try: 219 if status is not None: 220 return int(status) 221 else: 222 return None 223 except ValueError: 224 return None 225 226 def set_response_code(self, response_code): 227 228 """ 229 Set the 'response_code' using a numeric constant defined in the HTTP 230 specification. 231 """ 232 233 self.trans.response().setStatus(response_code) 234 235 def set_header_value(self, header, value): 236 237 """ 238 Set the HTTP 'header' with the given 'value'. 239 """ 240 241 self.trans.response().setHeader(self.format_header_value(header), self.format_header_value(value)) 242 243 def set_content_type(self, content_type): 244 245 """ 246 A framework-specific method which sets the 'content_type' for the 247 response. 248 """ 249 250 return self.trans.response().setHeader("Content-Type", self.format_content_type(content_type)) 251 252 # vim: tabstop=4 expandtab shiftwidth=4