1 #!/usr/bin/env python 2 3 """ 4 BaseHTTPRequestHandler classes. 5 """ 6 7 import Generic 8 from Helpers.Request import MessageBodyStream 9 from Helpers.Auth import UserInfo 10 from cgi import FieldStorage 11 from StringIO import StringIO 12 13 class Transaction(Generic.Transaction): 14 15 """ 16 BaseHTTPRequestHandler transaction interface. 17 """ 18 19 def __init__(self, trans): 20 21 """ 22 Initialise the transaction using the BaseHTTPRequestHandler instance 23 'trans'. 24 """ 25 26 self.trans = trans 27 28 # Other attributes of interest in instances of this class. 29 30 self.content_type = None 31 self.response_code = 200 32 self.content = StringIO() 33 self.headers = {} 34 35 def commit(self): 36 37 """ 38 A special method, synchronising the transaction with framework-specific 39 objects. 40 """ 41 42 self.trans.send_response(self.response_code) 43 if self.content_type is not None: 44 self.trans.send_header("Content-Type", self.format_content_type(self.content_type)) 45 for header, value in self.headers.items(): 46 self.trans.send_header(self.format_header_value(header), self.format_header_value(value)) 47 self.trans.end_headers() 48 self.content.seek(0) 49 self.trans.wfile.write(self.content.read()) 50 51 # Request-related methods. 52 53 def get_request_stream(self): 54 55 """ 56 A framework-specific method which returns the request stream for 57 the transaction. 58 """ 59 60 return MessageBodyStream(self.trans.rfile, self.get_headers()) 61 62 def get_request_method(self): 63 64 """ 65 A framework-specific method which gets the request method. 66 """ 67 68 return self.trans.command 69 70 def get_headers(self): 71 72 """ 73 A framework-specific method which returns the request headers. 74 NOTE: Experimental, since framework support varies somewhat. 75 """ 76 77 return self.trans.headers 78 79 def get_content_type(self): 80 81 """ 82 A framework-specific method which gets the content type specified on the 83 request, along with the charset employed. 84 """ 85 86 return self.parse_content_type(self.trans.headers.get("Content-type") or 87 self.trans.headers.get("Content-Type")) 88 89 def get_content_charsets(self): 90 91 """ 92 Returns the character set preferences. 93 """ 94 95 return self.parse_content_preferences(self.trans.headers["Accept-Charset"]) 96 97 def get_content_languages(self): 98 99 """ 100 A framework-specific method which extracts language information from 101 the transaction. 102 """ 103 104 return self.parse_content_preferences(self.trans.headers["Accept-Language"]) 105 106 def get_path(self): 107 108 """ 109 A framework-specific method which gets the entire path from the request. 110 """ 111 112 return self.trans.path 113 114 def get_path_info(self): 115 116 """ 117 A framework-specific method which gets the "path info" (the part of the 118 URL after the resource name handling the current request) from the 119 request. 120 """ 121 122 # NOTE: No attempt is made to deduce the "path info". 123 124 return self.trans.path 125 126 # Higher level request-related methods. 127 128 def get_fields(self): 129 130 """ 131 A framework-specific method which extracts the form fields from the 132 transaction. 133 """ 134 135 return FieldStorage(self.get_request_stream(), keep_blank_values=1) 136 137 def get_user(self): 138 139 """ 140 A framework-specific method which extracts user information from the 141 transaction. 142 """ 143 144 auth_header = self.get_headers().get("Authorization") 145 if auth_header: 146 return UserInfo(auth_header).username 147 else: 148 return None 149 150 # Response-related methods. 151 152 def get_response_stream(self): 153 154 """ 155 A framework-specific method which returns the response stream for 156 the transaction. 157 """ 158 159 # Return a stream which is later emptied into the real stream. 160 161 return self.content 162 163 def get_response_code(self): 164 165 """ 166 Get the response code associated with the transaction. If no response 167 code is defined, None is returned. 168 """ 169 170 return self.response_code 171 172 def set_response_code(self, response_code): 173 174 """ 175 Set the 'response_code' using a numeric constant defined in the HTTP 176 specification. 177 """ 178 179 self.response_code = response_code 180 181 def set_header(self, header, value): 182 183 """ 184 Set the HTTP 'header' with the given 'value'. 185 """ 186 187 # The header is not written out immediately due to the buffering in use. 188 189 self.headers[header] = value 190 191 def set_content_type(self, content_type): 192 193 """ 194 A framework-specific method which sets the 'content_type' for the 195 response. 196 """ 197 198 # The content type has to be written as a header, before actual content, 199 # but after the response line. This means that some kind of buffering is 200 # required. Hence, we don't write the header out immediately. 201 202 self.content_type = content_type 203 204 # vim: tabstop=4 expandtab shiftwidth=4