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