| ... | @@ -577,21 +577,20 @@ pub const Reader = struct { | ... | @@ -577,21 +577,20 @@ pub const Reader = struct { |
| 577 | len: switch (chunk_len_ptr.*) { | 577 | len: switch (chunk_len_ptr.*) { |
| 578 | .head => { | 578 | .head => { |
| 579 | var cp: ChunkParser = .init; | 579 | var cp: ChunkParser = .init; |
| 580 | const i = cp.feed(in.bufferContents()); | 580 | while (true) { |
| 581 | switch (cp.state) { | 581 | const i = cp.feed(in.bufferContents()); |
| 582 | .invalid => return error.HttpChunkInvalid, | 582 | switch (cp.state) { |
| 583 | .data => { | 583 | .invalid => return error.HttpChunkInvalid, |
| 584 | if (i > max_chunk_header_len) return error.HttpChunkInvalid; | 584 | .data => { |
| 585 | in.toss(i); | 585 | in.toss(i); |
| 586 | }, | 586 | break; |
| 587 | else => { | 587 | }, |
| 588 | try in.fill(max_chunk_header_len); | 588 | else => { |
| 589 | const next_i = cp.feed(in.bufferContents()[i..]); | 589 | in.toss(i); |
| 590 | if (cp.state != .data) return error.HttpChunkInvalid; | 590 | try in.fillMore(); |
| 591 | const header_len = i + next_i; | 591 | continue; |
| 592 | if (header_len > max_chunk_header_len) return error.HttpChunkInvalid; | 592 | }, |
| 593 | in.toss(header_len); | 593 | } |
| 594 | }, | | |
| 595 | } | 594 | } |
| 596 | if (cp.chunk_len == 0) return parseTrailers(reader, 0); | 595 | if (cp.chunk_len == 0) return parseTrailers(reader, 0); |
| 597 | const n = try in.read(bw, limit.min(.limited(cp.chunk_len))); | 596 | const n = try in.read(bw, limit.min(.limited(cp.chunk_len))); |
| ... | @@ -650,24 +649,21 @@ pub const Reader = struct { | ... | @@ -650,24 +649,21 @@ pub const Reader = struct { |
| 650 | len: switch (chunk_len_ptr.*) { | 649 | len: switch (chunk_len_ptr.*) { |
| 651 | .head => { | 650 | .head => { |
| 652 | var cp: ChunkParser = .init; | 651 | var cp: ChunkParser = .init; |
| 653 | const available_buffer = in.bufferContents(); | 652 | while (true) { |
| 654 | const i = cp.feed(available_buffer); | 653 | const i = cp.feed(in.bufferContents()); |
| 655 | if (cp.state == .invalid) return error.HttpChunkInvalid; | 654 | switch (cp.state) { |
| 656 | if (i == available_buffer.len) { | 655 | .invalid => return error.HttpChunkInvalid, |
| 657 | if (already_requested_more) { | 656 | .data => { |
| 658 | chunk_len_ptr.* = .head; | 657 | in.toss(i); |
| 659 | return amt_read; | 658 | break; |
| | 659 | }, |
| | 660 | else => { |
| | 661 | in.toss(i); |
| | 662 | already_requested_more = true; |
| | 663 | try in.fillMore(); |
| | 664 | continue; |
| | 665 | }, |
| 660 | } | 666 | } |
| 661 | already_requested_more = true; | | |
| 662 | try in.fill(max_chunk_header_len); | | |
| 663 | const next_i = cp.feed(in.bufferContents()[i..]); | | |
| 664 | if (cp.state != .data) return error.HttpChunkInvalid; | | |
| 665 | const header_len = i + next_i; | | |
| 666 | if (header_len > max_chunk_header_len) return error.HttpChunkInvalid; | | |
| 667 | in.toss(header_len); | | |
| 668 | } else { | | |
| 669 | if (i > max_chunk_header_len) return error.HttpChunkInvalid; | | |
| 670 | in.toss(i); | | |
| 671 | } | 667 | } |
| 672 | if (cp.chunk_len == 0) return parseTrailers(reader, amt_read); | 668 | if (cp.chunk_len == 0) return parseTrailers(reader, amt_read); |
| 673 | continue :len .init(cp.chunk_len + 2); | 669 | continue :len .init(cp.chunk_len + 2); |
| ... | @@ -739,21 +735,20 @@ pub const Reader = struct { | ... | @@ -739,21 +735,20 @@ pub const Reader = struct { |
| 739 | len: switch (chunk_len_ptr.*) { | 735 | len: switch (chunk_len_ptr.*) { |
| 740 | .head => { | 736 | .head => { |
| 741 | var cp: ChunkParser = .init; | 737 | var cp: ChunkParser = .init; |
| 742 | const i = cp.feed(in.bufferContents()); | 738 | while (true) { |
| 743 | switch (cp.state) { | 739 | const i = cp.feed(in.bufferContents()); |
| 744 | .invalid => return error.HttpChunkInvalid, | 740 | switch (cp.state) { |
| 745 | .data => { | 741 | .invalid => return error.HttpChunkInvalid, |
| 746 | if (i > max_chunk_header_len) return error.HttpChunkInvalid; | 742 | .data => { |
| 747 | in.toss(i); | 743 | in.toss(i); |
| 748 | }, | 744 | break; |
| 749 | else => { | 745 | }, |
| 750 | try in.fill(max_chunk_header_len); | 746 | else => { |
| 751 | const next_i = cp.feed(in.bufferContents()[i..]); | 747 | in.toss(i); |
| 752 | if (cp.state != .data) return error.HttpChunkInvalid; | 748 | try in.fillMore(); |
| 753 | const header_len = i + next_i; | 749 | continue; |
| 754 | if (header_len > max_chunk_header_len) return error.HttpChunkInvalid; | 750 | }, |
| 755 | in.toss(header_len); | 751 | } |
| 756 | }, | | |
| 757 | } | 752 | } |
| 758 | if (cp.chunk_len == 0) return parseTrailers(reader, 0); | 753 | if (cp.chunk_len == 0) return parseTrailers(reader, 0); |
| 759 | const n = try in.discard(limit.min(.limited(cp.chunk_len))); | 754 | const n = try in.discard(limit.min(.limited(cp.chunk_len))); |
| ... | @@ -1010,16 +1005,14 @@ pub const BodyWriter = struct { | ... | @@ -1010,16 +1005,14 @@ pub const BodyWriter = struct { |
| 1010 | else => unreachable, // An earlier write call indicated more data would follow. | 1005 | else => unreachable, // An earlier write call indicated more data would follow. |
| 1011 | }, | 1006 | }, |
| 1012 | } | 1007 | } |
| 1013 | if (options.trailers.len > 0) { | 1008 | try bw.writeAll("0\r\n"); |
| 1014 | try bw.writeAll("0\r\n"); | 1009 | for (options.trailers) |trailer| { |
| 1015 | for (options.trailers) |trailer| { | 1010 | try bw.writeAll(trailer.name); |
| 1016 | try bw.writeAll(trailer.name); | 1011 | try bw.writeAll(": "); |
| 1017 | try bw.writeAll(": "); | 1012 | try bw.writeAll(trailer.value); |
| 1018 | try bw.writeAll(trailer.value); | | |
| 1019 | try bw.writeAll("\r\n"); | | |
| 1020 | } | | |
| 1021 | try bw.writeAll("\r\n"); | 1013 | try bw.writeAll("\r\n"); |
| 1022 | } | 1014 | } |
| | 1015 | try bw.writeAll("\r\n"); |
| 1023 | w.state = .end; | 1016 | w.state = .end; |
| 1024 | } | 1017 | } |
| 1025 | | 1018 | |