Skip to content

Commit

Permalink
Add experimental 'strict' mode for matching headers with '-' and '_' …
Browse files Browse the repository at this point in the history
…characters; add pending specs for future 'fields' method
  • Loading branch information
jsl committed Dec 3, 2010
1 parent 11f1131 commit c9916ef
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 9 deletions.
26 changes: 17 additions & 9 deletions lib/http_headers.rb
Original file line number Original file line Diff line number Diff line change
@@ -1,33 +1,41 @@
# Class HttpHeaders parses a http header_str from Curl::Easy into component parts. # Class HttpHeaders parses a http header_str from Curl::Easy into component parts.
class HttpHeaders class HttpHeaders


attr_reader :content attr_reader :content, :strict_mode


def initialize(str) DEFAULTS = { :strict => true }

def initialize(str, opts = {})
@strict_mode = opts.keys.include?(:strict) ? opts[:strict] : DEFAULTS[:strict]
@content = str.split(/\\r\\n|\n|\r/) @content = str.split(/\\r\\n|\n|\r/)
end end


def version def version
@content[0].match(/HTTP\/\d\.\d/)[0] content[0].match(/HTTP\/\d\.\d/)[0]
end end


def response_code def response_code
@content[0].match(/HTTP\/\d\.\d (\d{3}.*)/)[1] content[0].match(/HTTP\/\d\.\d (\d{3}.*)/)[1]
end end


def method_missing(sym, *args) def method_missing(sym, *args)
detect_multi_value_keys(sym) detect_multi_value_keys(sym)
end end

private private


# Turns the given sym into a String after replacing the '_' character with the '-' # Turns the given sym into a String after replacing the '_' character with the '-'
def method_sym_to_http_key(sym) def method_sym_to_http_pattern(sym)
sym.to_s.gsub('_', '-') sym_s = sym.to_s
if strict_mode
sym_s.gsub('_', '-')
else
sym_s.gsub('_', "[-_]")
end
end end


def detect_multi_value_keys(tag) def detect_multi_value_keys(tag)
tag = method_sym_to_http_key(tag) tag = method_sym_to_http_pattern(tag)
regexp = /^#{tag}:/i regexp = /^#{tag}:/i
results = @content.select{|e| e =~ regexp }.map{|e| value_from(e)} results = @content.select{|e| e =~ regexp }.map{|e| value_from(e)}
results.size <= 1 ? results.first : results results.size <= 1 ? results.first : results
Expand Down
31 changes: 31 additions & 0 deletions spec/http_headers_spec.rb
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -41,6 +41,23 @@
HttpHeaders.new('Pragma: no-cache').pragma.should == 'no-cache' HttpHeaders.new('Pragma: no-cache').pragma.should == 'no-cache'
end end


describe "#fields" do

before {pending}

it "should return a collection of fields in the HTTP header" do
HttpHeaders.new('Pragma: no-cache\r\nCache-Control: private').field_names.should == ['Pragma', 'Cache-Control']
end

it "should not include the header" do
HttpHeaders.new('HTTP/1.1 200 OK\r\n').response_code.should == [ ]
end

it "should remove duplicates from the list" do
HttpHeaders.new('Set-Cookie: foo\r\nSet-Cookie: bar').field_names.should == ['Set-Cookie']
end
end

describe "breaking lines in header" do describe "breaking lines in header" do
it "should parse fields when separated by a normal newline" do it "should parse fields when separated by a normal newline" do
header = HttpHeaders.new(<<-EOS) header = HttpHeaders.new(<<-EOS)
Expand All @@ -57,6 +74,20 @@
end end
end end


describe "strict mode" do
it "should not recognize headers with values containing _ if strict mode is on" do
HttpHeaders.new("Foo_bar: baz", :strict => true).foo_bar.should be_nil
end

it "should recognize headers with values containing _ if strict mode is off" do
HttpHeaders.new("Foo_bar: baz", :strict => false).foo_bar.should == 'baz'
end

it "should have strict mode on by default" do
HttpHeaders.new("Foo_bar: baz").strict_mode.should be_true
end
end

describe "multi-valued keys" do describe "multi-valued keys" do
before do before do
@headers = <<EOS @headers = <<EOS
Expand Down

0 comments on commit c9916ef

Please sign in to comment.