• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
6class RequestHeaders(object):
7  '''A custom dictionary impementation for headers which ignores the case
8  of requests, since different HTTP libraries seem to mangle them.
9  '''
10  def __init__(self, dict_):
11    if isinstance(dict_, RequestHeaders):
12      self._dict = dict_
13    else:
14      self._dict = dict((k.lower(), v) for k, v in dict_.iteritems())
15
16  def get(self, key, default=None):
17    return self._dict.get(key.lower(), default)
18
19  def __repr__(self):
20    return repr(self._dict)
21
22  def __str__(self):
23    return repr(self._dict)
24
25
26class Request(object):
27  '''Request data.
28  '''
29  def __init__(self, path, host, headers, arguments={}):
30    self.path = path.lstrip('/')
31    self.host = host.rstrip('/')
32    self.headers = RequestHeaders(headers)
33    self.arguments = arguments
34
35  @staticmethod
36  def ForTest(path, host=None, headers=None, arguments=None):
37    return Request(path,
38                   host or 'http://developer.chrome.com',
39                   headers or {},
40                   arguments or {})
41
42  def __repr__(self):
43    return 'Request(path=%s, host=%s, headers=%s)' % (
44        self.path, self.host, self.headers)
45
46  def __str__(self):
47    return repr(self)
48
49class _ContentBuilder(object):
50  '''Builds the response content.
51  '''
52  def __init__(self):
53    self._buf = []
54
55  def Append(self, content):
56    if isinstance(content, unicode):
57      content = content.encode('utf-8', 'replace')
58    self._buf.append(content)
59
60  def ToString(self):
61    self._Collapse()
62    return self._buf[0]
63
64  def __str__(self):
65    return self.ToString()
66
67  def __len__(self):
68    return len(self.ToString())
69
70  def _Collapse(self):
71    self._buf = [''.join(self._buf)]
72
73class Response(object):
74  '''The response from Get().
75  '''
76  def __init__(self, content=None, headers=None, status=None):
77    self.content = _ContentBuilder()
78    if content is not None:
79      self.content.Append(content)
80    self.headers = {}
81    if headers is not None:
82      self.headers.update(headers)
83    self.status = status
84
85  @staticmethod
86  def Ok(content, headers=None):
87    '''Returns an OK (200) response.
88    '''
89    return Response(content=content, headers=headers, status=200)
90
91  @staticmethod
92  def Redirect(url, permanent=False):
93    '''Returns a redirect (301 or 302) response.
94    '''
95    status = 301 if permanent else 302
96    return Response(headers={'Location': url}, status=status)
97
98  @staticmethod
99  def NotFound(content, headers=None):
100    '''Returns a not found (404) response.
101    '''
102    return Response(content=content, headers=headers, status=404)
103
104  @staticmethod
105  def NotModified(content, headers=None):
106    return Response(content=content, headers=headers, status=304)
107
108  @staticmethod
109  def InternalError(content, headers=None):
110    '''Returns an internal error (500) response.
111    '''
112    return Response(content=content, headers=headers, status=500)
113
114  @staticmethod
115  def ThrottledError(content, headers=None):
116    '''Returns an HTTP throttle error (429) response.
117    '''
118    return Response(content=content, headers=headers, status=429)
119
120  def Append(self, content):
121    '''Appends |content| to the response content.
122    '''
123    self.content.append(content)
124
125  def AddHeader(self, key, value):
126    '''Adds a header to the response.
127    '''
128    self.headers[key] = value
129
130  def AddHeaders(self, headers):
131    '''Adds several headers to the response.
132    '''
133    self.headers.update(headers)
134
135  def SetStatus(self, status):
136    self.status = status
137
138  def GetRedirect(self):
139    if self.headers.get('Location') is None:
140      return (None, None)
141    return (self.headers.get('Location'), self.status == 301)
142
143  def IsNotFound(self):
144    return self.status == 404
145
146  def __eq__(self, other):
147    return (isinstance(other, self.__class__) and
148            str(other.content) == str(self.content) and
149            other.headers == self.headers and
150            other.status == self.status)
151
152  def __ne__(self, other):
153    return not (self == other)
154
155  def __repr__(self):
156    return 'Response(content=%s bytes, status=%s, headers=%s)' % (
157        len(self.content), self.status, self.headers)
158
159  def __str__(self):
160    return repr(self)
161
162class Servlet(object):
163  def __init__(self, request):
164    self._request = request
165
166  def Get(self):
167    '''Returns a Response.
168    '''
169    raise NotImplemented()
170