1 #!/usr/bin/env python 2 3 """ 4 mod_python classes. 5 """ 6 7 import Generic 8 from mod_python.util import parse_qs, FieldStorage 9 from mod_python import apache 10 try: 11 from mod_python import Cookie 12 except ImportError: 13 # NOTE: Should provide an alternative implementation. 14 Cookie = None 15 16 class Transaction(Generic.Transaction): 17 18 """ 19 mod_python transaction interface. 20 """ 21 22 def __init__(self, trans): 23 24 "Initialise the transaction using the mod_python transaction 'trans'." 25 26 self.trans = trans 27 self.response_code = apache.OK 28 self.user = None 29 30 # Cached information. 31 32 self.storage_body = None 33 34 # Request-related methods. 35 36 def get_request_stream(self): 37 38 """ 39 A framework-specific method which returns the request stream for 40 the transaction. 41 """ 42 43 return self.trans 44 45 def get_request_method(self): 46 47 """ 48 A framework-specific method which gets the request method. 49 """ 50 51 return self.trans.method 52 53 def get_headers(self): 54 55 """ 56 A framework-specific method which returns all request headers as a 57 dictionary-like object mapping header names to values. 58 NOTE: If duplicate header names are permitted, then this interface will 59 NOTE: need to change. 60 """ 61 62 return self.trans.headers_in 63 64 def get_header_values(self, key): 65 66 """ 67 A framework-specific method which returns a list of all request header 68 values associated with the given 'key'. Note that according to RFC 2616, 69 'key' is treated as a case-insensitive string. 70 """ 71 72 return self.convert_to_list(self.trans.headers_in.get(key)) 73 74 def get_content_type(self): 75 76 """ 77 A framework-specific method which gets the content type specified on the 78 request, along with the charset employed. 79 """ 80 81 return self.parse_content_type(self.trans.content_type) 82 83 def get_content_charsets(self): 84 85 """ 86 Returns the character set preferences. 87 """ 88 89 return self.parse_content_preferences(self.trans.headers_in.get("Accept-Charset")) 90 91 def get_content_languages(self): 92 93 """ 94 A framework-specific method which extracts language information from 95 the transaction. 96 """ 97 98 return self.parse_content_preferences(self.trans.headers_in.get("Accept-Language")) 99 100 def get_path(self): 101 102 """ 103 A framework-specific method which gets the entire path from the request. 104 """ 105 106 query_string = self.get_query_string() 107 if query_string: 108 return self.trans.uri + "?" + query_string 109 else: 110 return self.trans.uri 111 112 def get_path_without_query(self): 113 114 """ 115 A framework-specific method which gets the entire path from the request 116 minus the query string. 117 """ 118 119 return self.trans.uri 120 121 def get_path_info(self): 122 123 """ 124 A framework-specific method which gets the "path info" (the part of the 125 URL after the resource name handling the current request) from the 126 request. 127 """ 128 129 return self.trans.path_info 130 131 def get_query_string(self): 132 133 """ 134 A framework-specific method which gets the query string from the path in 135 the request. 136 """ 137 138 return self.trans.args or "" 139 140 # Higher level request-related methods. 141 142 def get_fields_from_path(self): 143 144 """ 145 A framework-specific method which extracts the form fields from the 146 path specified in the transaction. The underlying framework may refuse 147 to supply fields from the path if handling a POST transaction. 148 149 Returns a dictionary mapping field names to lists of values (even if a 150 single value is associated with any given field name). 151 """ 152 153 return parse_qs(self.get_query_string(), 1) # keep_blank_values=1 154 155 def get_fields_from_body(self): 156 157 """ 158 A framework-specific method which extracts the form fields from the 159 message body in the transaction. 160 161 Returns a dictionary mapping field names to lists of values (even if a 162 single value is associated with any given field name). 163 164 The mod_python.util.FieldStorage class may augment the fields from the 165 body with fields found in the path. 166 """ 167 168 if self.storage_body is None: 169 self.storage_body = FieldStorage(self.trans, keep_blank_values=1) 170 171 # Traverse the storage, finding each field value. 172 173 fields = {} 174 for field in self.storage_body.list: 175 if not fields.has_key(field.name): 176 fields[field.name] = [] 177 fields[field.name].append(field.value) 178 return fields 179 180 def get_user(self): 181 182 """ 183 A framework-specific method which extracts user information from the 184 transaction. 185 186 Returns a username as a string or None if no user is defined. 187 """ 188 189 if self.user is not None: 190 return self.user 191 else: 192 return self.trans.user 193 194 def get_cookies(self): 195 196 """ 197 A framework-specific method which obtains cookie information from the 198 request. 199 200 Returns a dictionary mapping cookie names to cookie objects. 201 202 NOTE: No additional information is passed to the underlying API despite 203 NOTE: support for enhanced cookies in mod_python. 204 """ 205 206 if Cookie: 207 return Cookie.get_cookies(self.trans) 208 else: 209 return None 210 211 def get_cookie(self, cookie_name): 212 213 """ 214 A framework-specific method which obtains cookie information from the 215 request. 216 217 Returns a cookie object for the given 'cookie_name' or None if no such 218 cookie exists. 219 """ 220 221 return self.get_cookies().get(cookie_name) 222 223 # Response-related methods. 224 225 def get_response_stream(self): 226 227 """ 228 A framework-specific method which returns the response stream for 229 the transaction. 230 """ 231 232 return self.trans 233 234 def get_response_code(self): 235 236 """ 237 Get the response code associated with the transaction. If no response 238 code is defined, None is returned. 239 """ 240 241 return self.response_code 242 243 def set_response_code(self, response_code): 244 245 """ 246 Set the 'response_code' using a numeric constant defined in the HTTP 247 specification. 248 """ 249 250 self.response_code = response_code 251 252 def set_header_value(self, header, value): 253 254 """ 255 Set the HTTP 'header' with the given 'value'. 256 """ 257 258 self.trans.headers_out[self.format_header_value(header)] = self.format_header_value(value) 259 260 def set_content_type(self, content_type): 261 262 """ 263 A framework-specific method which sets the 'content_type' for the 264 response. 265 """ 266 267 self.trans.content_type = self.format_content_type(content_type) 268 269 def set_cookie(self, cookie): 270 271 """ 272 A framework-specific method which stores the given 'cookie' object in 273 the response. 274 """ 275 276 if Cookie: 277 Cookie.add_cookie(self.trans, cookie) 278 else: 279 # NOTE: Should raise an exception or provide an implementation. 280 pass 281 282 def set_cookie_value(self, name, value, path=None, expires=None): 283 284 """ 285 A framework-specific method which stores a cookie with the given 'name' 286 and 'value' in the response. 287 288 The optional 'path' is a string which specifies the scope of the cookie, 289 and the optional 'expires' parameter is a value compatible with the 290 time.time function, and indicates the expiry date/time of the cookie. 291 """ 292 293 # NOTE: We just hope that Cookie converts Unicode arguments to US-ASCII. 294 295 if Cookie: 296 cookie = Cookie.Cookie(name, value) 297 if expires is not None: 298 cookie.expires = expires 299 if path is not None: 300 cookie.path = path 301 Cookie.add_cookie(self.trans, cookie) 302 else: 303 # NOTE: Should raise an exception or provide an implementation. 304 pass 305 306 def delete_cookie(self, cookie_name): 307 308 """ 309 A framework-specific method which adds to the response a request that 310 the cookie with the given 'cookie_name' be deleted/discarded by the 311 client. 312 """ 313 314 # Create a special cookie, given that we do not know whether the browser 315 # has been sent the cookie or not. 316 # NOTE: Magic discovered in Webware. 317 318 if Cookie: 319 cookie = Cookie.Cookie(cookie_name, "") 320 cookie.path = "/" 321 cookie.expires = 0 322 cookie.max_age = 0 323 Cookie.add_cookie(self.trans, cookie) 324 else: 325 # NOTE: Should raise an exception or provide an implementation. 326 pass 327 328 # Application-specific methods. 329 330 def set_user(self, username): 331 332 """ 333 An application-specific method which sets the user information with 334 'username' in the transaction. This affects subsequent calls to 335 'get_user'. 336 """ 337 338 self.user = username 339 340 # vim: tabstop=4 expandtab shiftwidth=4