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, encoding=None): 226 227 """ 228 A framework-specific method which extracts the form fields from the 229 message body in the transaction. The optional 'encoding' parameter 230 specifies the character encoding of the message body for cases where no 231 such information is available, but where the default encoding is to be 232 overridden. 233 234 Returns a dictionary mapping field names to lists of values (even if a 235 single value is associated with any given field name). 236 237 NOTE: There may not be a reliable means of extracting only the fields 238 NOTE: from the message body. Moreover, the encoding of the fields may 239 NOTE: not be pertinent. 240 """ 241 242 parameter_map = self.request.getParameterMap() 243 fields = {} 244 for key in parameter_map.keySet(): 245 fields[key] = parameter_map[key] 246 return fields 247 248 def get_user(self): 249 250 """ 251 A framework-specific method which extracts user information from the 252 transaction. 253 254 Returns a username as a string or None if no user is defined. 255 """ 256 257 if self.user is not None: 258 return self.user 259 else: 260 return self.request.getRemoteUser() 261 262 def get_cookies(self): 263 264 """ 265 A framework-specific method which obtains cookie information from the 266 request. 267 268 Returns a dictionary mapping cookie names to cookie objects. 269 """ 270 271 return self.cookies_in 272 273 def get_cookie(self, cookie_name): 274 275 """ 276 A framework-specific method which obtains cookie information from the 277 request. 278 279 Returns a cookie object for the given 'cookie_name' or None if no such 280 cookie exists. 281 """ 282 283 return self.cookies_in.get(cookie_name) 284 285 # Response-related methods. 286 287 def get_response_stream(self): 288 289 """ 290 A framework-specific method which returns the response stream for 291 the transaction. 292 """ 293 294 return self.response.getWriter() 295 296 def get_response_code(self): 297 298 """ 299 Get the response code associated with the transaction. If no response 300 code is defined, None is returned. 301 """ 302 303 return self.status 304 305 def set_response_code(self, response_code): 306 307 """ 308 Set the 'response_code' using a numeric constant defined in the HTTP 309 specification. 310 """ 311 312 self.status = response_code 313 self.response.setStatus(self.status) 314 315 def set_header_value(self, header, value): 316 317 """ 318 Set the HTTP 'header' with the given 'value'. 319 """ 320 321 self.response.setHeader(self.format_header_value(header), self.format_header_value(value)) 322 323 def set_content_type(self, content_type): 324 325 """ 326 A framework-specific method which sets the 'content_type' for the 327 response. 328 """ 329 330 return self.response.setHeader("Content-Type", self.format_content_type(content_type)) 331 332 # Higher level response-related methods. 333 334 def set_cookie(self, cookie): 335 336 """ 337 A framework-specific method which stores the given 'cookie' object in 338 the response. 339 """ 340 341 new_cookie = javax.servlet.http.Cookie(cookie.name, cookie.value) 342 self.response.addCookie(new_cookie) 343 344 def set_cookie_value(self, name, value, path=None, expires=None): 345 346 """ 347 A framework-specific method which stores a cookie with the given 'name' 348 and 'value' in the response. 349 350 The optional 'path' is a string which specifies the scope of the cookie, 351 and the optional 'expires' parameter is a value compatible with the 352 time.time function, and indicates the expiry date/time of the cookie. 353 """ 354 355 cookie = javax.servlet.http.Cookie(name, value) 356 if path is not None: 357 cookie.setPath(path) 358 359 # NOTE: The expires parameter seems not to be supported. 360 361 self.response.addCookie(cookie) 362 363 def delete_cookie(self, cookie_name): 364 365 """ 366 A framework-specific method which adds to the response a request that 367 the cookie with the given 'cookie_name' be deleted/discarded by the 368 client. 369 """ 370 371 # Create a special cookie, given that we do not know whether the browser 372 # has been sent the cookie or not. 373 # NOTE: Magic discovered in Webware. 374 375 cookie = javax.servlet.http.Cookie(cookie_name, "") 376 cookie.setPath("/") 377 cookie.setMaxAge(0) 378 self.response.addCookie(cookie) 379 380 # Application-specific methods. 381 382 def set_user(self, username): 383 384 """ 385 An application-specific method which sets the user information with 386 'username' in the transaction. This affects subsequent calls to 387 'get_user'. 388 """ 389 390 self.user = username 391 392 # vim: tabstop=4 expandtab shiftwidth=4