Skip to content
github-actions[bot] edited this page Jul 8, 2026 · 8 revisions

HTTP/1.1 协议

基础类型(HttpTypes

struct HttpText   { const char* Data; SIZE_T Length; };
struct HttpHeader { HttpText Name; HttpText Value; };

同处定义堆基元 HeapArray<T> / HeapObject<T> 与非分页池分配器(见 内存模型)。

请求构建(HttpRequestBuilder::Build

序列化 METHOD SP target SP HTTP/1.1\r\n + 头 + \r\n + body。要点:

  • 用测长 BufferWriter,目标缓冲不足返回 STATUS_BUFFER_TOO_SMALL 并写出所需长度。
  • Host 头总是首先发出(值来自 options.Host,不自动推导);随后按固定序 User-Agent、Content-Type、body 框定头、Connection、调用方额外头。
  • 方法枚举包含 CONNECT,可构建 CONNECT authority HTTP/1.1 请求;TRACE 不支持。
  • body:ContentLength 模式发 Content-LengthIncludeContentLength 可让 0 长 body 也发 Content-Length: 0);Chunked 模式发 Transfer-Encoding: chunked 并按 hex\r\n data \r\n ... 0\r\n 串行化,随后写出请求 trailer(若有)再以 \r\n 收尾。
  • 请求 trailer:仅在 Chunked 且确有 chunked 框定(有 body 或 IncludeContentLength)时可用,经 options.Trailers/TrailerCount 提供;字段名须为合法 token,禁止 trailer 字段 Content-Length/Transfer-Encoding/Host/Authorization/Proxy-Authorization/Cookie/Set-CookieSTATUS_NOT_SUPPORTED;公共 API 为 KhHttpRequestAddTrailer / khttp::RequestAddTrailer
  • 禁止的额外头Host/Content-Length/ConnectionSTATUS_INVALID_PARAMETERTransfer-Encoding/TESTATUS_NOT_SUPPORTEDTrailer 头仅在 chunked 框定下允许(否则 STATUS_NOT_SUPPORTED);调用方手写 Expect: 100-continue 且未通过库的 expect-continue 选项开启时 → STATUS_NOT_SUPPORTED
  • 引擎层在无 Accept-Encoding 时注入默认 gzip, deflate, br, identity(deflate 运行时不可用则 br, identity)。

流式请求体、Expect 与代理

  • 高层 BodyCreateStream / 底层 KhHttpRequestSetBodySource 使用调用方读取回调按块提供请求体;已知长度发送 Content-Length,未知长度配合 RequestBodyMode::Chunked 由库生成 chunked framing。
  • BodyAddTrailer* / KhHttpRequestAddTrailer 只在 chunked 请求体结束后发送 trailer,并继续拒绝禁止字段与 CRLF 注入。
  • SendFlagExpectContinue 显式开启 Expect: 100-continue,只有请求有 body 时才注入;收到 100 后发送 body,收到 final/417 不发送 body,等待超时后按 RFC 时序发送 body。
  • SessionConfig.Proxy / KhSessionOptions.Proxy 对 HTTPS 使用 CONNECT;对 http:// 使用 absolute-form request target,不建立 CONNECT 隧道,Proxy-Authorization 只来自显式代理配置。

响应解析(HttpParser::ParseResponse

  • 需完整头块(\r\n\r\n),否则 STATUS_MORE_PROCESSING_REQUIRED;头块 >64 KiB → STATUS_INVALID_NETWORK_RESPONSE
  • 状态行:必须 HTTP/<major>.<minor>仅接受 major==1 且 minor<=1;状态码恰 3 位、100..599。
  • 头:每行 ≤8 KiB;拒绝 obs-fold(行首 SP/TAB);名须为 token;值拒绝 <0x20(除 TAB)与 0x7f(允许高位字节);头数 ≥200 → STATUS_BUFFER_TOO_SMALL
  • body 框定:
    • 无 bodyResponseBodyForbidden(HEAD)或状态属 1xx/204/205/304。
    • 多个 Content-LengthTE+CL 冲突 → STATUS_INVALID_NETWORK_RESPONSE
    • chunked/TE 链 → HttpTransferCoding::DecodeResponseBody
    • Content-Length 路径:不足 → STATUS_MORE_PROCESSING_REQUIRED
    • close-delimited:仅当 MessageCompleteOnConnectionClose 且无 CL/TE。
  • 206 Partial Content 可用 HttpResponse::IsPartialContent 判断;GetContentRange 只读解析 Content-Range: bytes ...,不会影响 body 框定。

chunked 解码

块数 ≤8192、chunk-size 行 ≤32;严格 chunk 扩展语法(;name[=value|quoted]);终止块后解析 trailer:每行 ≤8 KiB、trailer 数 ≤256;禁止 trailer 字段Content-Length/Transfer-Encoding/Host/Authorization/Proxy-Authorization/Cookie/Set-CookieSTATUS_INVALID_NETWORK_RESPONSE

内容编码 Content-EncodingHttpContentEncoding + HttpCoding

coding 实现要点
gzip RFC1952 头解析,校验头 CRC16、尾 CRC32、ISIZE
deflate 自动识别 zlib 包装并校验 Adler-32;裸 DEFLATE 用内核 RtlDecompressBufferEx,附运行时探测 DeflateRuntimeAvailable
br 内置 Brotli 解码
compress 完整 LZW(.Z,9–16 bit,block 模式)
identity 跳过
  • 链最多 2 级(>2 → STATUS_NOT_SUPPORTED),按反序解码。
  • 解压炸弹防护:decoded aggregate 跟随响应/调用方容量,单级膨胀比 ≤64(MaxDecodeExpansionRatio),超限 → STATUS_INVALID_NETWORK_RESPONSE
  • 未知 coding → STATUS_NOT_SUPPORTED

传输编码 Transfer-EncodingHttpTransferCoding

  • 识别 chunked/gzip/deflate/compress,最多 4 级;identitySTATUS_INVALID_NETWORK_RESPONSEbrSTATUS_NOT_SUPPORTED;带参数 token → 非法;重复 chunked → 非法。
  • 反序解码,仅最外层 chunked 收 trailer;非最外 chunked 未吃完输入 → 非法。

English

HTTP/1.1 Protocol

Namespace KernelHttp::http, grounded in src/KernelHttpLib/http/.

Request building (HttpRequestBuilder::Build): serializes request line + headers + body via a length-measuring BufferWriter (STATUS_BUFFER_TOO_SMALL with required size if it won't fit); Host emitted first from options.Host; CONNECT requests can be built (CONNECT authority HTTP/1.1), TRACE is unsupported; body via Content-Length, builder-generated chunked, or streaming body sources (BodyCreateStream / KhHttpRequestSetBodySource); request trailers are supported only with chunked framing; forbidden extra headers Host/Content-Length/Connection (STATUS_INVALID_PARAMETER) and Transfer-Encoding/TE (STATUS_NOT_SUPPORTED); caller-supplied Expect: 100-continue with a body is accepted only through the library expect-continue path (SendFlagExpectContinue); Trailer is allowed only for chunked request trailers; engine injects default Accept-Encoding: gzip, deflate, br, identity (or br, identity when deflate runtime is unavailable). HTTPS proxy uses CONNECT; plaintext HTTP over proxy uses absolute-form targets and does not create a CONNECT tunnel.

Response parsing (HttpParser::ParseResponse): full header block required (else STATUS_MORE_PROCESSING_REQUIRED); >64 KiB header block rejected; status line accepts only HTTP major==1, minor<=1, 3-digit 100..599; per-line ≤8 KiB, obs-fold rejected, token names, value rejects <0x20 (except TAB) and 0x7f; ≥200 headers → STATUS_BUFFER_TOO_SMALL. No-body for HEAD/1xx/204/205/304; duplicate Content-Length or TE+CL conflict → STATUS_INVALID_NETWORK_RESPONSE; chunked ≤8192 chunks, strict extension grammar, forbidden trailers rejected; IsPartialContent / GetContentRange expose read-only 206 / Content-Range semantics.

Content-Encoding gzip (CRC16/CRC32/ISIZE verified), deflate (zlib autodetect + Adler-32, kernel RtlDecompressBufferEx with runtime probe), br (bundled Brotli), compress (full LZW), identity — up to 2 codings, reverse-decoded, with 64× per-step decompression-bomb guard. Transfer-Encoding chunked/gzip/deflate/compress up to 4 (identity rejected, brSTATUS_NOT_SUPPORTED), reverse-decoded with trailers only on the outermost chunked layer.

Clone this wiki locally