1 #!/usr/bin/env python 2 3 """ 4 Webware classes. 5 """ 6 7 import Generic 8 from cgi import parse_qs 9 import StringIO 10 from Helpers import Environment 11 12 class Transaction(Generic.Transaction): 13 14 """ 15 Webware transaction interface. 16 """ 17 18 def __init__(self, trans): 19 20 "Initialise the transaction using the Webware transaction 'trans'." 21 22 self.trans = trans 23 24 # Request-related methods. 25 26 def get_request_stream(self): 27 28 """ 29 A framework-specific method which returns the request stream for 30 the transaction. 31 """ 32 33 request = self.trans.request() 34 try: 35 stream = request.rawInput(rewind=1) 36 if stream is None: 37 return StringIO.StringIO("") 38 39 # NOTE: Dubious catch-all situation, but it is difficult to control 40 # NOTE: cases where Webware's internals themselves fail. 41 42 except: 43 return StringIO.StringIO("") 44 45 return stream 46 47 def get_request_method(self): 48 49 """ 50 A framework-specific method which gets the request method. 51 """ 52 53 return self.trans.request().method() 54 55 def get_headers(self): 56 57 """ 58 A framework-specific method which returns all request headers as a 59 dictionary-like object mapping header names to values. 60 NOTE: If duplicate header names are permitted, then this interface will 61 NOTE: need to change. 62 """ 63 64 # Use the Webware environment and some assumptions about variable names. 65 # NOTE: Using lower case for the header names. 66 67 env = self.trans.request().environ() 68 return Environment.get_headers(env) 69 70 def get_header_values(self, key): 71 72 """ 73 A framework-specific method which returns a list of all request header 74 values associated with the given 'key'. Note that according to RFC 2616, 75 'key' is treated as a case-insensitive string. 76 """ 77 78 # Use the Webware environment and some assumptions about variable names. 79 80 env = self.trans.request().environ() 81 cgi_key = "HTTP_" + key.replace("-", "_").upper() 82 if env.has_key(cgi_key): 83 return [env[cgi_key]] 84 else: 85 return [] 86 87 def get_content_type(self): 88 89 """ 90 A framework-specific method which gets the content type specified on the 91 request, along with the charset employed. 92 """ 93 94 return self.parse_content_type(self.trans.request().contentType()) 95 96 def get_content_charsets(self): 97 98 """ 99 Returns the character set preferences. 100 NOTE: Requires enhancements to HTTPRequest. 101 """ 102 103 return self.trans.request().contentCharsets() 104 105 def get_content_languages(self): 106 107 """ 108 A framework-specific method which extracts language information from 109 the transaction. 110 NOTE: Requires enhancements to HTTPRequest. 111 """ 112 113 return self.trans.request().contentLanguages() 114 115 def get_path(self): 116 117 """ 118 A framework-specific method which gets the entire path from the request. 119 """ 120 121 return self.trans.request().uri() 122 123 def get_path_info(self): 124 125 """ 126 A framework-specific method which gets the "path info" (the part of the 127 URL after the resource name handling the current request) from the 128 request. 129 """ 130 131 return self.trans.request().extraURLPath() 132 133 def get_query_string(self): 134 135 """ 136 A framework-specific method which gets the query string from the path in 137 the request. 138 """ 139 140 return self.trans.request().queryString() 141 142 # Higher level request-related methods. 143 144 def get_fields_from_path(self): 145 146 """ 147 A framework-specific method which extracts the form fields from the 148 path specified in the transaction. The underlying framework may refuse 149 to supply fields from the path if handling a POST transaction. 150 151 Returns a dictionary mapping field names to lists of values (even if a 152 single value is associated with any given field name). 153 """ 154 155 return parse_qs(self.get_query_string(), keep_blank_values=1) 156 157 def get_fields_from_body(self): 158 159 """ 160 A framework-specific method which extracts the form fields from the 161 message body in the transaction. 162 163 Returns a dictionary mapping field names to lists of values (even if a 164 single value is associated with any given field name). 165 """ 166 167 # Fix the non-list results. 168 169 fields = {} 170 for field_name, field_value in self.trans.request().fields().items(): 171 if type(field_value) == type([]): 172 fields[field_name] = field_value 173 else: 174 fields[field_name] = [field_value] 175 return fields 176 177 def get_user(self): 178 179 """ 180 A framework-specific method which extracts user information from the 181 transaction. 182 183 Returns a username as a string or None if no user is defined. 184 """ 185 186 # NOTE: Webware relies entirely on a CGI-style environment where the 187 # NOTE: actual headers are not available. Therefore, the Web server must 188 # NOTE: itself be set up to provide user support. 189 190 try: 191 return self.trans.request().remoteUser() 192 except KeyError, exc: 193 return None 194 195 # Response-related methods. 196 197 def get_response_stream(self): 198 199 """ 200 A framework-specific method which returns the response stream for 201 the transaction. 202 """ 203 204 return self.trans.response() 205 206 def get_response_code(self): 207 208 """ 209 Get the response code associated with the transaction. If no response 210 code is defined, None is returned. 211 """ 212 213 # NOTE: Webware treats the response code as just another header. 214 215 status = self.trans.response().header("Status", None) 216 try: 217 if status is not None: 218 return int(status) 219 else: 220 return None 221 except ValueError: 222 return None 223 224 def set_response_code(self, response_code): 225 226 """ 227 Set the 'response_code' using a numeric constant defined in the HTTP 228 specification. 229 """ 230 231 self.trans.response().setStatus(response_code) 232 233 def set_header_value(self, header, value): 234 235 """ 236 Set the HTTP 'header' with the given 'value'. 237 """ 238 239 self.trans.response().setHeader(self.format_header_value(header), self.format_header_value(value)) 240 241 def set_content_type(self, content_type): 242 243 """ 244 A framework-specific method which sets the 'content_type' for the 245 response. 246 """ 247 248 return self.trans.response().setHeader("Content-Type", self.format_content_type(content_type)) 249 250 # vim: tabstop=4 expandtab shiftwidth=4