def cors_request(req): if req.uri.startswith("/p/"): return # enndpoints for printers does not need CORS if req.method_number == state.METHOD_OPTIONS: res = Response(content_type="text/plain; charset=UTF-8", headers=options_headers, status_code=state.HTTP_NO_CONTENT) raise HTTPException(res)
def html_form(req, file_callback): """Generate upload page for specified callback.""" stats = "" hexdigest = "" if req.method == 'POST': start = time() bytes_read = 0 hexdigest = '' # pylint: disable=comparison-with-callable if file_callback == no_factory: to_download = min(req.content_length, 65365) data = req.read(to_download) while data: bytes_read += len(data) to_download = min(req.content_length - bytes_read, 65365) data = req.read(to_download) else: form = FieldStorage(req, keep_blank_values=app.keep_blank_values, strict_parsing=app.strict_parsing, file_callback=file_callback(req)) bytes_read = form.bytes_read hexdigest = form['file'].file.hexdigest() end = time() - start args = (hbytes(bytes_read) + (int(end), ) + hbytes(bytes_read / end) + (hexdigest, )) stats = ("Upload: %.2f%s in %ds -> %.2f%sps SHA256: %s" % args) log.info(stats) if bytes_read != req.content_length: log.error("File uploading not complete") raise HTTPException(400, error="File uploading not complete") return """ <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"/> <title>Upload form for %s</title> <style> body {width:90%%; max-width:900px; margin:auto; padding-top:30px;} h1 {text-align: center; color: #707070;} </style> </head> <body> <a href="/">/</a> <h1>Upload form for %s</h1> <form method="post" enctype="multipart/form-data"> <input type="file" name="file"/> <input type="submit" value="Send"/> </form> <pre>%s</pre> <hr> <small>Copyright (c) 2021 Ondřej Tůma. See <a href="http://poorhttp.zeropage.cz">poorhttp.zeropage.cz</a> </small> </body> </html>""" % (file_callback.__name__, file_callback.__name__, stats)
def handler_from_default(self, req: SimpleRequest): """Internal method, which is called if no handler is found.""" req.uri_rule = '/*' if req.method_number in self.__dhandlers: req.uri_handler = self.__dhandlers[req.method_number] self.handler_from_before(req) # call before handlers now return self.__dhandlers[req.method_number](req) self.handler_from_before(req) # call before handlers now log.error("404 Not Found: %s %s", req.method, req.path) raise HTTPException(HTTP_NOT_FOUND)
def blackhole_factory(req): """Factory for craeting Dummy file instance""" if req.content_length <= 0: raise HTTPException(400, error="Missing content length or no content") def create(filename): """Create Blackhole File object""" log.debug(create.__doc__) return Blackhole(filename) return create
def input_stream(req): """Stream request handler""" i = 0 # chunk must be read with extra method, uwsgi has own chunk = uwsgi.chunked_read() if uwsgi else req.read_chunk() while chunk: log.info("chunk: %s", chunk) if chunk != b'%d' % i: raise HTTPException(state.HTTP_BAD_REQUEST) chunk = uwsgi.chunked_read() if uwsgi else req.read_chunk() i += 1 return EmptyResponse(state.HTTP_OK)
def handler(req): if 'Authorization' not in req.headers: log.info('Digest: Authorization header not found') raise HTTPException(state.HTTP_UNAUTHORIZED, realm=realm) if req.authorization['type'] != 'Digest': log.error('Digest: Bad Authorization type') raise HTTPException(state.HTTP_UNAUTHORIZED, realm=realm) if not check_token(req.authorization.get('nonce'), req.secret_key, req.user_agent, timeout=req.app.auth_timeout): log.info("Digest: nonce value not match") raise HTTPException(state.HTTP_UNAUTHORIZED, realm=realm, stale=True) if not check_credentials(req, realm, username): raise HTTPException(state.HTTP_UNAUTHORIZED, realm=realm) req.user = req.authorization['username'] return fun(req)
def parse_json_request(raw: bytes, charset: str = "utf-8"): """Try to parse request data. Returned type could be: * JsonDict when dictionary is parsed. * JsonList when list is parsed. * Other based types from json.loads function like str, int, float, bool or None. * None when parsing of JSON fails. That is logged with WARNING log level. """ # pylint: disable=inconsistent-return-statements try: data = json_loads(raw.decode(charset)) if isinstance(data, dict): return JsonDict(data.items()) if isinstance(data, list): return JsonList(data) return data except BaseException as err: # pylint: disable=broad-except log.error("Invalid request json: %s", str(err)) raise HTTPException(HTTP_BAD_REQUEST, error=err) from err
def handler_from_table(self, req: Request): """Call right handler from handlers table (fill with route function). If no handler is fined, try to find directory or file if Document Root, resp. Document Index is set. Then try to call default handler for right method or call handler for status code 404 - not found. """ # pylint: disable=too-many-return-statements # static routes if req.path in self.__handlers: if req.method_number in self.__handlers[req.path]: handler = self.__handlers[req.path][req.method_number] req.uri_rule = req.path # nice variable for before handlers req.uri_handler = handler self.handler_from_before(req) # call before handlers now return handler(req) # call right handler now self.handler_from_before(req) # call before handlers now raise HTTPException(HTTP_METHOD_NOT_ALLOWED) # regular expression for ruri in self.__rhandlers: match = ruri.match(req.path) if match and req.method_number in self.__rhandlers[ruri]: handler, converters, rule = \ self.__rhandlers[ruri][req.method_number] req.uri_rule = rule or ruri.pattern req.uri_handler = handler if converters: # create OrderedDict from match inside of dict for # converters applying req.path_args = OrderedDict( (g, c(v)) for ((g, c), v) in zip(converters, match.groups())) self.handler_from_before(req) # call before handlers now return handler(req, *req.path_args.values()) req.path_args = match.groupdict() self.handler_from_before(req) # call before handlers now return handler(req, *match.groups()) # try file or index if req.document_root and \ req.method_number & (METHOD_HEAD | METHOD_GET): rfile = "%s%s" % (req.document_root, path.normpath( "%s" % req.path)) if not path.exists(rfile): if req.debug and req.path == '/debug-info': # work if debug req.uri_rule = '/debug-info' req.uri_handler = debug_info self.handler_from_before(req) # call before handlers now return debug_info(req, self) return self.handler_from_default(req) # try default # return file if path.isfile(rfile) and access(rfile, R_OK): req.uri_rule = '/*' self.handler_from_before(req) # call before handlers now log.info("Return file: %s", req.path) return FileResponse(rfile) # return directory index if req.document_index and path.isdir(rfile) \ and access(rfile, R_OK): log.info("Return directory: %s", req.path) req.uri_rule = '/*' req.uri_handler = directory_index self.handler_from_before(req) # call before handlers now return directory_index(req, rfile) self.handler_from_before(req) # call before handlers now raise HTTPException(HTTP_FORBIDDEN) # req.document_root if req.debug and req.path == '/debug-info': req.uri_rule = '/debug-info' req.uri_handler = debug_info self.handler_from_before(req) # call before handlers now return debug_info(req, self) return self.handler_from_default(req)
def directory_index(req, path): """Returns directory index as html page.""" if not isdir(path): log.error( "Only directory_index can be send with directory_index handler. " "`%s' is not directory.", path) raise HTTPException(HTTP_INTERNAL_SERVER_ERROR) index = os.listdir(path) if req.document_root != path[:-1]: index.append("..") # parent directory index.sort() diruri = req.uri.rstrip('/') content = ("<!DOCTYPE html>\n" "<html>\n" " <head>\n" " <title>Index of %s</title>\n" ' <meta http-equiv="content-type" ' 'content="text/html; charset=utf-8"/>\n' " <style>\n" " body { width: 98%%; margin: auto; }\n" " table { font: 90%% monospace; text-align: left; }\n" " td, th { padding: 0 1em 0 1em; }\n" " .size { text-align:right; white-space:pre; }\n" " </style>\n" " </head>\n" " <body>\n" " <h1>Index of %s</h1>\n" " <hr>\n" " <table>\n" " <tr><th>Name</th><th>Last Modified</th>" "<th class=\"size\">Size</th><th>Type</th></tr>\n" % (diruri, diruri)) for item in index: # dot files if item[0] == "." and item[1] != ".": continue # bakup files (~) if item[-1] == "~": continue fpath = "%s/%s" % (path, item) if not os.access(fpath, os.R_OK): continue fname = item + ('/' if isdir(fpath) else '') ftype = "" if isfile(fpath): # pylint: disable=unused-variable (ftype, encoding) = mimetypes.guess_type(fpath) if not ftype: ftype = 'application/octet-stream' size = "%.1f%s" % hbytes(getsize(fpath)) elif isdir(fpath): ftype = "Directory" size = "-" else: size = ftype = '-' content += ( " <tr><td><a href=\"%s\">%s</a></td><td>%s</td>" "<td class=\"size\">%s</td><td>%s</td></tr>\n" % (diruri + '/' + fname, fname, strftime("%d-%b-%Y %H:%M", gmtime(getctime(fpath))), size, ftype)) content += (" </table>\n" " <hr>\n") if req.debug: content += (" <small><i>%s / Poor WSGI for Python, " "webmaster: %s </i></small>\n" % (req.server_software, req.server_admin)) else: content += (" <small><i>webmaster: %s </i></small>\n" % req.server_admin) content += (" </body>\n" "</html>") return content
def not_implemented(req): raise HTTPException(state.HTTP_NOT_IMPLEMENTED)
def forbidden(req): raise HTTPException(state.HTTP_FORBIDDEN)
def value_error_handler(req, error): """ValueError exception handler example.""" assert req print("ValueError: ", error) raise HTTPException(state.HTTP_BAD_REQUEST)
def check_api_key(req): api_token = req.headers.get("API-Key", None) if api_token != XXX: raise HTTPException(401) return "api-key ok"
def check_login(req): cookie = PoorSession(req) if 'login' not in cookie.data: raise HTTPException(401) return "login ok"