1 #!/usr/bin/env python 2 3 """ 4 Java Servlet classes. 5 """ 6 7 import Generic 8 from StringIO import StringIO 9 from Helpers.Request import Cookie 10 import javax.servlet.http.Cookie 11 12 class Stream: 13 14 """ 15 Wrapper around java.io.BufferedReader. 16 """ 17 18 def __init__(self, stream): 19 20 "Initialise the stream with the given underlying 'stream'." 21 22 self.stream = stream 23 24 def read(self): 25 26 "Read the entire message, returning it as a string." 27 28 characters = StringIO() 29 while 1: 30 c = self.stream.read() 31 if c == -1: 32 return characters.getvalue() 33 else: 34 characters.write(chr(c)) 35 36 def readline(self): 37 38 "Read a line from the stream, returning it as a string." 39 40 return self.stream.readLine() 41 42 class Transaction(Generic.Transaction): 43 44 """ 45 Java Servlet transaction interface. 46 """ 47 48 def __init__(self, request, response): 49 50 """ 51 Initialise the transaction using the Java Servlet HTTP 'request' and 52 'response'. 53 """ 54 55 self.request = request 56 self.response = response 57 self.status = None 58 self.user = None 59 60 # Remember the cookies received in the request. 61 # NOTE: Discarding much of the information received. 62 63 self.cookies_in = {} 64 for cookie in self.request.getCookies(): 65 cookie_name = cookie.getName() 66 self.cookies_in[cookie_name] = Cookie(cookie_name, cookie.getValue()) 67 68 def commit(self): 69 70 """ 71 A special method, synchronising the transaction with framework-specific 72 objects. 73 """ 74 75 self.get_response_stream().close() 76 77 # Request-related methods. 78 79 def get_request_stream(self): 80 81 """ 82 A framework-specific method which returns the request stream for 83 the transaction. 84 """ 85 86 return Stream(self.request.getReader()) 87 88 def get_request_method(self): 89 90 """ 91 A framework-specific method which gets the request method. 92 """ 93 94 return self.request.getMethod() 95 96 def get_headers(self): 97 98 """ 99 A framework-specific method which returns all request headers as a 100 dictionary-like object mapping header names to values. 101 NOTE: If duplicate header names are permitted, then this interface will 102 NOTE: need to change. 103 """ 104 105 headers = {} 106 header_names = self.request.getHeaderNames() 107 if header_names: 108 for header_name in header_names: 109 110 # NOTE: Retrieve only a single value (not using getHeaders). 111 112 headers[header_name] = self.request.getHeader(header_name) 113 114 return headers 115 116 def get_header_values(self, key): 117 118 """ 119 A framework-specific method which returns a list of all request header 120 values associated with the given 'key'. Note that according to RFC 2616, 121 'key' is treated as a case-insensitive string. 122 """ 123 124 return self.request.getHeaders(key) 125 126 def get_content_type(self): 127 128 """ 129 A framework-specific method which gets the content type specified on the 130 request, along with the charset employed. 131 """ 132 133 content_types = self.get_header_values("Content-Type") 134 if len(content_types) >= 1: 135 return self.parse_content_type(content_types[0]) 136 else: 137 return None 138 139 def get_content_charsets(self): 140 141 """ 142 Returns the character set preferences. 143 """ 144 145 accept_charsets = self.get_header_values("Accept-Charset") 146 if len(accept_charsets) >= 1: 147 return self.parse_content_preferences(accept_charsets[0]) 148 else: 149 return None 150 151 def get_content_languages(self): 152 153 """ 154 A framework-specific method which extracts language information from 155 the transaction. 156 """ 157 158 accept_languages = self.get_header_values("Accept-Language") 159 if len(accept_languages) >= 1: 160 return self.parse_content_preferences(accept_languages[0]) 161 else: 162 return None 163 164 def get_path(self): 165 166 """ 167 A framework-specific method which gets the entire path from the request. 168 """ 169 170 return self.request.getServletPath() 171 172 def get_path_info(self): 173 174 """ 175 A framework-specific method which gets the "path info" (the part of the 176 URL after the resource name handling the current request) from the 177 request. 178 """ 179 180 return self.request.getPathInfo() 181 182 def get_query_string(self): 183 184 """ 185 A framework-specific method which gets the query string from the path in 186 the request. 187 """ 188 189 return self.request.getQueryString() 190 191 # Higher level request-related methods. 192 193 def get_fields_from_path(self): 194 195 """ 196 A framework-specific method which extracts the form fields from the 197 path specified in the transaction. The underlying framework may refuse 198 to supply fields from the path if handling a POST transaction. 199 200 Returns a dictionary mapping field names to lists of values (even if a 201 single value is associated with any given field name). 202 203 NOTE: There may not be a reliable means of extracting only the fields 204 NOTE: from the path. 205 """ 206 207 return self.get_fields_from_body() 208 209 def get_fields_from_body(self): 210 211 """ 212 A framework-specific method which extracts the form fields from the 213 message body in the transaction. 214 215 Returns a dictionary mapping field names to lists of values (even if a 216 single value is associated with any given field name). 217 218 NOTE: There may not be a reliable means of extracting only the fields 219 NOTE: from the message body. 220 """ 221 222 parameter_map = self.request.getParameterMap() 223 fields = {} 224 for key in parameter_map.keySet(): 225 fields[key] = parameter_map[key] 226 return fields 227 228 def get_user(self): 229 230 """ 231 A framework-specific method which extracts user information from the 232 transaction. 233 234 Returns a username as a string or None if no user is defined. 235 """ 236 237 if self.user is not None: 238 return self.user 239 else: 240 return self.request.getRemoteUser() 241 242 def get_cookies(self): 243 244 """ 245 A framework-specific method which obtains cookie information from the 246 request. 247 248 Returns a dictionary mapping cookie names to cookie objects. 249 """ 250 251 return self.cookies_in 252 253 def get_cookie(self, cookie_name): 254 255 """ 256 A framework-specific method which obtains cookie information from the 257 request. 258 259 Returns a cookie object for the given 'cookie_name' or None if no such 260 cookie exists. 261 """ 262 263 return self.cookies_in.get(cookie_name) 264 265 # Response-related methods. 266 267 def get_response_stream(self): 268 269 """ 270 A framework-specific method which returns the response stream for 271 the transaction. 272 """ 273 274 return self.response.getWriter() 275 276 def get_response_code(self): 277 278 """ 279 Get the response code associated with the transaction. If no response 280 code is defined, None is returned. 281 """ 282 283 return self.status 284 285 def set_response_code(self, response_code): 286 287 """ 288 Set the 'response_code' using a numeric constant defined in the HTTP 289 specification. 290 """ 291 292 self.status = response_code 293 self.response.setStatus(self.status) 294 295 def set_header_value(self, header, value): 296 297 """ 298 Set the HTTP 'header' with the given 'value'. 299 """ 300 301 self.response.setHeader(self.format_header_value(header), self.format_header_value(value)) 302 303 def set_content_type(self, content_type): 304 305 """ 306 A framework-specific method which sets the 'content_type' for the 307 response. 308 """ 309 310 return self.response.setHeader("Content-Type", self.format_content_type(content_type)) 311 312 # Higher level response-related methods. 313 314 def set_cookie(self, cookie): 315 316 """ 317 A framework-specific method which stores the given 'cookie' object in 318 the response. 319 """ 320 321 new_cookie = javax.servlet.http.Cookie(cookie.name, cookie.value) 322 self.response.addCookie(new_cookie) 323 324 def set_cookie_value(self, name, value, path=None, expires=None): 325 326 """ 327 A framework-specific method which stores a cookie with the given 'name' 328 and 'value' in the response. 329 330 The optional 'path' is a string which specifies the scope of the cookie, 331 and the optional 'expires' parameter is a value compatible with the 332 time.time function, and indicates the expiry date/time of the cookie. 333 """ 334 335 cookie = javax.servlet.http.Cookie(name, value) 336 if path is not None: 337 cookie.setPath(path) 338 339 # NOTE: The expires parameter seems not to be supported. 340 341 self.response.addCookie(cookie) 342 343 def delete_cookie(self, cookie_name): 344 345 """ 346 A framework-specific method which adds to the response a request that 347 the cookie with the given 'cookie_name' be deleted/discarded by the 348 client. 349 """ 350 351 # Create a special cookie, given that we do not know whether the browser 352 # has been sent the cookie or not. 353 # NOTE: Magic discovered in Webware. 354 355 cookie = javax.servlet.http.Cookie(cookie_name, "") 356 cookie.setPath("/") 357 cookie.setMaxAge(0) 358 self.response.addCookie(cookie) 359 360 # Application-specific methods. 361 362 def set_user(self, username): 363 364 """ 365 An application-specific method which sets the user information with 366 'username' in the transaction. This affects subsequent calls to 367 'get_user'. 368 """ 369 370 self.user = username 371 372 # vim: tabstop=4 expandtab shiftwidth=4