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 # NOTE: To be verified. 171 172 path = self.get_path_without_query() 173 qs = self.get_query_string() 174 if qs: 175 path += "?" 176 path += qs 177 return path 178 179 def get_path_without_query(self): 180 181 """ 182 A framework-specific method which gets the entire path from the request 183 minus the query string. 184 """ 185 186 return self.request.getServletPath() 187 188 def get_path_info(self): 189 190 """ 191 A framework-specific method which gets the "path info" (the part of the 192 URL after the resource name handling the current request) from the 193 request. 194 """ 195 196 return self.request.getPathInfo() 197 198 def get_query_string(self): 199 200 """ 201 A framework-specific method which gets the query string from the path in 202 the request. 203 """ 204 205 return self.request.getQueryString() 206 207 # Higher level request-related methods. 208 209 def get_fields_from_path(self): 210 211 """ 212 A framework-specific method which extracts the form fields from the 213 path specified in the transaction. The underlying framework may refuse 214 to supply fields from the path if handling a POST transaction. 215 216 Returns a dictionary mapping field names to lists of values (even if a 217 single value is associated with any given field name). 218 219 NOTE: There may not be a reliable means of extracting only the fields 220 NOTE: from the path. 221 """ 222 223 return self.get_fields_from_body() 224 225 def get_fields_from_body(self): 226 227 """ 228 A framework-specific method which extracts the form fields from the 229 message body in the transaction. 230 231 Returns a dictionary mapping field names to lists of values (even if a 232 single value is associated with any given field name). 233 234 NOTE: There may not be a reliable means of extracting only the fields 235 NOTE: from the message body. 236 """ 237 238 parameter_map = self.request.getParameterMap() 239 fields = {} 240 for key in parameter_map.keySet(): 241 fields[key] = parameter_map[key] 242 return fields 243 244 def get_user(self): 245 246 """ 247 A framework-specific method which extracts user information from the 248 transaction. 249 250 Returns a username as a string or None if no user is defined. 251 """ 252 253 if self.user is not None: 254 return self.user 255 else: 256 return self.request.getRemoteUser() 257 258 def get_cookies(self): 259 260 """ 261 A framework-specific method which obtains cookie information from the 262 request. 263 264 Returns a dictionary mapping cookie names to cookie objects. 265 """ 266 267 return self.cookies_in 268 269 def get_cookie(self, cookie_name): 270 271 """ 272 A framework-specific method which obtains cookie information from the 273 request. 274 275 Returns a cookie object for the given 'cookie_name' or None if no such 276 cookie exists. 277 """ 278 279 return self.cookies_in.get(cookie_name) 280 281 # Response-related methods. 282 283 def get_response_stream(self): 284 285 """ 286 A framework-specific method which returns the response stream for 287 the transaction. 288 """ 289 290 return self.response.getWriter() 291 292 def get_response_code(self): 293 294 """ 295 Get the response code associated with the transaction. If no response 296 code is defined, None is returned. 297 """ 298 299 return self.status 300 301 def set_response_code(self, response_code): 302 303 """ 304 Set the 'response_code' using a numeric constant defined in the HTTP 305 specification. 306 """ 307 308 self.status = response_code 309 self.response.setStatus(self.status) 310 311 def set_header_value(self, header, value): 312 313 """ 314 Set the HTTP 'header' with the given 'value'. 315 """ 316 317 self.response.setHeader(self.format_header_value(header), self.format_header_value(value)) 318 319 def set_content_type(self, content_type): 320 321 """ 322 A framework-specific method which sets the 'content_type' for the 323 response. 324 """ 325 326 return self.response.setHeader("Content-Type", self.format_content_type(content_type)) 327 328 # Higher level response-related methods. 329 330 def set_cookie(self, cookie): 331 332 """ 333 A framework-specific method which stores the given 'cookie' object in 334 the response. 335 """ 336 337 new_cookie = javax.servlet.http.Cookie(cookie.name, cookie.value) 338 self.response.addCookie(new_cookie) 339 340 def set_cookie_value(self, name, value, path=None, expires=None): 341 342 """ 343 A framework-specific method which stores a cookie with the given 'name' 344 and 'value' in the response. 345 346 The optional 'path' is a string which specifies the scope of the cookie, 347 and the optional 'expires' parameter is a value compatible with the 348 time.time function, and indicates the expiry date/time of the cookie. 349 """ 350 351 cookie = javax.servlet.http.Cookie(name, value) 352 if path is not None: 353 cookie.setPath(path) 354 355 # NOTE: The expires parameter seems not to be supported. 356 357 self.response.addCookie(cookie) 358 359 def delete_cookie(self, cookie_name): 360 361 """ 362 A framework-specific method which adds to the response a request that 363 the cookie with the given 'cookie_name' be deleted/discarded by the 364 client. 365 """ 366 367 # Create a special cookie, given that we do not know whether the browser 368 # has been sent the cookie or not. 369 # NOTE: Magic discovered in Webware. 370 371 cookie = javax.servlet.http.Cookie(cookie_name, "") 372 cookie.setPath("/") 373 cookie.setMaxAge(0) 374 self.response.addCookie(cookie) 375 376 # Application-specific methods. 377 378 def set_user(self, username): 379 380 """ 381 An application-specific method which sets the user information with 382 'username' in the transaction. This affects subsequent calls to 383 'get_user'. 384 """ 385 386 self.user = username 387 388 # vim: tabstop=4 expandtab shiftwidth=4