/ 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