From 808a5a44ec58b5f0d0ae7164a71ccce01b7d4a3a Mon Sep 17 00:00:00 2001 From: Matteo Collina Date: Fri, 9 Oct 2026 17:05:34 +0200 Subject: [PATCH] fix: reject partial start lines at EOF --- parser/src/lib.rs | 4 ++-- parser/tests/basic.rs | 18 +++++++++++++++++- parser/wasm/test/basic.test.js | 14 ++++++++++++++ 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/parser/src/lib.rs b/parser/src/lib.rs index f5f0b50..95b28db 100644 --- a/parser/src/lib.rs +++ b/parser/src/lib.rs @@ -265,8 +265,8 @@ impl Parser { /// put the parser in the error state. pub fn finish(&mut self) { match self.state { - // If the parser is one of the initial states, simply jump to finish - STATE_START | STATE_REQUEST_LINE | STATE_STATUS_LINE | STATE_FINISH => { + // An untouched or already finished parser can finish cleanly. + STATE_START | STATE_FINISH => { self.state = STATE_FINISH; } STATE_BODY_WITH_NO_LENGTH => { diff --git a/parser/tests/basic.rs b/parser/tests/basic.rs index 278d194..65c335a 100644 --- a/parser/tests/basic.rs +++ b/parser/tests/basic.rs @@ -4,7 +4,7 @@ mod helpers; use std::ffi::c_uchar; use milo_parser::{ - CALLBACK_ACTIVE_ON_HEADERS, ERROR_NONE, ERROR_UNEXPECTED_CHARACTER, ERROR_UNEXPECTED_STATE, + CALLBACK_ACTIVE_ON_HEADERS, ERROR_NONE, ERROR_UNEXPECTED_CHARACTER, ERROR_UNEXPECTED_EOF, ERROR_UNEXPECTED_STATE, EVENT_ACTIVE_ON_HEADER_NAME, EVENT_ACTIVE_ON_HEADER_VALUE, STATE_BODY_DECISION, STATE_ERROR, STATE_FINISH, STATE_HEADER, STATE_START, }; @@ -678,6 +678,22 @@ fn basic_finish_logic() { assert_eq!(parser.state, STATE_HEADER); parser.finish(); assert_eq!(parser.state, STATE_ERROR); + + parser.reset(false); + let partial_request = b"G"; + assert_eq!(parser.parse(partial_request.as_ptr(), partial_request.len()), 0); + parser.finish(); + assert_eq!(parser.state, STATE_ERROR); + assert_eq!(parser.error_code, ERROR_UNEXPECTED_EOF); + + parser.reset(false); + parser.autodetect = false; + parser.is_request = false; + let partial_response = b"HTTP"; + assert_eq!(parser.parse(partial_response.as_ptr(), partial_response.len()), 0); + parser.finish(); + assert_eq!(parser.state, STATE_ERROR); + assert_eq!(parser.error_code, ERROR_UNEXPECTED_EOF); } #[test] diff --git a/parser/wasm/test/basic.test.js b/parser/wasm/test/basic.test.js index 716ccd2..ea8b4ce 100644 --- a/parser/wasm/test/basic.test.js +++ b/parser/wasm/test/basic.test.js @@ -491,6 +491,20 @@ it('basic_finish_logic', t => { assert.equal(milo.getState(parser), milo.STATE_HEADER) milo.finish(parser) assert.equal(milo.getState(parser), milo.STATE_ERROR) + + milo.reset(parser, false) + assert.equal(parse('G'), 0) + milo.finish(parser) + assert.equal(milo.getState(parser), milo.STATE_ERROR) + assert.equal(milo.getErrorCode(parser), milo.ERROR_UNEXPECTED_EOF) + + milo.reset(parser, false) + milo.setShouldAutodetect(parser, false) + milo.setIsRequest(parser, false) + assert.equal(parse('HTTP'), 0) + milo.finish(parser) + assert.equal(milo.getState(parser), milo.STATE_ERROR) + assert.equal(milo.getErrorCode(parser), milo.ERROR_UNEXPECTED_EOF) }) it('basic_empty_fields', t => {