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