#pragma once #include #include #include #include #include "Export.h" #include class FileReceiver; namespace uns { // HTTP status codes. // Don't use "enum class" for converting to/from int easily. // The full list is available here: // https://en.wikipedia.org/wiki/List_of_HTTP_status_codes enum Status { // 此临时响应表明客户端应继续请求,或者如果请求已完成,则忽略此响应。 kContinue = 100, // 此代码是在响应客户端的 Upgrade 请求标头时发送的,用于指示服务器即将切换到的协议。 kSwitchingProtocols = 101, // 此代码曾在 WebDAV 上下文中使用,表示服务器已收到请求,但在响应时无法提供状态。 kProcessing = 102, // 此状态码主要与 Link 标头一起使用,允许用户代理在服务器准备响应时开始预加载资源,或预连接到页面需要资源的源站。 kEarlyHints = 103, // 请求成功。 kOK = 200, // 请求成功,并因此创建了一个新资源。 kCreated = 201, // 请求已被接收但尚未处理。 kAccepted = 202, // 此响应代码表示返回的元数据与原始服务器上可用的不完全相同,而是从本地或第三方副本收集的。这主要用于另一个资源的镜像或备份。 kNonAuthoritativeInformation = 203, // 对于此请求,没有内容可发送,但响应头可能有用。 kNoContent = 204, // 告知用户代理重置发送此请求的文档。 kResetContent = 205, // 当客户端请求了资源的一部分时,使用此响应代码进行响应。 kPartialContent = 206, // 在可能需要多个状态码的情况下,传递关于多个资源的信息。 kMultiStatus = 207, // 在 响应元素内部使用,以避免重复枚举同一集合的多个绑定的内部成员。 kAlreadyReported = 208, // 服务器已完成了对资源的 GET 请求,并且响应是对当前实例应用了一个或多个实例操作后的结果表示。 kIMUsed = 226, // 在代理驱动(agent-driven)的内容协商中,请求有多个可能的响应,用户代理或用户应选择其中之一。 kMultipleChoices = 300, // 请求资源的 URL 已永久更改。新 URL 在响应中给出。 kMovedPermanently = 301, // 此响应代码意味着请求资源的 URI 已暂时更改。未来可能还会对 URI 进行进一步更改,因此客户端在未来的请求中应使用相同的 URI。 kFound = 302, // 服务器发送此响应以指示客户端使用 GET 请求在另一个 URI 获取请求的资源。 kSeeOther = 303, // 用于缓存目的。它告知客户端响应未被修改,因此客户端可以继续使用相同的缓存响应版本。 kNotModified = 304, // 在 HTTP 规范的前一版本中定义,表示请求的响应必须通过代理访问。由于涉及代理带内配置的安全问题,此状态码已被弃用。 kUseProxy = 305, // 此响应代码不再使用,但被保留。它曾在 HTTP/1.1 规范的先前版本中使用。 k__Unused = 306, // 服务器发送此响应以指示客户端使用与先前请求相同的方法在另一个 URI 获取请求的资源。其语义与 302 Found 响应代码相同,但用户代理不得更改使用的 HTTP 方法:如果在第一个请求中使用了 POST,则在重定向请求中也必须使用 POST。 kTemporaryRedirect = 307, // 表示资源现在永久位于另一个 URI,由 Location 响应头指定。其语义与 301 Moved Permanently HTTP 响应代码相同,但用户代理不得更改使用的 HTTP 方法:如果在第一个请求中使用了 POST,则在第二个请求中也必须使用 POST。 kPermanentRedirect = 308, // 由于被认为是客户端错误的原因(例如,格式错误的请求语法、无效的请求消息结构或欺骗性的请求路由),服务器无法或不会处理该请求。 kBadRequest = 400, // 尽管 HTTP 标准指定为 "unauthorized",但从语义上讲,此响应的意思是 "unauthenticated"。即,客户端必须进行身份验证才能获得请求的响应。 kUnauthorized = 401, // 此代码最初用于数字支付系统,但此状态码很少使用,且不存在标准约定。 kPaymentRequired = 402, // 客户端没有访问内容的权利;也就是说,它是未授权的,因此服务器拒绝提供请求的资源。与 401 Unauthorized 不同,服务器知道客户端的身份。 kForbidden = 403, // 服务器找不到请求的资源。 kNotFound = 404, // 服务器知道请求方法,但目标资源不支持该方法。 kMethodNotAllowed = 405, // 当 Web 服务器执行服务器驱动的内容协商后,找不到任何符合用户代理给定条件的内容时,会发送此响应。 kNotAcceptable = 406, // 类似于 401 Unauthorized,但需要通过代理进行身份验证。 kProxyAuthenticationRequired = 407, // 某些服务器会在空闲连接上发送此响应,即使客户端之前没有任何请求。这意味着服务器希望关闭此未使用的连接。 kRequestTimeout = 408, // 当请求与服务器的当前状态冲突时,发送此响应。 kConflict = 409, // 当请求的内容已从服务器永久删除,且没有转发地址时,发送此响应。 kGone = 410, // 服务器拒绝了请求,因为未定义 Content-Length 标头字段,而服务器需要它。 kLengthRequired = 411, // 在条件请求中,客户端在其标头中指明了服务器不满足的前提条件。 kPreconditionFailed = 412, // 请求体大于服务器定义的限制。 kContentTooLarge = 413, // 客户端请求的 URI 长度超过了服务器愿意解释的长度。 kURITooLong = 414, // 服务器不支持请求数据的媒体格式,因此服务器拒绝该请求。 kUnsupportedMediaType = 415, // 无法满足请求中 Range 标头字段指定的范围。可能范围超出了目标资源数据的大小。 kRangeNotSatisfiable = 416, // 此响应代码表示服务器无法满足 Expect 请求标头字段指示的期望。 kExpectationFailed = 417, // 服务器拒绝尝试用茶壶煮咖啡。 kIamATeapot = 418, // 请求被发送到了一个无法产生响应的服务器。 kMisdirectedRequest = 421, // 请求格式正确,但由于语义错误而无法被遵循。 kUnprocessableContent = 422, // 正在访问的资源已被锁定。 kLocked = 423, // 由于先前的请求失败,导致当前请求失败。 kFailedDependency = 424, // 表示服务器不愿意冒险处理一个可能被重放的请求。 kTooEarly = 425, // 服务器拒绝使用当前协议执行请求,但可能在客户端升级到其他协议后愿意执行。服务器在 426 响应中发送 Upgrade 标头以指示所需的协议。 kUpgradeRequired = 426, // 原始服务器要求请求是有条件的。此响应旨在防止"丢失更新"问题,即客户端 GET 资源状态,修改后 PUT 回服务器,而同时第三方已修改了服务器上的状态,导致冲突。 kPreconditionRequired = 428, // 用户在给定的时间内发送了太多请求(速率限制)。 kTooManyRequests = 429, // 服务器因请求头字段太大而不愿意处理该请求。 kRequestHeaderFieldsTooLarge = 431, // 用户代理请求了一个无法合法提供的资源,例如被政府审查的网页。 kUnavailableForLegalReasons = 451, // 服务器遇到了不知道如何处理的情况。此错误是通用性的,表示服务器找不到更合适的 5XX 状态码来响应。 kInternalServerError = 500, // 服务器不支持请求方法,无法处理。 kNotImplemented = 501, // 此错误响应意味着服务器作为网关或代理时,收到了一个无效的响应。 kBadGateway = 502, // 服务器尚未准备好处理请求。 kServiceUnavailable = 503, // 当服务器作为网关或代理,无法及时获得响应时,会给出此错误响应。 kGatewayTimeout = 504, // 服务器不支持请求中使用的 HTTP 版本。 kHTTPVersionNotSupported = 505, // 服务器存在内部配置错误:在内容协商过程中,被选中的变体被配置为自身参与内容协商,这导致在创建响应时出现循环引用。 kVariantAlsoNegotiates = 506, // 由于服务器无法存储成功完成请求所需的表示,因此无法对资源执行该方法。 kInsufficientStorage = 507, // 服务器在处理请求时检测到无限循环。 kLoopDetected = 508, // 客户端请求声明了一个应使用 HTTP 扩展(RFC 2774)来处理请求,但该扩展不受支持。 kNotExtended = 510, // 表示客户端需要进行身份验证才能获得网络访问权限。 kNetworkAuthenticationRequired = 511, //Not Standard Code By UnknownObject // 请求载体的格式错误,如:无法解析的JSON等。 k_uRequestFormatError = 489, // 请求无效。可能是由于未正确携带数据等必要信息。 k_uRequestInvalid = 490, // 请求URL超范围。此响应表示请求的URL是错误的。 k_uURLOutOfRange = 492, // 无效的请求主机。指示请求时使用了错误的域名/IP。 k_uInvalidRequestHost = 493, // IP地址被封禁。 k_uIPBlocked = 494, // 非法上传请求。指示本次上传请求不符合服务器规定。 k_uIllegalUpload = 495, // 文件格式错误。指示上传的文件格式不符合服务器规定。 k_uFileFormatError = 496, // 无效文件。处理请求所需的文件已过期/无法访问。 k_uInvalidFile = 497, // 上传的文件过大。非文件上传时应使用 413 Content Too Large。 k_uFileTooLarge = 498, // 每秒请求数过多。仅在一些特殊API中使用,常规情况需使用 429 Too Many Requests。 k_uRPSLimited = 499, // 子过程失败。服务器在处理请求的某个步骤中遇到无法恢复的错误。 k_uSubProcessFalied = 533, // 服务器检测到漏洞利用/可执行文件上传等网络攻击行为。 k_uServerHateYou = 540, // 检测到拒绝服务漏洞攻击。 k_uDoSFound = 550, // 检测到分布式拒绝服务漏洞攻击。 k_uDDoSFound = 551, // 未知的服务器错误。当服务器无法定位错误来源时返回。否则应使用 500 Internal Server Error。 k_uUnknownServerError = 560 }; // 路径穿透防御等级 enum class PathTraversalDefenceLevel { DenyAll, //拒绝所有带有对应特征的路径 AutoNormalize, //允许普通路径穿透,自动归一化,并要求进行安全路径检查 AllowNormal, //允许普通路径穿透,原样返回,要求进行安全路径检查 AllowAll [[deprecated("警告: AllowAll 已启用 - 路径穿透防御关闭 - 仅供测试环境使用.")]] //允许所有行为(仅供测试) }; class UNSWSC_DLL_EXPORT UrlQuery { public: UrlQuery(); ~UrlQuery(); // 显式支持深拷贝与移动,内部完美同步 webcc 状态 UrlQuery(const UrlQuery& other); UrlQuery& operator=(const UrlQuery& other); UrlQuery(UrlQuery&& other) noexcept; UrlQuery& operator=(UrlQuery&& other) noexcept; public: bool Empty() const; std::size_t Size() const; bool Has(const std::string& key) const; const std::string& Get(const std::string& key) const; std::pair Get(std::size_t index) const; std::string ToString(bool encode = true) const; private: friend class Request; class Impl; std::unique_ptr pimpl; explicit UrlQuery(std::unique_ptr impl); }; class UNSWSC_DLL_EXPORT FormPart { private: class Impl; private: friend class Request; friend class ::FileReceiver; std::unique_ptr pimpl; private: explicit FormPart(std::unique_ptr impl); public: ~FormPart(); public: std::string GetNameS() const; std::string_view GetName() const; std::string GetFileNameS() const; std::string_view GetFileName() const; std::string GetMediaTypeS() const; std::string_view GetMediaType() const; const std::string& GetData() const; std::size_t GetSize() const; std::size_t GetDataSize() const; }; using FormPartPtr = std::shared_ptr; class UNSWSC_DLL_EXPORT Request { private: class Impl; friend class ServerCore; friend class FileReceiverAdapter; friend class ServerProcessorAdapter; friend class SyncFileReceiverAdapter; std::unique_ptr pimpl; private: explicit Request(std::unique_ptr impl); public: ~Request(); Impl* GetImpl() const { return pimpl.get(); } public: // 基础请求信息 std::string GetMethodS() const; std::string_view GetMethod() const; std::string GetAddressS() const; std::string_view GetAddress() const; size_t GetContentLength() const; std::string GetDataS() const; std::string_view GetData() const; // 扁平化后的 Url 核心数据项 std::string GetSchemeS() const; std::string_view GetScheme() const; std::string GetHostS() const; std::string_view GetHost() const; int GetPortI() const; std::string GetPortS() const; std::string_view GetPort() const; std::string GetPathS() const; std::string_view GetPath() const; std::string GetQueryStringS() const; std::string_view GetQueryString() const; // 复杂复合对象获取 UrlQuery GetQuery() const; const std::vector& GetArgs() const; // 多部分表单(文件上传)支撑 bool IsForm() const; const std::vector& GetFormParts() const; // 请求头获取 bool HasHeader(std::string_view header) const; std::string GetHeader(std::string_view header, bool* existed = nullptr) const; std::vector> GetAllHeaders() const; }; class UNSWSC_DLL_EXPORT Response { private: class Impl; private: friend class ResponseBuilder; std::unique_ptr pimpl; private: explicit Response(std::unique_ptr impl); public: ~Response(); Impl* GetImpl() const { return pimpl.get(); } }; using RequestPtr = std::shared_ptr; using ResponsePtr = std::shared_ptr; }