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