def post(self, api_request): if self.verbose: logging.info('post: api_request={}', api_request) context = api_request['context'] if len(context) > 0: query_params = api_request['query_params'] operator = context[0] if operator == 'mode': self.controller.set_mode(query_params['mode']) elif operator == 'np': pin = None num_pixels = None if 'pin' in query_params: pin = query_params['pin'] if 'num_pixels' in query_params: num_pixels = query_params['num_pixels'] self.controller.set_np(pin=pin, num_pixels=num_pixels) elif operator == 'lamp': if 'color_name' not in query_params: raise uhttpd.BadRequestException( "Expected name in query_params") self.controller.set_color_name(query_params['color_name']) elif operator == 'schedule': if 'name' not in query_params: raise uhttpd.BadRequestException( "Expected name in query_params") self.controller.update_schedule(query_params['name'], api_request['body']) elif operator == 'colorspec': if 'name' not in query_params: raise uhttpd.BadRequestException( "Expected name in query_params") self.controller.set_colorspec(query_params['name'], api_request['body']) elif operator == 'color': self.controller.set_color( (int(query_params['r']), int(query_params['g']), int(query_params['b']))) elif operator == 'reboot': self.controller.reboot() elif operator == 'reset': self.controller.reset() else: raise uhttpd.BadRequestException( "Bad post request: Unknown operator: {}".format(operator)) else: raise uhttpd.BadRequestException( "Bad post request: Missing operator in context")
def save(self, api_request): context = api_request['context'] logging.info("context: {}".format(context)) if context == ['ap', 'config']: return self.save_ap_config(api_request) else: raise uhttpd.BadRequestException("Unsupported context on save: {}", context)
def extract_query(path): components = path.split("?") query_params = {} if len(components) == 1: return path, query_params elif len(components) > 2: raise uhttpd.BadRequestException("Malformed path: {}".format(path)) path_part = components[0] query_part = components[1] qparam_components = query_part.split("&") for qparam_component in qparam_components: if qparam_component.strip() == '': continue qparam = qparam_component.split("=") if len(qparam) != 2 or not qparam[0]: raise uhttpd.BadRequestException( "Invalid query parameter: {}".format(qparam_component)) query_params[qparam[0]] = qparam[1] return path_part, query_params
def delete(self, api_request): context = api_request['context'] if len(context) > 0: query_params = api_request['query_params'] operator = context[0] if operator == 'schedule': if 'name' not in query_params: raise uhttpd.BadRequestException( "Expected name in query_params") self.controller.delete_schedule(query_params['name']) elif operator == 'colorspec': if 'name' not in query_params: raise uhttpd.BadRequestException( "Expected name in query_params") self.controller.delete_colorspec(query_params['name']) else: raise uhttpd.BadRequestException( "Bad delete request: Unknown operator: {}".format( operator)) else: raise uhttpd.BadRequestException( "Bad delete request: Missing operator in context")
def get(self, api_request): context = api_request['context'] if len(context) > 0: if context[0] == 'config': query_params = api_request['query_params'] return Handler.get_path( self.controller.config, context[1:], 'all' in query_params and query_params['all'] == 'true') if context[0] == 'stats': return self.controller.get_stats() if context[0] == 'color': return self.controller.get_color() else: raise uhttpd.BadRequestException( "Bad get request: Missing operator in context")
def handle_request(self, http_request): # # We only support GET # verb = http_request['verb'] if verb != 'get': raise uhttpd.BadRequestException( "Unsupported HTTP verb: {}".format(verb)) # the relative path is the path on the HTTP request stripped of the # prefix used to register the file handler relative_path = uhttpd.get_relative_path(http_request) # the effective path is the relative path with the root path # prefixed, and normalized to remove '.' and '..' absolute_path = self.effective_path(relative_path) # # If the path is forbidden, 403 out # remote_addr = http_request['tcp']['remote_addr'] if not self.is_prefix(self._root_path, absolute_path): logging.info("FORBIDDEN {} {}".format(remote_addr, absolute_path)) raise uhttpd.ForbiddenException(absolute_path) # # If the path doesn't exist, 404 out # if not exists(absolute_path): logging.info("NOT_FOUND {} {}".format(remote_addr, absolute_path)) raise uhttpd.NotFoundException(absolute_path) # # Otherwise, generate a file listing or a file # if is_dir(absolute_path): index_path = absolute_path + "/index.html" if exists(index_path): response = self.create_file_response(index_path) logging.info("ACCESS {} {}".format(remote_addr, index_path)) return response else: logging.info("ACCESS {} {}".format(remote_addr, absolute_path)) prefix = http_request['prefix'] return self.create_dir_listing_response(absolute_path) else: logging.info("ACCESS {} {}".format(remote_addr, absolute_path)) return self.create_file_response(absolute_path)
def get(self, api_request): #print(api_request) context = api_request['context'] if len(context) > 0: what_to_return = context[0] if what_to_return == 'query_params': query_params = api_request['query_params'] return query_params elif what_to_return == "nothing": return None elif what_to_return == "empty": return b'' elif what_to_return == "something": return b'something' elif what_to_return == "bad_request_excetion": raise uhttpd.BadRequestException("derp") elif what_to_return == "not_found_excetion": raise uhttpd.NotFoundException("what you were looking for") elif what_to_return == "forbidden_excetion": raise uhttpd.ForbiddenException("tsktsk") return {'action': 'get'}
def get(self, api_request): #print(api_request) context = api_request['context'] if len(context) > 0: what_to_return = context[0] if what_to_return == 'query_params': query_params = api_request['query_params'] return query_params elif what_to_return == "nothing": return None elif what_to_return == "empty": return b'' elif what_to_return == "something": return b'something' elif what_to_return == "html": return "<html><body><h1>HTML</h1></body></html>" elif what_to_return == "json": return { 'some': [{ 'j': 1, 's': [], 'o': "str", 'n': { "дружище": "バディ" } }] } elif what_to_return == "int": return 1342 elif what_to_return == "float": return 3.14159 elif what_to_return == "bad_request_excetion": raise uhttpd.BadRequestException("derp") elif what_to_return == "not_found_excetion": raise uhttpd.NotFoundException("what you were looking for") elif what_to_return == "forbidden_excetion": raise uhttpd.ForbiddenException("tsktsk") else: return {'action': 'get'}
def handle_request(self, http_request): relative_path = uhttpd.get_relative_path(http_request) path_part, query_params = self.extract_query(relative_path) components = path_part.strip('/').split('/') prefix, handler, context = self.find_handler(components) if handler: json_body = None headers = http_request['headers'] if 'body' in http_request and 'content-type' in headers and headers[ 'content-type'] == "application/json": try: json_body = ujson.loads(http_request['body']) except Exception as e: raise uhttpd.BadRequestException( "Failed to load JSON: {}".format(e)) verb = http_request['verb'] api_request = { 'prefix': prefix, 'context': context, 'query_params': query_params, 'body': json_body, 'http': http_request } if verb == 'get': response = handler.get(api_request) elif verb == 'put': response = handler.put(api_request) elif verb == 'post': response = handler.post(api_request) elif verb == 'delete': response = handler.delete(api_request) else: # TODO add support for more verbs! error_message = "Unsupported verb: {}".format(verb) raise uhttpd.BadRequestException(error_message) else: error_message = "No handler found for components {}".format( components) raise uhttpd.NotFoundException(error_message) ## ## prepare response ## if response is not None: response_type = type(response) if response_type is dict or response_type is list: data = ujson.dumps(response).encode('UTF-8') body = lambda stream: stream.awrite(data) content_type = "application/json" content_length = len(data) elif response_type is bytes: data = response body = lambda stream: stream.awrite(data) content_type = "application/binary" content_length = len(data) elif response_type is str: data = response.encode("UTF-8") body = lambda stream: stream.awrite(data) content_type = "text/html; charset=utf-8" content_length = len(data) elif response_type is int or response_type is float: data = str(response) body = lambda stream: stream.awrite(data) content_type = "text/plain" content_length = len(data) else: data = str(response) body = lambda stream: stream.awrite(data) content_type = "text/plain" content_length = len(data) else: body = None content_type = None content_length = None headers = {} if content_length: headers.update({'content-length': content_length}) if content_type: headers.update({'content-type': content_type}) return {'code': 200, 'headers': headers, 'body': body}
def handle_request(self, http_request): relative_path = uhttpd.get_relative_path(http_request) path_part, query_params = self.extract_query(relative_path) components = path_part.strip('/').split('/') prefix, handler, context = self.find_handler(components) if handler: json_body = None headers = http_request['headers'] if 'body' in http_request and 'content-type' in headers and headers[ 'content-type'] == "application/json": try: json_body = ujson.loads(http_request['body']) except Exception as e: raise uhttpd.BadRequestException( "Failed to load JSON: {}".format(e)) verb = http_request['verb'] api_request = { 'prefix': prefix, 'context': context, 'query_params': query_params, 'body': json_body, 'http': http_request } if verb == 'get': response = handler.get(api_request) elif verb == 'put': response = handler.put(api_request) elif verb == 'post': response = handler.post(api_request) elif verb == 'delete': response = handler.delete(api_request) else: # TODO add support for more verbs! error_message = "Unsupported verb: {}".format(verb) raise uhttpd.BadRequestException(error_message) else: error_message = "No handler found for components {}".format( components) raise uhttpd.NotFoundException(error_message) if response is not None: if type(response) is dict: data = ujson.dumps(response).encode('UTF-8') content_type = "application/json" elif type(response) is bytes: data = response content_type = "application/binary" else: raise Exception( "Response from API Handler is neither dict nor bytearray nor None" ) body = lambda stream: stream.awrite(data) else: data = body = None ret = { 'code': 200, 'headers': { 'content-length': len(data) if data else 0 }, 'body': body } if data is not None: ret['headers']['content-type'] = content_type return ret