/ adafruit_wsgi / request.py
request.py
  1  # The MIT License (MIT)
  2  #
  3  # Copyright (c) 2019 Matthew Costi for Adafruit Industries
  4  #
  5  # Permission is hereby granted, free of charge, to any person obtaining a copy
  6  # of this software and associated documentation files (the "Software"), to deal
  7  # in the Software without restriction, including without limitation the rights
  8  # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9  # copies of the Software, and to permit persons to whom the Software is
 10  # furnished to do so, subject to the following conditions:
 11  #
 12  # The above copyright notice and this permission notice shall be included in
 13  # all copies or substantial portions of the Software.
 14  #
 15  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17  # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18  # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 20  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 21  # THE SOFTWARE.
 22  
 23  """
 24  `Request`
 25  ================================================================================
 26  
 27  
 28  * Author(s): Matthew Costi
 29  """
 30  import re
 31  
 32  
 33  class Request:
 34      """
 35      An incoming HTTP request.
 36      A higher level abstraction of the raw WSGI Environ dictionary.
 37      """
 38  
 39      def __init__(self, environ):
 40          self._method = environ["REQUEST_METHOD"]
 41          self._path = environ["PATH_INFO"]
 42          self._query_params = self.__parse_query_params(environ.get("QUERY_STRING", ""))
 43          self._headers = self.__parse_headers(environ)
 44          self._body = environ["wsgi.input"]
 45          self._wsgi_environ = environ
 46  
 47      @property
 48      def method(self):
 49          """
 50          the HTTP Method Type of this request
 51          """
 52          return self._method
 53  
 54      @property
 55      def path(self):
 56          """
 57          the path this request was made to
 58          """
 59          return self._path
 60  
 61      @property
 62      def query_params(self):
 63          """
 64          Request query parameters, represented as a dictionary of
 65          param name to param value
 66          """
 67          return self._query_params
 68  
 69      @property
 70      def headers(self):
 71          """
 72          Request headers, represented as a dictionary of
 73          header name to header value
 74          """
 75          return self._headers
 76  
 77      @property
 78      def body(self):
 79          """
 80          The Request Body
 81          """
 82          return self._body
 83  
 84      @property
 85      def wsgi_environ(self):
 86          """
 87          The raw WSGI Environment dictionary representation of the request
 88          """
 89          return self._wsgi_environ
 90  
 91      @staticmethod
 92      def __parse_query_params(query_string):
 93          param_list = query_string.split("&")
 94          params = {}
 95          for param in param_list:
 96              key_val = param.split("=")
 97              if len(key_val) == 2:
 98                  params[key_val[0]] = key_val[1]
 99          return params
100  
101      @staticmethod
102      def __parse_headers(environ):
103          headers = {}
104  
105          # Content Type and Content Length headers
106          #  are stored in environ differently than other headers
107          if "CONTENT_TYPE" in environ:
108              headers["content-type"] = environ["CONTENT_TYPE"]
109          if "CONTENT_LENGTH" in environ:
110              headers["content-length"] = environ["CONTENT_LENGTH"]
111  
112          env_header_re = re.compile(r"HTTP_(.+)")
113          for key, val in environ.items():
114              header = env_header_re.match(key)
115              if header:
116                  headers[header.group(1).replace("_", "-").lower()] = val
117          return headers