Skip to content

Commit

Permalink
Merge pull request #25 from metabahn/add/reset
Browse files Browse the repository at this point in the history
Add support for resetting the parser
  • Loading branch information
bryanp authored Sep 9, 2021
2 parents c954bde + 26160b8 commit 969a92f
Show file tree
Hide file tree
Showing 10 changed files with 97 additions and 5 deletions.
2 changes: 1 addition & 1 deletion ffi/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,5 @@ parser << "GET / HTTP/1.1\r\n\r\n"

# Reset the parser for the next request:
#
parser.finish
parser.reset
```
1 change: 1 addition & 0 deletions ffi/lib/llhttp.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,5 @@ class Callbacks < FFI::Struct
attach_function :llhttp_get_error_reason, [:pointer], :string
attach_function :llhttp_should_keep_alive, [:pointer], :int
attach_function :llhttp_finish, [:pointer], :int
attach_function :llhttp_reset, [:pointer], :void
end
8 changes: 7 additions & 1 deletion ffi/lib/llhttp/parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,18 @@ def keep_alive?
LLHttp.llhttp_should_keep_alive(@pointer) == 1
end

# [public] Get ready to parse the next request.
# [public] Tells the parser we are finished.
#
def finish
LLHttp.llhttp_finish(@pointer)
end

# [public] Get ready to parse the next request/response.
#
def reset
LLHttp.llhttp_reset(@pointer)
end

CALLBACKS.each do |callback|
class_eval(
<<~RB, __FILE__, __LINE__ + 1
Expand Down
2 changes: 1 addition & 1 deletion mri/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,5 @@ parser << "GET / HTTP/1.1\r\n\r\n"

# Reset the parser for the next request:
#
parser.finish
parser.reset
```
13 changes: 13 additions & 0 deletions mri/ext/llhttp/llhttp_ext.c
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,18 @@ VALUE rb_llhttp_finish(VALUE self) {
return Qtrue;
}

VALUE rb_llhttp_reset(VALUE self) {
llhttp_t *parser;

Data_Get_Struct(self, llhttp_t, parser);

llhttp_settings_t *settings = parser->settings;

llhttp_reset(parser);

return Qtrue;
}

VALUE rb_llhttp_content_length(VALUE self) {
llhttp_t *parser;

Expand Down Expand Up @@ -301,6 +313,7 @@ void Init_llhttp_ext(void) {
rb_define_method(cParser, "<<", rb_llhttp_parse, 1);
rb_define_method(cParser, "parse", rb_llhttp_parse, 1);
rb_define_method(cParser, "finish", rb_llhttp_finish, 0);
rb_define_method(cParser, "reset", rb_llhttp_reset, 0);

rb_define_method(cParser, "content_length", rb_llhttp_content_length, 0);
rb_define_method(cParser, "method_name", rb_llhttp_method_name, 0);
Expand Down
4 changes: 4 additions & 0 deletions mri/lib/llhttp/parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ module LLHttp
#
# Call `LLHttp::Parser#finish` when processing is complete for the current request or response.
#
# Resetting
#
# Call `LLHttp::Parser#reset` to reset the parser for the next request or response.
#
class Parser
LLHTTP_TYPES = {both: 0, request: 1, response: 2}.freeze

Expand Down
2 changes: 1 addition & 1 deletion spec/acceptance/support/server.rb
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def run
ensure
stream.close

@parser.finish
@parser.reset
end

private def parse_next(stream)
Expand Down
64 changes: 64 additions & 0 deletions spec/integration/no_content_length_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# frozen_string_literal: true

require_relative "support/context/parsing"

RSpec.describe "parsing responses without a content length" do
include_context "parsing"

shared_examples "examples" do
let(:extension) {
proc {
def on_message_begin
@calls << :on_message_begin
end

def on_header_field(_)
@calls << :on_header_field
end

def on_header_value(_)
@calls << :on_header_value
end

def on_headers_complete
@calls << :on_headers_complete
end

def on_body(_)
@calls << :on_body
end

def on_message_complete
@calls << :on_message_complete
end
}
}

it "parses correctly" do
10_000.times do
parse

instance.reset
end

expect(delegate.calls.count(:on_message_begin)).to eq(10_000)
expect(delegate.calls.count(:on_header_field)).to eq(0)
expect(delegate.calls.count(:on_header_value)).to eq(0)
expect(delegate.calls.count(:on_headers_complete)).to eq(10_000)
expect(delegate.calls.count(:on_body)).to eq(0)
expect(delegate.calls.count(:on_message_complete)).to eq(0)
end
end

context "response" do
let(:type) {
:response
}

let(:fixture) {
:response_sans_content_length
}

include_examples "examples"
end
end
2 changes: 1 addition & 1 deletion spec/integration/reusing_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def on_message_complete
10_000.times do
parse

instance.finish
instance.reset
end

expect(delegate.calls.count(:on_message_begin)).to eq(10_000)
Expand Down
4 changes: 4 additions & 0 deletions spec/integration/support/context/parsing.rb
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ def initialize(context)
"body2\n",
"body3\n",
"\r\n"
],

response_sans_content_length: [
"HTTP/1.1 200 OK\r\n\r\n"
]
}
}
Expand Down

0 comments on commit 969a92f

Please sign in to comment.