Home | History | Annotate | Download | only in server2
      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 
      6 class 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 
     26 class 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 
     45 class _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 
     69 class 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 
    152 class 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