litefs.handlers.wsgi 源代码

#!/usr/bin/env python
# coding: utf-8

"""
WSGI 请求处理器

用于在 gunicorn、uWSGI 等 WSGI 服务器中运行
符合 PEP 3333 规范
"""

from http.cookies import SimpleCookie

from ..exceptions import HttpError
from ..session import Session
from .base import BaseRequestHandler
from .form import parse_form, parse_header, parse_multipart_wsgi


[文档] class WSGIRequestHandler(BaseRequestHandler): """ WSGI 请求处理器,用于在 gunicorn、uWSGI 等 WSGI 服务器中运行 符合 PEP 3333 规范,处理 WSGI environ 并返回标准响应 """ @staticmethod def _reset_input_stream(wsgi_input): """重置 WSGI 输入流位置,使后续中间件可重新读取请求体。""" if hasattr(wsgi_input, 'seek'): try: wsgi_input.seek(0) except (OSError, AttributeError): pass def __init__(self, app, environ): super(WSGIRequestHandler, self).__init__(app, environ) self._environ = self._normalize_environ(environ) self._headers = [] self._get = parse_form(self._environ.get("QUERY_STRING", "")) content_type = self._environ.get("CONTENT_TYPE", "") if content_type: content_type_raw = content_type content_type, params = parse_header(content_type) content_length_str = self._environ.get("CONTENT_LENGTH") or "0" content_length = int(content_length_str) if content_length_str.strip() else 0 if content_length > 0: max_request_size = getattr(app.config, "max_request_size", 10485760) if content_length > max_request_size: raise HttpError( 413, f"Request body too large. Maximum size is {max_request_size} bytes" ) if content_type_raw == "application/x-www-form-urlencoded": if content_length > 0: wsgi_input = self._environ.get("wsgi.input") if wsgi_input: post_content = wsgi_input.read(content_length) self._reset_input_stream(wsgi_input) post_content = post_content.decode("utf-8") self._post = parse_form(post_content) elif content_type_raw.startswith("multipart/form-data"): boundary = params.get("boundary") if boundary: wsgi_input = self._environ.get("wsgi.input") if wsgi_input: content_length_str = self._environ.get("CONTENT_LENGTH") or "0" content_length = ( int(content_length_str) if content_length_str.strip() else 0 ) if content_length > 0: self._post, self._files = parse_multipart_wsgi( wsgi_input, boundary, content_length, getattr(app.config, "max_upload_size", 52428800) ) self._reset_input_stream(wsgi_input) else: if content_length > 0: wsgi_input = self._environ.get("wsgi.input") if wsgi_input: self._body = wsgi_input.read(content_length) self._reset_input_stream(wsgi_input) self._body = self._body.decode("utf-8") self._session_id, self._session = self._get_session() self._middlewares = app._get_middleware_instances() def _normalize_environ(self, environ): normalized = dict(environ) if "PATH_INFO" not in normalized: normalized["PATH_INFO"] = "/" if "REQUEST_METHOD" not in normalized: normalized["REQUEST_METHOD"] = "GET" if "QUERY_STRING" not in normalized: normalized["QUERY_STRING"] = "" if "CONTENT_LENGTH" not in normalized: normalized["CONTENT_LENGTH"] = "0" else: content_length = normalized.get("CONTENT_LENGTH", "0") if content_length == "" or content_length is None: normalized["CONTENT_LENGTH"] = "0" if "CONTENT_TYPE" not in normalized: normalized["CONTENT_TYPE"] = "" if "HTTP_HOST" not in normalized: host = normalized.get("SERVER_NAME", "localhost") port = normalized.get("SERVER_PORT", "80") if port != "80": normalized["HTTP_HOST"] = "%s:%s" % (host, port) else: normalized["HTTP_HOST"] = host return normalized def _get_session(self): app = self._app sessions = app.sessions session_name = app.config.session_name cookie_str = self._environ.get("HTTP_COOKIE", "") cookie = SimpleCookie(cookie_str) morsel = cookie.get(session_name) if morsel is not None: session_id = morsel.value session = sessions.get(session_id) if session is not None: # 设置存储后端实例,确保数据修改时自动保存 session.store = sessions return session_id, session session_id = self._new_session_id() # 创建 Session 对象时传入存储后端实例 session = Session(session_id, store=sessions) sessions.put(session_id, session) return None, session @property def cookie(self): cookie_str = self._environ.get("HTTP_COOKIE", "") cookie = SimpleCookie() cookie.load(cookie_str) return cookie
[文档] def handler(self): app = self._app middleware_result = app.middleware_manager.process_request(self) if middleware_result is not None: from .response import Response if isinstance(middleware_result, Response): return self.handle_response(middleware_result) return middleware_result try: environ = self._environ path_info = environ.get("PATH_INFO", "/") request_method = environ.get("REQUEST_METHOD", "GET") # 尝试使用路由系统处理请求 route_match = app.router.match_with_route(path_info, request_method) if route_match: route, params = route_match handler = route.handler try: # 将路由参数添加到请求对象 setattr(self, 'route_path', route.path) setattr(self, 'route_params', params) setattr(self, 'path_params', params) result = handler(self, **params) return self._process_route_result(result, app) except Exception: return self._process_route_error(app) # 路由未匹配,返回 404 return app.middleware_manager.process_response(self, self._response(404)) except Exception as e: middleware_result = app.middleware_manager.process_exception(self, e) if middleware_result is not None: return middleware_result raise
__all__ = [ 'WSGIRequestHandler', ]