| author | |
| committer | |
| log | c523b5421be86cdd0591a5672eeaea30fb142fe4 |
| tree | 17b23ca55286378604d878930523a32cf0fe796b |
| parent | 16f89eab45c4356f8f1d824c342e76aee8ddff90 |
| signature |
3 files changed, 52 insertions(+), 55 deletions(-)
lib/std/http.zig+3| ... | ... | @@ -289,14 +289,17 @@ pub const Status = enum(u10) { |
| 289 | 289 | |
| 290 | 290 | pub const TransferEncoding = enum { |
| 291 | 291 | chunked, |
| 292 | none, | |
| 292 | 293 | // compression is intentionally omitted here, as std.http.Client stores it as content-encoding |
| 293 | 294 | }; |
| 294 | 295 | |
| 295 | 296 | pub const ContentEncoding = enum { |
| 296 | 297 | identity, |
| 297 | 298 | compress, |
| 299 | @"x-compress", | |
| 298 | 300 | deflate, |
| 299 | 301 | gzip, |
| 302 | @"x-gzip", | |
| 300 | 303 | zstd, |
| 301 | 304 | }; |
| 302 | 305 |
lib/std/http/Client.zig+24-27| ... | ... | @@ -425,27 +425,23 @@ pub const Response = struct { |
| 425 | 425 | // Transfer-Encoding: deflate, chunked |
| 426 | 426 | var iter = mem.splitBackwardsScalar(u8, header_value, ','); |
| 427 | 427 | |
| 428 | if (iter.next()) |first| { | |
| 429 | const trimmed = mem.trim(u8, first, " "); | |
| 430 | ||
| 431 | if (std.meta.stringToEnum(http.TransferEncoding, trimmed)) |te| { | |
| 432 | if (res.transfer_encoding != null) return error.HttpHeadersInvalid; | |
| 433 | res.transfer_encoding = te; | |
| 434 | } else if (std.meta.stringToEnum(http.ContentEncoding, trimmed)) |ce| { | |
| 435 | if (res.transfer_compression != null) return error.HttpHeadersInvalid; | |
| 436 | res.transfer_compression = ce; | |
| 437 | } else { | |
| 438 | return error.HttpTransferEncodingUnsupported; | |
| 439 | } | |
| 440 | } | |
| 428 | const first = iter.first(); | |
| 429 | const trimmed_first = mem.trim(u8, first, " "); | |
| 441 | 430 | |
| 442 | if (iter.next()) |second| { | |
| 443 | if (res.transfer_compression != null) return error.HttpTransferEncodingUnsupported; | |
| 431 | var next: ?[]const u8 = first; | |
| 432 | if (std.meta.stringToEnum(http.TransferEncoding, trimmed_first)) |transfer| { | |
| 433 | if (res.transfer_encoding != .none) return error.HttpHeadersInvalid; // we already have a transfer encoding | |
| 434 | res.transfer_encoding = transfer; | |
| 444 | 435 | |
| 445 | const trimmed = mem.trim(u8, second, " "); | |
| 436 | next = iter.next(); | |
| 437 | } | |
| 438 | ||
| 439 | if (next) |second| { | |
| 440 | const trimmed_second = mem.trim(u8, second, " "); | |
| 446 | 441 | |
| 447 | if (std.meta.stringToEnum(http.ContentEncoding, trimmed)) |ce| { | |
| 448 | res.transfer_compression = ce; | |
| 442 | if (std.meta.stringToEnum(http.ContentEncoding, trimmed_second)) |transfer| { | |
| 443 | if (res.transfer_compression != .identity) return error.HttpHeadersInvalid; // double compression is not supported | |
| 444 | res.transfer_compression = transfer; | |
| 449 | 445 | } else { |
| 450 | 446 | return error.HttpTransferEncodingUnsupported; |
| 451 | 447 | } |
| ... | ... | @@ -459,7 +455,7 @@ pub const Response = struct { |
| 459 | 455 | |
| 460 | 456 | res.content_length = content_length; |
| 461 | 457 | } else if (std.ascii.eqlIgnoreCase(header_name, "content-encoding")) { |
| 462 | if (res.transfer_compression != null) return error.HttpHeadersInvalid; | |
| 458 | if (res.transfer_compression != .identity) return error.HttpHeadersInvalid; | |
| 463 | 459 | |
| 464 | 460 | const trimmed = mem.trim(u8, header_value, " "); |
| 465 | 461 | |
| ... | ... | @@ -494,8 +490,8 @@ pub const Response = struct { |
| 494 | 490 | reason: []const u8, |
| 495 | 491 | |
| 496 | 492 | content_length: ?u64 = null, |
| 497 | transfer_encoding: ?http.TransferEncoding = null, | |
| 498 | transfer_compression: ?http.ContentEncoding = null, | |
| 493 | transfer_encoding: http.TransferEncoding = .none, | |
| 494 | transfer_compression: http.ContentEncoding = .identity, | |
| 499 | 495 | |
| 500 | 496 | headers: http.Headers, |
| 501 | 497 | parser: proto.HeadersParser, |
| ... | ... | @@ -771,8 +767,9 @@ pub const Request = struct { |
| 771 | 767 | req.connection.?.closing = true; |
| 772 | 768 | } |
| 773 | 769 | |
| 774 | if (req.response.transfer_encoding) |te| { | |
| 775 | switch (te) { | |
| 770 | if (req.response.transfer_encoding != .none) { | |
| 771 | switch (req.response.transfer_encoding) { | |
| 772 | .none => unreachable, | |
| 776 | 773 | .chunked => { |
| 777 | 774 | req.response.parser.next_chunk_length = 0; |
| 778 | 775 | req.response.parser.state = .chunk_head_size; |
| ... | ... | @@ -840,19 +837,19 @@ pub const Request = struct { |
| 840 | 837 | } else { |
| 841 | 838 | req.response.skip = false; |
| 842 | 839 | if (!req.response.parser.done) { |
| 843 | if (req.response.transfer_compression) |tc| switch (tc) { | |
| 840 | switch (req.response.transfer_compression) { | |
| 844 | 841 | .identity => req.response.compression = .none, |
| 845 | .compress => return error.CompressionNotSupported, | |
| 842 | .compress, .@"x-compress" => return error.CompressionNotSupported, | |
| 846 | 843 | .deflate => req.response.compression = .{ |
| 847 | 844 | .deflate = std.compress.zlib.decompressStream(req.client.allocator, req.transferReader()) catch return error.CompressionInitializationFailed, |
| 848 | 845 | }, |
| 849 | .gzip => req.response.compression = .{ | |
| 846 | .gzip, .@"x-gzip" => req.response.compression = .{ | |
| 850 | 847 | .gzip = std.compress.gzip.decompress(req.client.allocator, req.transferReader()) catch return error.CompressionInitializationFailed, |
| 851 | 848 | }, |
| 852 | 849 | .zstd => req.response.compression = .{ |
| 853 | 850 | .zstd = std.compress.zstd.decompressStream(req.client.allocator, req.transferReader()), |
| 854 | 851 | }, |
| 855 | }; | |
| 852 | } | |
| 856 | 853 | } |
| 857 | 854 | |
| 858 | 855 | break; |
lib/std/http/Server.zig+25-28| ... | ... | @@ -228,27 +228,23 @@ pub const Request = struct { |
| 228 | 228 | // Transfer-Encoding: deflate, chunked |
| 229 | 229 | var iter = mem.splitBackwardsScalar(u8, header_value, ','); |
| 230 | 230 | |
| 231 | if (iter.next()) |first| { | |
| 232 | const trimmed = mem.trim(u8, first, " "); | |
| 233 | ||
| 234 | if (std.meta.stringToEnum(http.TransferEncoding, trimmed)) |te| { | |
| 235 | if (req.transfer_encoding != null) return error.HttpHeadersInvalid; | |
| 236 | req.transfer_encoding = te; | |
| 237 | } else if (std.meta.stringToEnum(http.ContentEncoding, trimmed)) |ce| { | |
| 238 | if (req.transfer_compression != null) return error.HttpHeadersInvalid; | |
| 239 | req.transfer_compression = ce; | |
| 240 | } else { | |
| 241 | return error.HttpTransferEncodingUnsupported; | |
| 242 | } | |
| 243 | } | |
| 231 | const first = iter.first(); | |
| 232 | const trimmed_first = mem.trim(u8, first, " "); | |
| 244 | 233 | |
| 245 | if (iter.next()) |second| { | |
| 246 | if (req.transfer_compression != null) return error.HttpTransferEncodingUnsupported; | |
| 234 | var next: ?[]const u8 = first; | |
| 235 | if (std.meta.stringToEnum(http.TransferEncoding, trimmed_first)) |transfer| { | |
| 236 | if (req.transfer_encoding != .none) return error.HttpHeadersInvalid; // we already have a transfer encoding | |
| 237 | req.transfer_encoding = transfer; | |
| 247 | 238 | |
| 248 | const trimmed = mem.trim(u8, second, " "); | |
| 239 | next = iter.next(); | |
| 240 | } | |
| 241 | ||
| 242 | if (next) |second| { | |
| 243 | const trimmed_second = mem.trim(u8, second, " "); | |
| 249 | 244 | |
| 250 | if (std.meta.stringToEnum(http.ContentEncoding, trimmed)) |ce| { | |
| 251 | req.transfer_compression = ce; | |
| 245 | if (std.meta.stringToEnum(http.ContentEncoding, trimmed_second)) |transfer| { | |
| 246 | if (req.transfer_compression != .identity) return error.HttpHeadersInvalid; // double compression is not supported | |
| 247 | req.transfer_compression = transfer; | |
| 252 | 248 | } else { |
| 253 | 249 | return error.HttpTransferEncodingUnsupported; |
| 254 | 250 | } |
| ... | ... | @@ -256,7 +252,7 @@ pub const Request = struct { |
| 256 | 252 | |
| 257 | 253 | if (iter.next()) |_| return error.HttpTransferEncodingUnsupported; |
| 258 | 254 | } else if (std.ascii.eqlIgnoreCase(header_name, "content-encoding")) { |
| 259 | if (req.transfer_compression != null) return error.HttpHeadersInvalid; | |
| 255 | if (req.transfer_compression != .identity) return error.HttpHeadersInvalid; | |
| 260 | 256 | |
| 261 | 257 | const trimmed = mem.trim(u8, header_value, " "); |
| 262 | 258 | |
| ... | ... | @@ -278,8 +274,8 @@ pub const Request = struct { |
| 278 | 274 | version: http.Version, |
| 279 | 275 | |
| 280 | 276 | content_length: ?u64 = null, |
| 281 | transfer_encoding: ?http.TransferEncoding = null, | |
| 282 | transfer_compression: ?http.ContentEncoding = null, | |
| 277 | transfer_encoding: http.TransferEncoding = .none, | |
| 278 | transfer_compression: http.ContentEncoding = .identity, | |
| 283 | 279 | |
| 284 | 280 | headers: http.Headers, |
| 285 | 281 | parser: proto.HeadersParser, |
| ... | ... | @@ -511,8 +507,9 @@ pub const Response = struct { |
| 511 | 507 | res.request.headers = .{ .allocator = res.allocator, .owned = true }; |
| 512 | 508 | try res.request.parse(res.request.parser.header_bytes.items); |
| 513 | 509 | |
| 514 | if (res.request.transfer_encoding) |te| { | |
| 515 | switch (te) { | |
| 510 | if (res.request.transfer_encoding != .none) { | |
| 511 | switch (res.request.transfer_encoding) { | |
| 512 | .none => unreachable, | |
| 516 | 513 | .chunked => { |
| 517 | 514 | res.request.parser.next_chunk_length = 0; |
| 518 | 515 | res.request.parser.state = .chunk_head_size; |
| ... | ... | @@ -527,19 +524,19 @@ pub const Response = struct { |
| 527 | 524 | } |
| 528 | 525 | |
| 529 | 526 | if (!res.request.parser.done) { |
| 530 | if (res.request.transfer_compression) |tc| switch (tc) { | |
| 527 | switch (res.request.transfer_compression) { | |
| 531 | 528 | .identity => res.request.compression = .none, |
| 532 | .compress => return error.CompressionNotSupported, | |
| 529 | .compress, .@"x-compress" => return error.CompressionNotSupported, | |
| 533 | 530 | .deflate => res.request.compression = .{ |
| 534 | 531 | .deflate = std.compress.zlib.decompressStream(res.allocator, res.transferReader()) catch return error.CompressionInitializationFailed, |
| 535 | 532 | }, |
| 536 | .gzip => res.request.compression = .{ | |
| 533 | .gzip, .@"x-gzip" => res.request.compression = .{ | |
| 537 | 534 | .gzip = std.compress.gzip.decompress(res.allocator, res.transferReader()) catch return error.CompressionInitializationFailed, |
| 538 | 535 | }, |
| 539 | 536 | .zstd => res.request.compression = .{ |
| 540 | 537 | .zstd = std.compress.zstd.decompressStream(res.allocator, res.transferReader()), |
| 541 | 538 | }, |
| 542 | }; | |
| 539 | } | |
| 543 | 540 | } |
| 544 | 541 | } |
| 545 | 542 | |
| ... | ... | @@ -754,7 +751,7 @@ test "HTTP server handles a chunked transfer coding request" { |
| 754 | 751 | defer _ = res.reset(); |
| 755 | 752 | try res.wait(); |
| 756 | 753 | |
| 757 | try expect(res.request.transfer_encoding.? == .chunked); | |
| 754 | try expect(res.request.transfer_encoding == .chunked); | |
| 758 | 755 | |
| 759 | 756 | const server_body: []const u8 = "message from server!\n"; |
| 760 | 757 | res.transfer_encoding = .{ .content_length = server_body.len }; |