rbkb-http 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.gitignore +5 -0
- data/History.txt +4 -0
- data/LICENSE +22 -0
- data/README.rdoc +18 -0
- data/Rakefile +59 -0
- data/VERSION +1 -0
- data/lib/rbkb/http/base.rb +179 -0
- data/lib/rbkb/http/body.rb +220 -0
- data/lib/rbkb/http/common.rb +74 -0
- data/lib/rbkb/http/headers.rb +406 -0
- data/lib/rbkb/http/parameters.rb +220 -0
- data/lib/rbkb/http/request.rb +76 -0
- data/lib/rbkb/http/response.rb +86 -0
- data/lib/rbkb/http.rb +22 -0
- data/rbkb-http.gemspec +74 -0
- data/spec/rbkb-http_spec.rb +7 -0
- data/spec/spec_helper.rb +9 -0
- data/test/test_helper.rb +9 -0
- data/test/test_http.rb +27 -0
- data/test/test_http_helper.rb +59 -0
- data/test/test_http_request.rb +136 -0
- data/test/test_http_response.rb +222 -0
- metadata +103 -0
@@ -0,0 +1,86 @@
|
|
1
|
+
|
2
|
+
module Rbkb::Http
|
3
|
+
# A Response encapsulates all the entities in a HTTP response,
|
4
|
+
# including the status header, general headers, and body.
|
5
|
+
class Response < Base
|
6
|
+
attr_accessor :status
|
7
|
+
|
8
|
+
alias first_entity status
|
9
|
+
alias first_entity= status=
|
10
|
+
|
11
|
+
# Returns a raw HTTP response for this instance. Must have a status
|
12
|
+
# element defined at a bare minimum.
|
13
|
+
def to_raw(raw_body=nil)
|
14
|
+
raise "this response has no status" unless first_entity()
|
15
|
+
self.headers ||= default_headers_obj()
|
16
|
+
self.body = raw_body if raw_body
|
17
|
+
|
18
|
+
if do_chunked_encoding?(@headers)
|
19
|
+
unless @body.is_a? ChunkedBody
|
20
|
+
@body = ChunkedBody.new(@body, @body.opts)
|
21
|
+
end
|
22
|
+
@headers.delete_header("Content-Length")
|
23
|
+
elsif not opts[:ignore_content_length]
|
24
|
+
unless @body.is_a? BoundBody
|
25
|
+
@body = BoundBody.new(@body, @body.opts)
|
26
|
+
end
|
27
|
+
@headers.delete_header("Transfer-Encoding")
|
28
|
+
else
|
29
|
+
@body = Body.new(@body, @body.opts)
|
30
|
+
end
|
31
|
+
@body.base = self
|
32
|
+
|
33
|
+
yield(self) if block_given?
|
34
|
+
|
35
|
+
bstr = @body.to_raw
|
36
|
+
hdrs = @headers.to_raw_array.unshift(self.first_entity.to_raw)
|
37
|
+
return "#{hdrs.join("\r\n")}\r\n\r\n#{bstr}"
|
38
|
+
end
|
39
|
+
|
40
|
+
# Parses a raw HTTP response and captures data into the current instance.
|
41
|
+
def capture(str)
|
42
|
+
raise "arg 0 must be a string" unless String === str
|
43
|
+
hstr, bstr = str.split(/\s*\r?\n\r?\n/, 2)
|
44
|
+
|
45
|
+
capture_headers(hstr)
|
46
|
+
|
47
|
+
yield(self, bstr) if block_given?
|
48
|
+
|
49
|
+
unless @body and @body.capture_complete?
|
50
|
+
@body =
|
51
|
+
if do_chunked_encoding?
|
52
|
+
ChunkedBody.new {|b| b.base = self }
|
53
|
+
elsif content_length()
|
54
|
+
BoundBody.new {|b| b.base = self }
|
55
|
+
else
|
56
|
+
Body.new {|b| b.base = self }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
capture_body(bstr)
|
61
|
+
|
62
|
+
return self
|
63
|
+
end
|
64
|
+
|
65
|
+
# Indicates whether to use chunked encoding based on presence of
|
66
|
+
# the "Transfer-Encoding: chunked" header or the :ignore_chunked_encoding
|
67
|
+
# opts parameter.
|
68
|
+
def do_chunked_encoding?(hdrs=@headers)
|
69
|
+
( (not @opts[:ignore_chunked_encoding]) and
|
70
|
+
(hdrs.get_header_value("Transfer-Encoding").to_s =~ /(?:^|\W)chunked(?:\W|$)/) )
|
71
|
+
end
|
72
|
+
|
73
|
+
# Returns a new Headers object extended as ResponseHeaders. This is the
|
74
|
+
# default object which will be used when composing fresh Response header
|
75
|
+
# entities.
|
76
|
+
def default_headers_obj(*args)
|
77
|
+
Headers.new(*args).extend(ResponseHeaders)
|
78
|
+
end
|
79
|
+
|
80
|
+
# Returns a new BoundBody object. This is the default object which will
|
81
|
+
# be used when composing fresh Response body entities.
|
82
|
+
def default_body_obj(*args)
|
83
|
+
BoundBody.new(*args)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
data/lib/rbkb/http.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
begin ; require 'rubygems' ; rescue LoadError ; end
|
2
|
+
|
3
|
+
require 'rbkb'
|
4
|
+
|
5
|
+
# ???Why???? would anyone create their own HTTP implementation in ruby with
|
6
|
+
# so many options out there? Short answer: Net::HTTP and others just don't cut
|
7
|
+
# it in lots of edge cases. I needed something I could control completely.
|
8
|
+
|
9
|
+
module Rbkb::Http
|
10
|
+
# nop
|
11
|
+
end
|
12
|
+
|
13
|
+
require 'time' # gives us Time.httpdate parser and output methods
|
14
|
+
|
15
|
+
require "rbkb/http/common.rb"
|
16
|
+
require "rbkb/http/base.rb"
|
17
|
+
require "rbkb/http/request.rb"
|
18
|
+
require "rbkb/http/response.rb"
|
19
|
+
require "rbkb/http/headers.rb"
|
20
|
+
require "rbkb/http/body.rb"
|
21
|
+
require "rbkb/http/parameters.rb"
|
22
|
+
|
data/rbkb-http.gemspec
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{rbkb-http}
|
8
|
+
s.version = "0.2.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Eric Monti"]
|
12
|
+
s.date = %q{2009-11-12}
|
13
|
+
s.description = %q{HTTP libraries and tools based on and complementary to Ruby BlackBag}
|
14
|
+
s.email = %q{emonti@matasano.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"History.txt",
|
23
|
+
"LICENSE",
|
24
|
+
"README.rdoc",
|
25
|
+
"Rakefile",
|
26
|
+
"VERSION",
|
27
|
+
"lib/rbkb/http.rb",
|
28
|
+
"lib/rbkb/http/base.rb",
|
29
|
+
"lib/rbkb/http/body.rb",
|
30
|
+
"lib/rbkb/http/common.rb",
|
31
|
+
"lib/rbkb/http/headers.rb",
|
32
|
+
"lib/rbkb/http/parameters.rb",
|
33
|
+
"lib/rbkb/http/request.rb",
|
34
|
+
"lib/rbkb/http/response.rb",
|
35
|
+
"rbkb-http.gemspec",
|
36
|
+
"spec/rbkb-http_spec.rb",
|
37
|
+
"spec/spec_helper.rb",
|
38
|
+
"test/test_helper.rb",
|
39
|
+
"test/test_http.rb",
|
40
|
+
"test/test_http_helper.rb",
|
41
|
+
"test/test_http_request.rb",
|
42
|
+
"test/test_http_response.rb"
|
43
|
+
]
|
44
|
+
s.homepage = %q{http://github.com/emonti/rbkb-http}
|
45
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
46
|
+
s.require_paths = ["lib"]
|
47
|
+
s.rubygems_version = %q{1.3.5}
|
48
|
+
s.summary = %q{HTTP protocol add-ons for Ruby BlackBag}
|
49
|
+
s.test_files = [
|
50
|
+
"spec/rbkb-http_spec.rb",
|
51
|
+
"spec/spec_helper.rb",
|
52
|
+
"test/test_helper.rb",
|
53
|
+
"test/test_http.rb",
|
54
|
+
"test/test_http_helper.rb",
|
55
|
+
"test/test_http_request.rb",
|
56
|
+
"test/test_http_response.rb"
|
57
|
+
]
|
58
|
+
|
59
|
+
if s.respond_to? :specification_version then
|
60
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
61
|
+
s.specification_version = 3
|
62
|
+
|
63
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
64
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
65
|
+
s.add_runtime_dependency(%q<rbkb>, [">= 0"])
|
66
|
+
else
|
67
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
68
|
+
s.add_dependency(%q<rbkb>, [">= 0"])
|
69
|
+
end
|
70
|
+
else
|
71
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
72
|
+
s.add_dependency(%q<rbkb>, [">= 0"])
|
73
|
+
end
|
74
|
+
end
|
data/spec/spec_helper.rb
ADDED
data/test/test_helper.rb
ADDED
data/test/test_http.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_http_helper.rb'
|
2
|
+
|
3
|
+
class TestHttp < Test::Unit::TestCase
|
4
|
+
include Rbkb::Http
|
5
|
+
|
6
|
+
def test_names
|
7
|
+
assert_equal CommonInterface, Rbkb::Http::CommonInterface
|
8
|
+
assert_equal Base, Rbkb::Http::Base
|
9
|
+
|
10
|
+
assert_equal Response, Rbkb::Http::Response
|
11
|
+
assert_equal Request, Rbkb::Http::Request
|
12
|
+
assert_equal Parameters, Rbkb::Http::Parameters
|
13
|
+
assert_equal FormUrlencodedParams, Rbkb::Http::FormUrlencodedParams
|
14
|
+
|
15
|
+
assert_equal Headers, Rbkb::Http::Headers
|
16
|
+
assert_equal RequestHeaders, Rbkb::Http::RequestHeaders
|
17
|
+
assert_equal RequestAction, Rbkb::Http::RequestAction
|
18
|
+
assert_equal ResponseHeaders, Rbkb::Http::ResponseHeaders
|
19
|
+
assert_equal ResponseStatus, Rbkb::Http::ResponseStatus
|
20
|
+
|
21
|
+
assert_equal Body, Rbkb::Http::Body
|
22
|
+
assert_equal BoundBody, Rbkb::Http::BoundBody
|
23
|
+
assert_equal ChunkedBody, Rbkb::Http::ChunkedBody
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'test_helper.rb')
|
2
|
+
|
3
|
+
module HttpTestHelper
|
4
|
+
# contains various test cases to test common interface features
|
5
|
+
module CommonInterfaceTests
|
6
|
+
|
7
|
+
def setup()
|
8
|
+
raise "Helper stub called. Override setup() in TestCase"
|
9
|
+
end
|
10
|
+
|
11
|
+
def do_type_tests(x)
|
12
|
+
raise "Helper stub called. Override do_type_tests() in TestCase"
|
13
|
+
end
|
14
|
+
|
15
|
+
def do_type_tests(x)
|
16
|
+
raise "Helper stub called. Override do_capture_value_tests() in TestCase"
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_init_parse
|
20
|
+
req = @obj_klass.new(@rawdat, @obj_opts)
|
21
|
+
do_capture_value_tests(req)
|
22
|
+
do_type_tests(req)
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_parse
|
26
|
+
req = @obj_klass.parse(@rawdat, @obj_opts)
|
27
|
+
do_capture_value_tests(req)
|
28
|
+
do_type_tests(req)
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_capture
|
32
|
+
req = @obj.capture(@rawdat)
|
33
|
+
do_capture_value_tests(req)
|
34
|
+
do_type_tests(req)
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_back_to_raw
|
38
|
+
req = @obj.capture(@rawdat)
|
39
|
+
assert_equal @rawdat_crlf, req.to_raw
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_capture_and_reuse_nondestructive
|
43
|
+
@obj.capture(@rawdat_crlf)
|
44
|
+
@obj.reset_capture
|
45
|
+
@obj.capture(@rawdat_crlf)
|
46
|
+
do_capture_value_tests(@obj)
|
47
|
+
do_type_tests(@obj)
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_capture_and_reuse_destructive
|
51
|
+
@obj.capture(@rawdat_crlf)
|
52
|
+
@obj.reset_capture!
|
53
|
+
@obj.capture(@rawdat_crlf)
|
54
|
+
do_capture_value_tests(@obj)
|
55
|
+
do_type_tests(@obj)
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,136 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_http_helper.rb'
|
2
|
+
|
3
|
+
class TestHttpRequest < Test::Unit::TestCase
|
4
|
+
include HttpTestHelper::CommonInterfaceTests
|
5
|
+
|
6
|
+
include Rbkb::Http
|
7
|
+
|
8
|
+
def setup
|
9
|
+
@obj_klass = Request
|
10
|
+
@obj = @obj_klass.new
|
11
|
+
|
12
|
+
@rawdat =<<_EOF_
|
13
|
+
GET /csi?v=3&s=webhp&action=&tran=undefined HTTP/1.1
|
14
|
+
Host: www.google.com
|
15
|
+
User-Agent: Mozilla/5.0
|
16
|
+
Accept: image/png,image/*;q=0.8,*/*;q=0.5
|
17
|
+
Accept-Language: en-us,en;q=0.5
|
18
|
+
Accept-Encoding: gzip,deflate
|
19
|
+
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
|
20
|
+
Keep-Alive: 300
|
21
|
+
Proxy-Connection: keep-alive
|
22
|
+
Referer: http://www.google.com/
|
23
|
+
Cookie: PREFID=NNNN:LM=1237996892:S=YYYYY; NID=111
|
24
|
+
|
25
|
+
_EOF_
|
26
|
+
|
27
|
+
@hstr, @body = @rawdat.split(/^\n/, 2)
|
28
|
+
@rawdat_crlf = @hstr.gsub("\n", "\r\n") + "\r\n" + @body
|
29
|
+
|
30
|
+
@verb = "GET"
|
31
|
+
@uri = "/csi?v=3&s=webhp&action=&tran=undefined"
|
32
|
+
@path, @query = @uri.split('?',2)
|
33
|
+
@req_parameters = [
|
34
|
+
["v", "3"],
|
35
|
+
["s", "webhp"],
|
36
|
+
["action", ""],
|
37
|
+
["tran", "undefined"]
|
38
|
+
]
|
39
|
+
@version = "HTTP/1.1"
|
40
|
+
|
41
|
+
@headers = [
|
42
|
+
["Host", "www.google.com"],
|
43
|
+
["User-Agent", "Mozilla/5.0"],
|
44
|
+
["Accept", "image/png,image/*;q=0.8,*/*;q=0.5"],
|
45
|
+
["Accept-Language", "en-us,en;q=0.5"],
|
46
|
+
["Accept-Encoding", "gzip,deflate"],
|
47
|
+
["Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7"],
|
48
|
+
["Keep-Alive", "300"],
|
49
|
+
["Proxy-Connection", "keep-alive"],
|
50
|
+
["Referer", "http://www.google.com/"],
|
51
|
+
["Cookie", "PREFID=NNNN:LM=1237996892:S=YYYYY; NID=111"],
|
52
|
+
]
|
53
|
+
end
|
54
|
+
|
55
|
+
def do_type_tests(req)
|
56
|
+
assert_kind_of Request, req
|
57
|
+
assert_kind_of Headers, req.headers
|
58
|
+
assert_kind_of Body, req.body
|
59
|
+
assert_kind_of RequestAction, req.action
|
60
|
+
assert_kind_of RequestHeaders, req.headers
|
61
|
+
end
|
62
|
+
|
63
|
+
def do_capture_value_tests(req)
|
64
|
+
assert_equal @headers, req.headers
|
65
|
+
assert_equal @body, req.body.to_s
|
66
|
+
assert_equal @uri, req.action.uri.to_s
|
67
|
+
assert_equal @path, req.action.uri.path
|
68
|
+
assert_equal @query, req.action.uri.query
|
69
|
+
assert_equal @verb, req.action.verb
|
70
|
+
assert_equal @version, req.action.version
|
71
|
+
assert_equal @req_parameters, req.action_parameters
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_capture_crlf_headers
|
75
|
+
req = @obj.capture(@rawdat_crlf)
|
76
|
+
do_capture_value_tests(req)
|
77
|
+
do_type_tests(req)
|
78
|
+
assert_equal @rawdat_crlf, req.to_raw
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_captured_body_type
|
82
|
+
@obj.capture(@rawdat)
|
83
|
+
assert_kind_of Body, @obj.body
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
class TestHttpPostRequest < TestHttpRequest
|
90
|
+
|
91
|
+
def setup
|
92
|
+
@obj_klass = Request
|
93
|
+
@obj = @obj_klass.new
|
94
|
+
|
95
|
+
@rawdat =<<_EOF_
|
96
|
+
POST /path/script.cgi?qtype=foo HTTP/1.0
|
97
|
+
From: frog@jmarshall.com
|
98
|
+
HasColon: this_has_a_colon:yikes
|
99
|
+
User-Agent: HTTPTool/1.0
|
100
|
+
Content-Type: application/x-www-form-urlencoded
|
101
|
+
Content-Length: 32
|
102
|
+
|
103
|
+
home=Cosby&favorite+flavor=flies
|
104
|
+
_EOF_
|
105
|
+
@rawdat.chomp!
|
106
|
+
|
107
|
+
@hstr, @body = @rawdat.split(/^\n/, 2)
|
108
|
+
@rawdat_crlf = @hstr.gsub("\n", "\r\n") + "\r\n" + @body
|
109
|
+
|
110
|
+
@verb = "POST"
|
111
|
+
@uri = "/path/script.cgi?qtype=foo"
|
112
|
+
@path, @query = @uri.split('?',2)
|
113
|
+
@req_parameters = [
|
114
|
+
["qtype", "foo"],
|
115
|
+
]
|
116
|
+
@version = "HTTP/1.0"
|
117
|
+
|
118
|
+
@headers = [
|
119
|
+
["From", "frog@jmarshall.com"],
|
120
|
+
["HasColon", "this_has_a_colon:yikes"],
|
121
|
+
["User-Agent", "HTTPTool/1.0"],
|
122
|
+
["Content-Type", "application/x-www-form-urlencoded"],
|
123
|
+
["Content-Length", "32"],
|
124
|
+
]
|
125
|
+
|
126
|
+
@post_parameters = [["home", "Cosby"], ["favorite+flavor", "flies"]]
|
127
|
+
end
|
128
|
+
|
129
|
+
def test_captured_body_type
|
130
|
+
@obj.capture(@rawdat)
|
131
|
+
assert_kind_of BoundBody, @obj.body
|
132
|
+
end
|
133
|
+
|
134
|
+
|
135
|
+
end
|
136
|
+
|
@@ -0,0 +1,222 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_http_helper.rb'
|
2
|
+
|
3
|
+
class TestHttpResponse < Test::Unit::TestCase
|
4
|
+
include HttpTestHelper::CommonInterfaceTests
|
5
|
+
|
6
|
+
include Rbkb::Http
|
7
|
+
|
8
|
+
def setup
|
9
|
+
@obj_klass = Response
|
10
|
+
@obj_opts = nil
|
11
|
+
@obj = @obj_klass.new(nil, @obj_opts)
|
12
|
+
|
13
|
+
@rawdat =<<_EOF_
|
14
|
+
HTTP/1.0 404 Not Found
|
15
|
+
Date: Thu, 26 Mar 2009 01:18:52 GMT
|
16
|
+
Server: Apache
|
17
|
+
Content-Type: text/html; charset=iso-8859-1
|
18
|
+
Content-Length: 190
|
19
|
+
Connection: Keep-Alive
|
20
|
+
|
21
|
+
<html><head>
|
22
|
+
<title>Error report</title></head>
|
23
|
+
<body><h1>HTTP Status 404</h1><HR size="1" noshade><p><u>The requested resource is not available.</u></p><HR size="1" noshade>
|
24
|
+
</body></html>
|
25
|
+
_EOF_
|
26
|
+
|
27
|
+
@hstr, @body = @rawdat.split(/^\n/, 2)
|
28
|
+
@rawdat_crlf = @hstr.gsub("\n", "\r\n") + "\r\n" + @body
|
29
|
+
|
30
|
+
@code = 404
|
31
|
+
@text = "Not Found"
|
32
|
+
@version = "HTTP/1.0"
|
33
|
+
|
34
|
+
@headers = [
|
35
|
+
["Date", "Thu, 26 Mar 2009 01:18:52 GMT"],
|
36
|
+
["Server", "Apache"],
|
37
|
+
["Content-Type", "text/html; charset=iso-8859-1"],
|
38
|
+
["Content-Length", "190"],
|
39
|
+
["Connection", "Keep-Alive"]
|
40
|
+
]
|
41
|
+
|
42
|
+
@content_length = 190
|
43
|
+
end
|
44
|
+
|
45
|
+
def do_type_tests(rsp)
|
46
|
+
assert_kind_of Response, rsp
|
47
|
+
assert_kind_of Headers, rsp.headers
|
48
|
+
assert_kind_of Body, rsp.body
|
49
|
+
assert_kind_of ResponseStatus, rsp.status
|
50
|
+
assert_kind_of ResponseHeaders, rsp.headers
|
51
|
+
end
|
52
|
+
|
53
|
+
def do_capture_value_tests(rsp)
|
54
|
+
assert_equal @headers, rsp.headers
|
55
|
+
assert_equal @body, rsp.body
|
56
|
+
assert_equal @code, rsp.status.code
|
57
|
+
assert_equal @text, rsp.status.text
|
58
|
+
assert_equal @version, rsp.status.version
|
59
|
+
assert_equal @content_length, rsp.content_length
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_capture_crlf_headers
|
63
|
+
@obj.capture(@rawdat_crlf)
|
64
|
+
do_capture_value_tests(@obj)
|
65
|
+
do_type_tests(@obj)
|
66
|
+
assert_equal @rawdat_crlf, @obj.to_raw
|
67
|
+
end
|
68
|
+
|
69
|
+
def test_captured_body_type
|
70
|
+
@obj.capture(@rawdat)
|
71
|
+
assert_kind_of BoundBody, @obj.body
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
class TestHttpResponseChunked < TestHttpResponse
|
77
|
+
include Rbkb::Http
|
78
|
+
|
79
|
+
def setup
|
80
|
+
@obj_klass = Response
|
81
|
+
@obj_opts = {}
|
82
|
+
@obj = @obj_klass.new
|
83
|
+
|
84
|
+
@rawdat =<<_EOF_
|
85
|
+
HTTP/1.1 200 OK
|
86
|
+
Date: Thu, 26 Mar 2009 01:18:52 GMT
|
87
|
+
Server: Apache
|
88
|
+
Content-Type: text/html; charset=iso-8859-1
|
89
|
+
Transfer-Encoding: chunked
|
90
|
+
Connection: Keep-Alive
|
91
|
+
|
92
|
+
20
|
93
|
+
This is a test of a chunked-enco
|
94
|
+
|
95
|
+
10
|
96
|
+
ded HTTP request
|
97
|
+
|
98
|
+
0
|
99
|
+
_EOF_
|
100
|
+
|
101
|
+
@hstr, @rawbody = @rawdat.split(/^\n/, 2)
|
102
|
+
@rawdat_crlf = @rawdat.gsub("\n", "\r\n")
|
103
|
+
@hdrs_crlf = @hstr.gsub("\n", "\r\n")
|
104
|
+
|
105
|
+
@body = "This is a test of a chunked-encoded HTTP request"
|
106
|
+
|
107
|
+
@code = 200
|
108
|
+
@text = "OK"
|
109
|
+
@version = "HTTP/1.1"
|
110
|
+
|
111
|
+
@headers = [
|
112
|
+
["Date", "Thu, 26 Mar 2009 01:18:52 GMT"],
|
113
|
+
["Server", "Apache"],
|
114
|
+
["Content-Type", "text/html; charset=iso-8859-1"],
|
115
|
+
["Transfer-Encoding", "chunked"],
|
116
|
+
["Connection", "Keep-Alive"]
|
117
|
+
]
|
118
|
+
|
119
|
+
@content_length = nil
|
120
|
+
@tc_chunk_size = 0x20
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_captured_body_type
|
124
|
+
@obj.capture(@rawdat)
|
125
|
+
assert_kind_of ChunkedBody, @obj.body
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_back_to_raw
|
129
|
+
@obj.capture(@rawdat)
|
130
|
+
do_capture_value_tests(@obj)
|
131
|
+
do_type_tests(@obj)
|
132
|
+
@obj.body.opts[:output_chunk_size] = @tc_chunk_size
|
133
|
+
assert_equal @rawdat_crlf, @obj.to_raw
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_capture_crlf_headers
|
137
|
+
@obj.capture(@rawdat_crlf)
|
138
|
+
do_capture_value_tests(@obj)
|
139
|
+
do_type_tests(@obj)
|
140
|
+
@obj.body.opts[:output_chunk_size] = @tc_chunk_size
|
141
|
+
assert_equal @rawdat_crlf, @obj.to_raw
|
142
|
+
end
|
143
|
+
|
144
|
+
def test_default_chunk_size
|
145
|
+
if @body.size > ChunkedBody::DEFAULT_CHUNK_SIZE
|
146
|
+
assert "TESTCASE ERROR!!!", "make the setup() @body < DEFAULT_CHUNK_SIZE"
|
147
|
+
end
|
148
|
+
raw_tc = "#{@hdrs_crlf}\r\n#{@body.size.to_s(16)}\r\n#{@body}\r\n\r\n0\r\n"
|
149
|
+
@obj.capture(@rawdat_crlf)
|
150
|
+
do_capture_value_tests(@obj)
|
151
|
+
do_type_tests(@obj)
|
152
|
+
assert_equal raw_tc, @obj.to_raw
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
# This test-case simulates a HTTP response to a HEAD request. This type of
|
157
|
+
# response is special since it returns Content-Length: NNN or
|
158
|
+
# Transfer-Encoding: chunked headers without any actual body data.
|
159
|
+
# To handle this special situation, we use the 'ignore_content_length' and
|
160
|
+
# 'ignore_chunked_encoding' options.
|
161
|
+
class TestHttpResponseToHead < TestHttpResponse
|
162
|
+
def setup
|
163
|
+
@obj_klass = Response
|
164
|
+
|
165
|
+
# Technically, a server should only respond to HEAD with one of
|
166
|
+
# content length *or* chunked encoding. However, we ignore them both.
|
167
|
+
@obj_opts = {
|
168
|
+
:ignore_content_length => true,
|
169
|
+
:ignore_chunked_encoding => true
|
170
|
+
}
|
171
|
+
@obj = @obj_klass.new(nil, @obj_opts)
|
172
|
+
|
173
|
+
# Note, our test-case includes both content length and chunked encoding.
|
174
|
+
# A real server probably wouldn't do this, but we want to make sure
|
175
|
+
# we handle both.
|
176
|
+
@rawdat =<<_EOF_
|
177
|
+
HTTP/1.1 200 OK
|
178
|
+
Cache-Control: private, max-age=0
|
179
|
+
Date: Fri, 27 Mar 2009 04:27:27 GMT
|
180
|
+
Expires: -1
|
181
|
+
Content-Length: 9140
|
182
|
+
Content-Type: text/html; charset=ISO-8859-1
|
183
|
+
Server: Booble
|
184
|
+
Transfer-Encoding: chunked
|
185
|
+
|
186
|
+
_EOF_
|
187
|
+
|
188
|
+
@hstr, @body = @rawdat.split(/^\n/, 2)
|
189
|
+
@rawdat_crlf = @hstr.gsub("\n", "\r\n") + "\r\n" + @body
|
190
|
+
|
191
|
+
@code = 200
|
192
|
+
@text = "OK"
|
193
|
+
@version = "HTTP/1.1"
|
194
|
+
|
195
|
+
@headers = [
|
196
|
+
["Cache-Control", "private, max-age=0"],
|
197
|
+
["Date", "Fri, 27 Mar 2009 04:27:27 GMT"],
|
198
|
+
["Expires", "-1"],
|
199
|
+
["Content-Length", "9140"],
|
200
|
+
["Content-Type", "text/html; charset=ISO-8859-1"],
|
201
|
+
["Server", "Booble"],
|
202
|
+
["Transfer-Encoding", "chunked"]
|
203
|
+
]
|
204
|
+
|
205
|
+
# Content length should get ignored
|
206
|
+
@content_length = nil
|
207
|
+
end
|
208
|
+
|
209
|
+
def test_capture_crlf_headers
|
210
|
+
@obj.capture(@rawdat_crlf)
|
211
|
+
do_capture_value_tests(@obj)
|
212
|
+
do_type_tests(@obj)
|
213
|
+
assert_equal @rawdat_crlf, @obj.to_raw
|
214
|
+
end
|
215
|
+
|
216
|
+
def test_captured_body_type
|
217
|
+
@obj.capture(@rawdat)
|
218
|
+
assert_kind_of Body, @obj.body
|
219
|
+
end
|
220
|
+
|
221
|
+
end
|
222
|
+
|