| # Copyright 2013 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| |
| class RequestHeaders(object): |
| '''A custom dictionary impementation for headers which ignores the case |
| of requests, since different HTTP libraries seem to mangle them. |
| ''' |
| def __init__(self, dict_): |
| if isinstance(dict_, RequestHeaders): |
| self._dict = dict_ |
| else: |
| self._dict = dict((k.lower(), v) for k, v in dict_.iteritems()) |
| |
| def get(self, key, default=None): |
| return self._dict.get(key.lower(), default) |
| |
| def __repr__(self): |
| return repr(self._dict) |
| |
| def __str__(self): |
| return repr(self._dict) |
| |
| |
| class Request(object): |
| '''Request data. |
| ''' |
| def __init__(self, path, host, headers): |
| self.path = path.lstrip('/') |
| self.host = host.rstrip('/') |
| self.headers = RequestHeaders(headers) |
| |
| @staticmethod |
| def ForTest(path, host=None, headers=None): |
| return Request(path, host or 'http://developer.chrome.com', headers or {}) |
| |
| def __repr__(self): |
| return 'Request(path=%s, host=%s, headers=%s)' % ( |
| self.path, self.host, self.headers) |
| |
| def __str__(self): |
| return repr(self) |
| |
| class _ContentBuilder(object): |
| '''Builds the response content. |
| ''' |
| def __init__(self): |
| self._buf = [] |
| |
| def Append(self, content): |
| if isinstance(content, unicode): |
| content = content.encode('utf-8', 'replace') |
| self._buf.append(content) |
| |
| def ToString(self): |
| self._Collapse() |
| return self._buf[0] |
| |
| def __str__(self): |
| return self.ToString() |
| |
| def __len__(self): |
| return len(self.ToString()) |
| |
| def _Collapse(self): |
| self._buf = [''.join(self._buf)] |
| |
| class Response(object): |
| '''The response from Get(). |
| ''' |
| def __init__(self, content=None, headers=None, status=None): |
| self.content = _ContentBuilder() |
| if content is not None: |
| self.content.Append(content) |
| self.headers = {} |
| if headers is not None: |
| self.headers.update(headers) |
| self.status = status |
| |
| @staticmethod |
| def Ok(content, headers=None): |
| '''Returns an OK (200) response. |
| ''' |
| return Response(content=content, headers=headers, status=200) |
| |
| @staticmethod |
| def Redirect(url, permanent=False): |
| '''Returns a redirect (301 or 302) response. |
| ''' |
| status = 301 if permanent else 302 |
| return Response(headers={'Location': url}, status=status) |
| |
| @staticmethod |
| def NotFound(content, headers=None): |
| '''Returns a not found (404) response. |
| ''' |
| return Response(content=content, headers=headers, status=404) |
| |
| @staticmethod |
| def NotModified(content, headers=None): |
| return Response(content=content, headers=headers, status=304) |
| |
| @staticmethod |
| def InternalError(content, headers=None): |
| '''Returns an internal error (500) response. |
| ''' |
| return Response(content=content, headers=headers, status=500) |
| |
| def Append(self, content): |
| '''Appends |content| to the response content. |
| ''' |
| self.content.append(content) |
| |
| def AddHeader(self, key, value): |
| '''Adds a header to the response. |
| ''' |
| self.headers[key] = value |
| |
| def AddHeaders(self, headers): |
| '''Adds several headers to the response. |
| ''' |
| self.headers.update(headers) |
| |
| def SetStatus(self, status): |
| self.status = status |
| |
| def GetRedirect(self): |
| if self.headers.get('Location') is None: |
| return (None, None) |
| return (self.headers.get('Location'), self.status == 301) |
| |
| def IsNotFound(self): |
| return self.status == 404 |
| |
| def __eq__(self, other): |
| return (isinstance(other, self.__class__) and |
| str(other.content) == str(self.content) and |
| other.headers == self.headers and |
| other.status == self.status) |
| |
| def __ne__(self, other): |
| return not (self == other) |
| |
| def __repr__(self): |
| return 'Response(content=%s bytes, status=%s, headers=%s)' % ( |
| len(self.content), self.status, self.headers) |
| |
| def __str__(self): |
| return repr(self) |
| |
| class Servlet(object): |
| def __init__(self, request): |
| self._request = request |
| |
| def Get(self): |
| '''Returns a Response. |
| ''' |
| raise NotImplemented() |