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