• 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):
30    self.path = path.lstrip('/')
31    self.host = host.rstrip('/')
32    self.headers = RequestHeaders(headers)
33
34  @staticmethod
35  def ForTest(path, host=None, headers=None):
36    return Request(path, host or 'http://developer.chrome.com', headers or {})
37
38  def __repr__(self):
39    return 'Request(path=%s, host=%s, headers=%s)' % (
40        self.path, self.host, self.headers)
41
42  def __str__(self):
43    return repr(self)
44
45class _ContentBuilder(object):
46  '''Builds the response content.
47  '''
48  def __init__(self):
49    self._buf = []
50
51  def Append(self, content):
52    if isinstance(content, unicode):
53      content = content.encode('utf-8', 'replace')
54    self._buf.append(content)
55
56  def ToString(self):
57    self._Collapse()
58    return self._buf[0]
59
60  def __str__(self):
61    return self.ToString()
62
63  def __len__(self):
64    return len(self.ToString())
65
66  def _Collapse(self):
67    self._buf = [''.join(self._buf)]
68
69class Response(object):
70  '''The response from Get().
71  '''
72  def __init__(self, content=None, headers=None, status=None):
73    self.content = _ContentBuilder()
74    if content is not None:
75      self.content.Append(content)
76    self.headers = {}
77    if headers is not None:
78      self.headers.update(headers)
79    self.status = status
80
81  @staticmethod
82  def Ok(content, headers=None):
83    '''Returns an OK (200) response.
84    '''
85    return Response(content=content, headers=headers, status=200)
86
87  @staticmethod
88  def Redirect(url, permanent=False):
89    '''Returns a redirect (301 or 302) response.
90    '''
91    status = 301 if permanent else 302
92    return Response(headers={'Location': url}, status=status)
93
94  @staticmethod
95  def NotFound(content, headers=None):
96    '''Returns a not found (404) response.
97    '''
98    return Response(content=content, headers=headers, status=404)
99
100  @staticmethod
101  def NotModified(content, headers=None):
102    return Response(content=content, headers=headers, status=304)
103
104  @staticmethod
105  def InternalError(content, headers=None):
106    '''Returns an internal error (500) response.
107    '''
108    return Response(content=content, headers=headers, status=500)
109
110  def Append(self, content):
111    '''Appends |content| to the response content.
112    '''
113    self.content.append(content)
114
115  def AddHeader(self, key, value):
116    '''Adds a header to the response.
117    '''
118    self.headers[key] = value
119
120  def AddHeaders(self, headers):
121    '''Adds several headers to the response.
122    '''
123    self.headers.update(headers)
124
125  def SetStatus(self, status):
126    self.status = status
127
128  def GetRedirect(self):
129    if self.headers.get('Location') is None:
130      return (None, None)
131    return (self.headers.get('Location'), self.status == 301)
132
133  def IsNotFound(self):
134    return self.status == 404
135
136  def __eq__(self, other):
137    return (isinstance(other, self.__class__) and
138            str(other.content) == str(self.content) and
139            other.headers == self.headers and
140            other.status == self.status)
141
142  def __ne__(self, other):
143    return not (self == other)
144
145  def __repr__(self):
146    return 'Response(content=%s bytes, status=%s, headers=%s)' % (
147        len(self.content), self.status, self.headers)
148
149  def __str__(self):
150    return repr(self)
151
152class Servlet(object):
153  def __init__(self, request):
154    self._request = request
155
156  def Get(self):
157    '''Returns a Response.
158    '''
159    raise NotImplemented()
160