lib/http.py
changeset 7 d6a8258bd90e
child 8 0ce1f471e9d7
equal deleted inserted replaced
6:5565d94da522 7:d6a8258bd90e
       
     1 """
       
     2     WSGI HTTP utility code
       
     3 """
       
     4 
       
     5 # for utility functions
       
     6 import cgi
       
     7 
       
     8 # for header handling
       
     9 import wsgiref.headers
       
    10 
       
    11 class Request (object) :
       
    12     """
       
    13         HTTP Request with associated metadata
       
    14     """
       
    15 
       
    16     def __init__ (self, env) :
       
    17         """
       
    18             Parse env data
       
    19         """
       
    20 
       
    21         # store env
       
    22         self.env = env
       
    23 
       
    24         # get the querystring
       
    25         self.arg_str = env.get('QUERY_STRING', '')
       
    26 
       
    27         # parse query args
       
    28         self.arg_dict = cgi.parse_qs(self.arg_str, True)
       
    29 
       
    30 class Response (object) :
       
    31     """
       
    32         HTTP Response with headers and data
       
    33     """
       
    34 
       
    35     def __init__ (self, data, content_type='text/html', status='200 OK', charset='utf8') :
       
    36         """
       
    37             Create the response. The Content-type header is built from the given values. The given \a data must be
       
    38             either a str (which is sent plain), an unicode object (which is encoded with the relevant charset), or
       
    39             None, whereupon an empty response body is sent. The content_type argument can also be forced to None to
       
    40             not send a Content-type header (e.g. for redirects)
       
    41         """
       
    42 
       
    43         # store info
       
    44         self.status = status
       
    45         self.data = data
       
    46         self.charset = charset
       
    47 
       
    48         # headers
       
    49         self.headers = wsgiref.headers.Headers([])
       
    50         
       
    51         # add Content-type header?
       
    52         if content_type :
       
    53             self.add_header('Content-type', content_type, charset=charset)
       
    54 
       
    55     def add_header (self, name, value, **params) :
       
    56         """
       
    57             Add response header with the given name/value, plus option params
       
    58 
       
    59             XXX: uses the wsgiref.headers code, not sure how that behaves re multiple headers with the same name, etc
       
    60         """
       
    61         
       
    62         self.headers.add_header(name, value, **params)
       
    63     
       
    64     def get_status (self) :
       
    65         """
       
    66             Returns response status string (XXX Foo)
       
    67         """
       
    68 
       
    69         return self.status
       
    70     
       
    71     def get_headers (self) :
       
    72         """
       
    73             Returns the list of header (name, value) pairs
       
    74         """
       
    75 
       
    76         return self.headers.items()
       
    77 
       
    78     def get_data (self) :
       
    79         """
       
    80             Returns the response data - as an encoded string
       
    81         """
       
    82 
       
    83         if self.data :
       
    84             return self.data.encode(self.charset)
       
    85 
       
    86         else :
       
    87             return ''
       
    88 
       
    89 class ErrorResponse (Response) :
       
    90     """
       
    91         A response with an error code / message
       
    92     """
       
    93 
       
    94     def __init__ (self, status, message) :
       
    95         """
       
    96             Build a plain error message response with the given status/message
       
    97         """
       
    98 
       
    99         data = """\
       
   100 <html><head><title>%(title)s</title></head><body>
       
   101 <h1>%(title)s</h1>
       
   102 <p>%(message)s</p>
       
   103 </body></html>
       
   104 """ % dict(
       
   105             title       = status, 
       
   106             message     = message
       
   107         )
       
   108             
       
   109         super(ErrorResponse, self).__init__(data, status=status)
       
   110 
       
   111 class ResponseError (Exception) :
       
   112     """
       
   113         An exception that results in a specfic 4xx ErrorResponse message to the client
       
   114     """
       
   115 
       
   116     def __init__ (self, message, status='400 Bad Request') :
       
   117         self.status = status
       
   118         self.message = message
       
   119 
       
   120         super(ResponseError, self).__init__(message)
       
   121 
       
   122     def get_response (self) :
       
   123         return ErrorResponse(self.status, self.message)
       
   124 
       
   125 class Redirect (Response) :
       
   126     """
       
   127         Redirect response
       
   128     """
       
   129 
       
   130     def __init__ (self, url) :
       
   131         """
       
   132             Redirect to given *absolute* URL
       
   133         """
       
   134         
       
   135         # no content-type or data
       
   136         super(Redirect, self).__init__(None, content_type=None, status='302 Found')
       
   137 
       
   138         # add Location: header
       
   139         self.add_header("Location", url)
       
   140 
       
   141