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_info(self): 113 114 """ 115 A framework-specific method which gets the "path info" (the part of the 116 URL after the resource name handling the current request) from the 117 request. 118 """ 119 120 return self.trans.path_info 121 122 def get_query_string(self): 123 124 """ 125 A framework-specific method which gets the query string from the path in 126 the request. 127 """ 128 129 return self.trans.args or "" 130 131 # Higher level request-related methods. 132 133 def get_fields_from_path(self): 134 135 """ 136 A framework-specific method which extracts the form fields from the 137 path specified in the transaction. The underlying framework may refuse 138 to supply fields from the path if handling a POST transaction. 139 140 Returns a dictionary mapping field names to lists of values (even if a 141 single value is associated with any given field name). 142 """ 143 144 return parse_qs(self.get_query_string(), 1) # keep_blank_values=1 145 146 def get_fields_from_body(self): 147 148 """ 149 A framework-specific method which extracts the form fields from the 150 message body in the transaction. 151 152 Returns a dictionary mapping field names to lists of values (even if a 153 single value is associated with any given field name). 154 155 The mod_python.util.FieldStorage class may augment the fields from the 156 body with fields found in the path. 157 """ 158 159 if self.storage_body is None: 160 self.storage_body = FieldStorage(self.trans, keep_blank_values=1) 161 162 # Traverse the storage, finding each field value. 163 164 fields = {} 165 for field in self.storage_body.list: 166 if not fields.has_key(field.name): 167 fields[field.name] = [] 168 fields[field.name].append(field.value) 169 return fields 170 171 def get_user(self): 172 173 """ 174 A framework-specific method which extracts user information from the 175 transaction. 176 177 Returns a username as a string or None if no user is defined. 178 """ 179 180 if self.user is not None: 181 return self.user 182 else: 183 return self.trans.user 184 185 def get_cookies(self): 186 187 """ 188 A framework-specific method which obtains cookie information from the 189 request. 190 191 Returns a dictionary mapping cookie names to cookie objects. 192 193 NOTE: No additional information is passed to the underlying API despite 194 NOTE: support for enhanced cookies in mod_python. 195 """ 196 197 if Cookie: 198 return Cookie.get_cookies(self.trans) 199 else: 200 return None 201 202 def get_cookie(self, cookie_name): 203 204 """ 205 A framework-specific method which obtains cookie information from the 206 request. 207 208 Returns a cookie object for the given 'cookie_name' or None if no such 209 cookie exists. 210 """ 211 212 return self.get_cookies().get(cookie_name) 213 214 # Response-related methods. 215 216 def get_response_stream(self): 217 218 """ 219 A framework-specific method which returns the response stream for 220 the transaction. 221 """ 222 223 return self.trans 224 225 def get_response_code(self): 226 227 """ 228 Get the response code associated with the transaction. If no response 229 code is defined, None is returned. 230 """ 231 232 return self.response_code 233 234 def set_response_code(self, response_code): 235 236 """ 237 Set the 'response_code' using a numeric constant defined in the HTTP 238 specification. 239 """ 240 241 self.response_code = response_code 242 243 def set_header_value(self, header, value): 244 245 """ 246 Set the HTTP 'header' with the given 'value'. 247 """ 248 249 self.trans.headers_out[self.format_header_value(header)] = self.format_header_value(value) 250 251 def set_content_type(self, content_type): 252 253 """ 254 A framework-specific method which sets the 'content_type' for the 255 response. 256 """ 257 258 self.trans.content_type = self.format_content_type(content_type) 259 260 def set_cookie(self, cookie): 261 262 """ 263 A framework-specific method which stores the given 'cookie' object in 264 the response. 265 """ 266 267 if Cookie: 268 Cookie.add_cookie(self.trans, cookie) 269 else: 270 # NOTE: Should raise an exception or provide an implementation. 271 pass 272 273 def set_cookie_value(self, name, value, path=None, expires=None): 274 275 """ 276 A framework-specific method which stores a cookie with the given 'name' 277 and 'value' in the response. 278 279 The optional 'path' is a string which specifies the scope of the cookie, 280 and the optional 'expires' parameter is a value compatible with the 281 time.time function, and indicates the expiry date/time of the cookie. 282 """ 283 284 # NOTE: We just hope that Cookie converts Unicode arguments to US-ASCII. 285 286 if Cookie: 287 cookie = Cookie.Cookie(name, value) 288 if expires is not None: 289 cookie.expires = expires 290 if path is not None: 291 cookie.path = path 292 Cookie.add_cookie(self.trans, cookie) 293 else: 294 # NOTE: Should raise an exception or provide an implementation. 295 pass 296 297 def delete_cookie(self, cookie_name): 298 299 """ 300 A framework-specific method which adds to the response a request that 301 the cookie with the given 'cookie_name' be deleted/discarded by the 302 client. 303 """ 304 305 # Create a special cookie, given that we do not know whether the browser 306 # has been sent the cookie or not. 307 # NOTE: Magic discovered in Webware. 308 309 if Cookie: 310 cookie = Cookie.Cookie(cookie_name, "") 311 cookie.path = "/" 312 cookie.expires = 0 313 cookie.max_age = 0 314 Cookie.add_cookie(self.trans, cookie) 315 else: 316 # NOTE: Should raise an exception or provide an implementation. 317 pass 318 319 # Application-specific methods. 320 321 def set_user(self, username): 322 323 """ 324 An application-specific method which sets the user information with 325 'username' in the transaction. This affects subsequent calls to 326 'get_user'. 327 """ 328 329 self.user = username 330 331 # vim: tabstop=4 expandtab shiftwidth=4