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