1 #!/usr/bin/env python 2 3 """ 4 Twisted classes. 5 """ 6 7 import Generic 8 from Helpers.Auth import UserInfo 9 from cgi import parse_qs 10 11 class Transaction(Generic.Transaction): 12 13 """ 14 Twisted transaction interface. 15 """ 16 17 def __init__(self, trans): 18 19 "Initialise the transaction using the Twisted transaction 'trans'." 20 21 self.trans = trans 22 23 # Request-related methods. 24 25 def get_request_stream(self): 26 27 """ 28 A framework-specific method which returns the request stream for 29 the transaction. 30 """ 31 32 return self.trans.content 33 34 def get_request_method(self): 35 36 """ 37 A framework-specific method which gets the request method. 38 """ 39 40 return self.trans.method 41 42 def get_headers(self): 43 44 """ 45 A framework-specific method which returns all request headers. 46 """ 47 48 return self.trans.received_headers 49 50 def get_header_values(self, key): 51 52 """ 53 A framework-specific method which returns a list of all request header 54 values associated with the given 'key'. Note that according to RFC 2616, 55 'key' is treated as a case-insensitive string. 56 """ 57 58 # Twisted does not convert the header key to lower case (which is the 59 # stored representation). 60 61 return self.convert_to_list(self.trans.received_headers.get(key.lower())) 62 63 def get_content_type(self): 64 65 """ 66 A framework-specific method which gets the content type specified on the 67 request, along with the charset employed. 68 """ 69 70 return self.parse_content_type(self.trans.getHeader("Content-Type")) 71 72 def get_content_charsets(self): 73 74 """ 75 Returns the character set preferences. 76 """ 77 78 return self.parse_content_preferences(self.trans.getHeader("Accept-Language")) 79 80 def get_content_languages(self): 81 82 """ 83 A framework-specific method which extracts language information from 84 the transaction. 85 """ 86 87 return self.parse_content_preferences(self.trans.getHeader("Accept-Charset")) 88 89 def get_path(self): 90 91 """ 92 A framework-specific method which gets the entire path from the request. 93 """ 94 95 return self.trans.uri 96 97 def get_path_info(self): 98 99 """ 100 A framework-specific method which gets the "path info" (the part of the 101 URL after the resource name handling the current request) from the 102 request. 103 """ 104 105 return "/%s" % "/".join(self.trans.postpath) 106 107 def get_query_string(self): 108 109 """ 110 A framework-specific method which gets the query string from the path in 111 the request. 112 """ 113 114 t = self.get_path().split("?") 115 if len(t) == 1: 116 return "" 117 else: 118 119 # NOTE: Overlook erroneous usage of "?" characters in the path. 120 121 return "?".join(t[1:]) 122 123 # Higher level request-related methods. 124 125 def get_fields_from_path(self): 126 127 """ 128 A framework-specific method which extracts the form fields from the 129 path specified in the transaction. The underlying framework may refuse 130 to supply fields from the path if handling a POST transaction. 131 132 Returns a dictionary mapping field names to lists of values (even if a 133 single value is associated with any given field name). 134 """ 135 136 return parse_qs(self.get_query_string(), keep_blank_values=1) 137 138 def get_fields_from_body(self): 139 140 """ 141 A framework-specific method which extracts the form fields from the 142 message body in the transaction. 143 144 The returned object should employ the cgi.FieldStorage interface. 145 """ 146 147 # NOTE: May need a wrapper around this object. 148 149 return self.trans.args 150 151 def get_fields(self): 152 153 """ 154 A framework-specific method which extracts the form fields from the 155 transaction. Typically, the origin of the form fields will be affected 156 by the method specified in the transaction. 157 158 The returned object should employ the cgi.FieldStorage interface. 159 """ 160 161 # NOTE: May need a wrapper around this object. 162 163 return self.trans.args 164 165 def get_user(self): 166 167 """ 168 A framework-specific method which extracts user information from the 169 transaction. 170 """ 171 172 # NOTE: Twisted makes headers lower case, for some reason. 173 174 auth_header = self.get_headers().get("authorization") 175 if auth_header: 176 return UserInfo(auth_header).username 177 else: 178 return None 179 180 # Response-related methods. 181 182 def get_response_stream(self): 183 184 """ 185 A framework-specific method which returns the response stream for 186 the transaction. 187 """ 188 189 return self.trans 190 191 def get_response_code(self): 192 193 """ 194 Get the response code associated with the transaction. If no response 195 code is defined, None is returned. 196 """ 197 198 # NOTE: Accessing the request attribute directly. 199 200 return self.trans.code 201 202 def set_response_code(self, response_code): 203 204 """ 205 Set the 'response_code' using a numeric constant defined in the HTTP 206 specification. 207 """ 208 209 self.trans.setResponseCode(response_code) 210 211 def set_header_value(self, header, value): 212 213 """ 214 Set the HTTP 'header' with the given 'value'. 215 """ 216 217 self.trans.setHeader(self.format_header_value(header), self.format_header_value(value)) 218 219 def set_content_type(self, content_type): 220 221 """ 222 A framework-specific method which sets the 'content_type' for the 223 response. 224 """ 225 226 self.trans.setHeader("Content-Type", self.format_content_type(content_type)) 227 228 # vim: tabstop=4 expandtab shiftwidth=4