1c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)# Copyright 2013 The Chromium Authors. All rights reserved. 2c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)# Use of this source code is governed by a BSD-style license that can be 3c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)# found in the LICENSE file. 4c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 5c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class Request(object): 6c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) '''Request data. 7c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ''' 8b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def __init__(self, path, host, headers): 9b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) self.path = path.lstrip('/') 10b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) self.host = host.rstrip('/') 11c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) self.headers = headers 12c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 13b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) @staticmethod 14a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) def ForTest(path, host='http://developer.chrome.com', headers=None): 15a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return Request(path, host, headers or {}) 16b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 17b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def __repr__(self): 18ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch return 'Request(path=%s, host=%s, headers=%s)' % ( 19ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch self.path, self.host, self.headers) 20b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 21b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def __str__(self): 22b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return repr(self) 23b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 24c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class _ContentBuilder(object): 25c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) '''Builds the response content. 26c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ''' 27c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def __init__(self): 28c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) self._buf = [] 29c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 30c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def Append(self, content): 31c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if isinstance(content, unicode): 32c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) content = content.encode('utf-8', 'replace') 33c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) self._buf.append(content) 34c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 35c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def ToString(self): 36c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) self._Collapse() 37c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return self._buf[0] 38c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 39c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def __str__(self): 40c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return self.ToString() 41c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 42c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def __len__(self): 43c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return len(self.ToString()) 44c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 45c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def _Collapse(self): 46c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) self._buf = [''.join(self._buf)] 47c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 48c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class Response(object): 49c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) '''The response from Get(). 50c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ''' 51c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def __init__(self, content=None, headers=None, status=None): 52c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) self.content = _ContentBuilder() 53c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if content is not None: 54c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) self.content.Append(content) 55c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) self.headers = {} 56c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) if headers is not None: 57c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) self.headers.update(headers) 58c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) self.status = status 59c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 60c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) @staticmethod 61c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def Ok(content, headers=None): 62c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) '''Returns an OK (200) response. 63c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ''' 64c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return Response(content=content, headers=headers, status=200) 65c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 66c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) @staticmethod 67c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def Redirect(url, permanent=False): 68c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) '''Returns a redirect (301 or 302) response. 69c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ''' 70c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) status = 301 if permanent else 302 71c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return Response(headers={'Location': url}, status=status) 72c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 73c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) @staticmethod 74c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def NotFound(content, headers=None): 75c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) '''Returns a not found (404) response. 76c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ''' 77c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return Response(content=content, headers=headers, status=404) 78c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 79c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) @staticmethod 80c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def InternalError(content, headers=None): 81c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) '''Returns an internal error (500) response. 82c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ''' 83c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) return Response(content=content, headers=headers, status=500) 84c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 85c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def Append(self, content): 86c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) '''Appends |content| to the response content. 87c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ''' 88c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) self.content.append(content) 89c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 90c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def AddHeader(self, key, value): 91c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) '''Adds a header to the response. 92c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ''' 93c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) self.headers[key] = value 94c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 95c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def AddHeaders(self, headers): 96c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) '''Adds several headers to the response. 97c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ''' 98c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) self.headers.update(headers) 99c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 100c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def SetStatus(self, status): 101c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) self.status = status 102c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 103a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) def GetRedirect(self): 104a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) if self.headers.get('Location') is None: 105a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return (None, None) 106a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) return (self.headers.get('Location'), self.status == 301) 107a93a17c8d99d686bd4a1511e5504e5e6cc9fcadfTorne (Richard Coles) 1080f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) def IsNotFound(self): 1090f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) return self.status == 404 1100f1bc08d4cfcc34181b0b5cbf065c40f687bf740Torne (Richard Coles) 111ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch def __eq__(self, other): 112ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch return (isinstance(other, self.__class__) and 113ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch str(other.content) == str(self.content) and 114ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch other.headers == self.headers and 115ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch other.status == self.status) 116ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 117ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch def __ne__(self, other): 118ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch return not (self == other) 119ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch 120c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def __repr__(self): 121ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch return 'Response(content=%s bytes, status=%s, headers=%s)' % ( 122ca12bfac764ba476d6cd062bf1dde12cc64c3f40Ben Murdoch len(self.content), self.status, self.headers) 123c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 124b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) def __str__(self): 125b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) return repr(self) 126b2df76ea8fec9e32f6f3718986dba0d95315b29cTorne (Richard Coles) 127c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles)class Servlet(object): 128c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def __init__(self, request): 129c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) self._request = request 130c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) 131c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) def Get(self): 132c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) '''Returns a Response. 133c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) ''' 134c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) raise NotImplemented() 135