| ... | @@ -31,7 +31,7 @@ pub const State = enum { | ... | @@ -31,7 +31,7 @@ pub const State = enum { |
| 31 | | 31 | |
| 32 | /// Initialize an HTTP server that can respond to multiple requests on the same | 32 | /// Initialize an HTTP server that can respond to multiple requests on the same |
| 33 | /// connection. | 33 | /// connection. |
| 34 | /// The returned `Server` is ready for `readRequest` to be called. | 34 | /// The returned `Server` is ready for `receiveHead` to be called. |
| 35 | pub fn init(connection: net.Server.Connection, read_buffer: []u8) Server { | 35 | pub fn init(connection: net.Server.Connection, read_buffer: []u8) Server { |
| 36 | return .{ | 36 | return .{ |
| 37 | .connection = connection, | 37 | .connection = connection, |
| ... | @@ -51,6 +51,12 @@ pub const ReceiveHeadError = error{ | ... | @@ -51,6 +51,12 @@ pub const ReceiveHeadError = error{ |
| 51 | HttpHeadersInvalid, | 51 | HttpHeadersInvalid, |
| 52 | /// A low level I/O error occurred trying to read the headers. | 52 | /// A low level I/O error occurred trying to read the headers. |
| 53 | HttpHeadersUnreadable, | 53 | HttpHeadersUnreadable, |
| | 54 | /// Partial HTTP request was received but the connection was closed before |
| | 55 | /// fully receiving the headers. |
| | 56 | HttpRequestTruncated, |
| | 57 | /// The client sent 0 bytes of headers before closing the stream. |
| | 58 | /// In other words, a keep-alive connection was finally closed. |
| | 59 | HttpConnectionClosing, |
| 54 | }; | 60 | }; |
| 55 | | 61 | |
| 56 | /// The header bytes reference the read buffer that Server was initialized with | 62 | /// The header bytes reference the read buffer that Server was initialized with |
| ... | @@ -63,8 +69,11 @@ pub fn receiveHead(s: *Server) ReceiveHeadError!Request { | ... | @@ -63,8 +69,11 @@ pub fn receiveHead(s: *Server) ReceiveHeadError!Request { |
| 63 | // In case of a reused connection, move the next request's bytes to the | 69 | // In case of a reused connection, move the next request's bytes to the |
| 64 | // beginning of the buffer. | 70 | // beginning of the buffer. |
| 65 | if (s.next_request_start > 0) { | 71 | if (s.next_request_start > 0) { |
| 66 | if (s.read_buffer_len > s.next_request_start) rebase(s, 0); | 72 | if (s.read_buffer_len > s.next_request_start) { |
| 67 | s.next_request_start = 0; | 73 | rebase(s, 0); |
| | 74 | } else { |
| | 75 | s.read_buffer_len = 0; |
| | 76 | } |
| 68 | } | 77 | } |
| 69 | | 78 | |
| 70 | var hp: http.HeadParser = .{}; | 79 | var hp: http.HeadParser = .{}; |
| ... | @@ -82,6 +91,13 @@ pub fn receiveHead(s: *Server) ReceiveHeadError!Request { | ... | @@ -82,6 +91,13 @@ pub fn receiveHead(s: *Server) ReceiveHeadError!Request { |
| 82 | return error.HttpHeadersOversize; | 91 | return error.HttpHeadersOversize; |
| 83 | const read_n = s.connection.stream.read(buf) catch | 92 | const read_n = s.connection.stream.read(buf) catch |
| 84 | return error.HttpHeadersUnreadable; | 93 | return error.HttpHeadersUnreadable; |
| | 94 | if (read_n == 0) { |
| | 95 | if (s.read_buffer_len > 0) { |
| | 96 | return error.HttpRequestTruncated; |
| | 97 | } else { |
| | 98 | return error.HttpConnectionClosing; |
| | 99 | } |
| | 100 | } |
| 85 | s.read_buffer_len += read_n; | 101 | s.read_buffer_len += read_n; |
| 86 | const bytes = buf[0..read_n]; | 102 | const bytes = buf[0..read_n]; |
| 87 | const end = hp.feed(bytes); | 103 | const end = hp.feed(bytes); |