net-http-server 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,87 @@
1
+ require 'spec_helper'
2
+ require 'rack/handler/helpers/test_request'
3
+
4
+ require 'rack/handler/http'
5
+ require 'rack/lint'
6
+ require 'rack/builder'
7
+ require 'rack/static'
8
+
9
+ describe Rack::Handler::HTTP do
10
+ include TestRequest::Helpers
11
+
12
+ let(:host) { '0.0.0.0' }
13
+ let(:port) { 9204 }
14
+
15
+ before(:all) do
16
+ app = Rack::Builder.app do
17
+ use Rack::Lint
18
+ use Rack::Static, :urls => ["/spec/images"]
19
+ run TestRequest.new
20
+ end
21
+
22
+ @server = Rack::Handler::HTTP.new(app, :Host => host, :Port => port)
23
+
24
+ Thread.new { @server.run }
25
+ Thread.pass until @server.running?
26
+ end
27
+
28
+ after(:all) do
29
+ @server.stop
30
+ Thread.pass until @server.stopped?
31
+ end
32
+
33
+ it "should respond to a simple get request" do
34
+ GET "/"
35
+ status.should == 200
36
+ end
37
+
38
+ it "should have CGI headers on GET" do
39
+ GET("/")
40
+ response["REQUEST_METHOD"].should == "GET"
41
+ response["SCRIPT_NAME"].should == ''
42
+ response["PATH_INFO"].should == "/"
43
+ response["QUERY_STRING"].should == ""
44
+ response["test.postdata"].should == ""
45
+
46
+ GET("/test/foo?quux=1")
47
+ response["REQUEST_METHOD"].should == "GET"
48
+ response["SCRIPT_NAME"].should == ''
49
+ response["REQUEST_URI"].should == "/test/foo"
50
+ response["PATH_INFO"].should == "/test/foo"
51
+ response["QUERY_STRING"].should == "quux=1"
52
+ end
53
+
54
+ it "should have CGI headers on POST" do
55
+ POST("/", {"rack-form-data" => "23"}, {'X-test-header' => '42'})
56
+ status.should == 200
57
+ response["REQUEST_METHOD"].should == "POST"
58
+ response["REQUEST_URI"].should == "/"
59
+ response["QUERY_STRING"].should == ""
60
+ response["HTTP_X_TEST_HEADER"].should == "42"
61
+ response["test.postdata"].should == "rack-form-data=23"
62
+ end
63
+
64
+ it "should support HTTP auth" do
65
+ GET("/test", {:user => "ruth", :passwd => "secret"})
66
+ response["HTTP_AUTHORIZATION"].should == "Basic cnV0aDpzZWNyZXQ="
67
+ end
68
+
69
+ it "should set status" do
70
+ GET("/test?secret")
71
+ status.should == 403
72
+ response["rack.url_scheme"].should == "http"
73
+ end
74
+
75
+ it "should not set content-type to '' in requests" do
76
+ GET("/test", 'Content-Type' => '')
77
+ response['Content-Type'].should == nil
78
+ end
79
+
80
+ it "should serve images" do
81
+ file_size = File.size(File.join(File.dirname(__FILE__), 'images', 'image.jpg'))
82
+ GET("/spec/images/image.jpg")
83
+ status.should == 200
84
+ response.content_length.should == file_size
85
+ response.body.size.should == file_size
86
+ end
87
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+ require 'net/http/server/daemon'
3
+
4
+ describe Net::HTTP::Server::Daemon do
5
+ subject { Net::HTTP::Server::Daemon }
6
+
7
+ describe "new" do
8
+ it "should have a default host" do
9
+ daemon = subject.new { |request,socket| }
10
+
11
+ daemon.host.should_not be_nil
12
+ end
13
+
14
+ it "should have a default port" do
15
+ daemon = subject.new { |request,socket| }
16
+
17
+ daemon.port.should_not be_nil
18
+ end
19
+
20
+ it "should require a HTTP Request handler" do
21
+ lambda {
22
+ subject.new
23
+ }.should raise_error
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,90 @@
1
+ require 'spec_helper'
2
+ require 'net/http/server/parser'
3
+
4
+ describe Net::HTTP::Server::Parser do
5
+ it "should not parse garbage" do
6
+ garbage = (1..255).map { |b| b.chr }.join * 100
7
+
8
+ lambda {
9
+ subject.parse(garbage)
10
+ }.should raise_error(Parslet::ParseFailed)
11
+ end
12
+
13
+ describe "request line" do
14
+ it "should parse non-standard request methods" do
15
+ request = subject.parse("FOO / HTTP/1.1\r\n\r\n")
16
+
17
+ request[:method].should == 'FOO'
18
+ end
19
+
20
+ it "should allow '*' as the path" do
21
+ request = subject.parse("OPTIONS * HTTP/1.1\r\n\r\n")
22
+
23
+ request[:uri].should == '*'
24
+ end
25
+
26
+ it "should not confuse the '/*' path with '*'" do
27
+ request = subject.parse("OPTIONS /* HTTP/1.1\r\n\r\n")
28
+
29
+ request[:uri][:path].should == '*'
30
+ end
31
+
32
+ it "should parse absolute paths" do
33
+ request = subject.parse("GET /absolute/path HTTP/1.1\r\n\r\n")
34
+
35
+ request[:uri][:path].should == 'absolute/path'
36
+ end
37
+
38
+ it "should parse the params in the path" do
39
+ request = subject.parse("GET /path;q=1;p=2 HTTP/1.1\r\n\r\n")
40
+
41
+ request[:uri][:path].should == 'path'
42
+ request[:uri][:params].should == 'q=1;p=2'
43
+ end
44
+
45
+ it "should parse the query-string in the path" do
46
+ request = subject.parse("GET /path?q=1&p=2 HTTP/1.1\r\n\r\n")
47
+
48
+ request[:uri][:path].should == 'path'
49
+ request[:uri][:query].should == 'q=1&p=2'
50
+ end
51
+
52
+ it "should parse absolute URIs paths" do
53
+ request = subject.parse("GET http://www.example.com:8080/path HTTP/1.1\r\n\r\n")
54
+
55
+ request[:uri][:scheme].should == 'http'
56
+ request[:uri][:host].should == 'www.example.com'
57
+ request[:uri][:port].should == '8080'
58
+ request[:uri][:path].should == 'path'
59
+ end
60
+
61
+ it "should parse non-http URIs" do
62
+ request = subject.parse("GET xmpp://alice:secret@example.com/path HTTP/1.1\r\n\r\n")
63
+
64
+ request[:uri][:scheme].should == 'xmpp'
65
+ request[:uri][:user_info].should == 'alice:secret'
66
+ request[:uri][:host].should == 'example.com'
67
+ request[:uri][:path].should == 'path'
68
+ end
69
+
70
+ it "should parse the HTTP version" do
71
+ request = subject.parse("GET /path HTTP/1.1\r\n\r\n")
72
+
73
+ request[:version].should == '1.1'
74
+ end
75
+
76
+ it "should allow future HTTP versions" do
77
+ request = subject.parse("GET /path HTTP/2.0\r\n\r\n")
78
+
79
+ request[:version].should == '2.0'
80
+ end
81
+
82
+ it "should parse simple GET requests" do
83
+ request = subject.parse("GET / HTTP/1.1\r\n\r\n")
84
+
85
+ request[:method].should == 'GET'
86
+ request[:uri][:path].should be_nil
87
+ request[:version].should == '1.1'
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,110 @@
1
+ require 'spec_helper'
2
+ require 'net/http/server/requests'
3
+
4
+ require 'stringio'
5
+
6
+ describe Net::HTTP::Server::Requests do
7
+ include Net::HTTP::Server::Requests
8
+
9
+ describe "read_request" do
10
+ it "should ignore requests that do not contain an HTTP version" do
11
+ stream = StringIO.new("GET /\r\n")
12
+
13
+ read_request(stream).should be_nil
14
+ end
15
+
16
+ it "should ignore requests with malformed headers" do
17
+ stream = StringIO.new("GET / HTTP/1.1\r\nFoo: Bar\r\nBAZ\r\n\r\n")
18
+
19
+ read_request(stream).should be_nil
20
+ end
21
+
22
+ it "should read requests with an HTTP Version and Headers" do
23
+ request = "GET / HTTP/1.1\r\nFoo: Bar\r\n\r\n"
24
+ stream = StringIO.new(request)
25
+
26
+ read_request(stream).should == request
27
+ end
28
+
29
+ it "should not read the body of the request" do
30
+ request = "GET / HTTP/1.1\r\nFoo: Bar\r\n\r\n"
31
+ body = "<html>\r\n\t<body>hello</body>\r\n</html>\r\n"
32
+ stream = StringIO.new(request + body)
33
+
34
+ read_request(stream)
35
+
36
+ stream.read.should == body
37
+ end
38
+ end
39
+
40
+ describe "normalize_uri" do
41
+ it "should infer the :port, if :scheme is also set" do
42
+ request = {:uri => {:scheme => 'https'}}
43
+ normalize_uri(request)
44
+
45
+ request[:uri][:port].should == 443
46
+ end
47
+
48
+ it "should convert :port to an Integer" do
49
+ request = {:uri => {:scheme => 'http', :port => '80'}}
50
+ normalize_uri(request)
51
+
52
+ request[:uri][:port].should == 80
53
+ end
54
+
55
+ it "should default :path to '/'" do
56
+ request = {:uri => {:path => nil}}
57
+ normalize_uri(request)
58
+
59
+ request[:uri][:path].should == '/'
60
+ end
61
+
62
+ it "should ensure that the path begins with a '/'" do
63
+ request = {:uri => {:path => 'foo'}}
64
+ normalize_uri(request)
65
+
66
+ request[:uri][:path].should == '/foo'
67
+ end
68
+
69
+ it "should replace a '*' URI with an empty Hash" do
70
+ request = {:uri => '*'}
71
+ normalize_uri(request)
72
+
73
+ request[:uri].should == {}
74
+ end
75
+ end
76
+
77
+ describe "normalize_headers" do
78
+ it "should convert empty headers to an empty Hash" do
79
+ request = {:headers => []}
80
+ normalize_headers(request)
81
+
82
+ request[:headers].should == {}
83
+ end
84
+
85
+ it "should convert header names and values into a Hash" do
86
+ request = {:headers => [
87
+ {:name => 'Content-Type', :value => 'text/html'},
88
+ {:name => 'Content-Length', :value => '5'}
89
+ ]}
90
+ normalize_headers(request)
91
+
92
+ request[:headers].should == {
93
+ 'Content-Type' => 'text/html',
94
+ 'Content-Length' => '5'
95
+ }
96
+ end
97
+
98
+ it "should group duplicate header names into the same Hash key" do
99
+ request = {:headers => [
100
+ {:name => 'Content-Type', :value => 'text/html'},
101
+ {:name => 'Content-Type', :value => 'UTF8'},
102
+ ]}
103
+ normalize_headers(request)
104
+
105
+ request[:headers].should == {
106
+ 'Content-Type' => ['text/html', 'UTF8']
107
+ }
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,105 @@
1
+ require 'spec_helper'
2
+ require 'net/http/server/responses'
3
+
4
+ require 'stringio'
5
+
6
+ describe Net::HTTP::Server::Responses do
7
+ include Net::HTTP::Server::Responses
8
+
9
+ before(:each) { @stream = StringIO.new }
10
+
11
+ describe "write_status" do
12
+ let(:status) { 200 }
13
+ let(:reason) { Net::HTTP::Server::Responses::HTTP_STATUSES[status] }
14
+
15
+ before(:each) { write_status(@stream,status) }
16
+
17
+ it "should write the HTTP Version" do
18
+ parts = @stream.string.split(' ')
19
+
20
+ parts[0].should =~ /HTTP\/1.1/
21
+ end
22
+
23
+ it "should write the Status Code" do
24
+ parts = @stream.string.split(' ')
25
+
26
+ parts[1].should == status.to_s
27
+ end
28
+
29
+ it "should write the Reason String" do
30
+ parts = @stream.string.split(' ')
31
+
32
+ parts[2].should == reason
33
+ end
34
+
35
+ it "should end the line with a '\\r\\n'" do
36
+ @stream.string[-2..-1].should == "\r\n"
37
+ end
38
+ end
39
+
40
+ describe "write_headers" do
41
+ it "should separate header names and values with a ': '" do
42
+ write_headers(@stream, 'Foo' => 'Bar')
43
+
44
+ @stream.string.should include(': ')
45
+ end
46
+
47
+ it "should terminate each header with a '\\r\\n'" do
48
+ write_headers(@stream, 'Foo' => 'Bar', 'Baz' => 'Qix')
49
+
50
+ @stream.string.split("\r\n").should =~ [
51
+ 'Foo: Bar',
52
+ 'Baz: Qix'
53
+ ]
54
+ end
55
+
56
+ it "should end the headers with a '\\r\\n'" do
57
+ write_headers(@stream, {})
58
+
59
+ @stream.string.should == "\r\n"
60
+ end
61
+
62
+ it "should write String headers" do
63
+ write_headers(@stream, 'Content-Type' => 'text/html')
64
+
65
+ @stream.string.split("\r\n").should == [
66
+ 'Content-Type: text/html'
67
+ ]
68
+ end
69
+
70
+ it "should write multiple headers for multi-line String values" do
71
+ write_headers(@stream, 'Content-Type' => "text/html\ncharset=UTF8")
72
+
73
+ @stream.string.split("\r\n").should == [
74
+ 'Content-Type: text/html',
75
+ 'Content-Type: charset=UTF8'
76
+ ]
77
+ end
78
+
79
+ it "should properly format Time values" do
80
+ time = Time.parse('2011-01-25 14:15:29 -0800')
81
+ write_headers(@stream, 'Date' => time)
82
+
83
+ @stream.string.split("\r\n").should == [
84
+ 'Date: Tue, 25 Jan 2011 22:15:29 GMT'
85
+ ]
86
+ end
87
+
88
+ it "should write Array values as multiple headers" do
89
+ write_headers(@stream, 'Content-Type' => ['text/html', 'charset=UTF8'])
90
+
91
+ @stream.string.split("\r\n").should == [
92
+ 'Content-Type: text/html',
93
+ 'Content-Type: charset=UTF8'
94
+ ]
95
+ end
96
+ end
97
+
98
+ describe "write_body" do
99
+ it "should write each check of the body" do
100
+ write_body(@stream,['one', 'two', 'three'])
101
+
102
+ @stream.string.should == 'onetwothree'
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+ require 'net/http/server'
3
+
4
+ describe Net::HTTP::Server do
5
+ end
@@ -0,0 +1,2 @@
1
+ gem 'rspec', '~> 2.4.0'
2
+ require 'rspec'
metadata ADDED
@@ -0,0 +1,155 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: net-http-server
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Postmodern
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-01-26 00:00:00 -08:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: parslet
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ none: false
25
+ requirements:
26
+ - - ~>
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 1
30
+ - 0
31
+ version: "1.0"
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: ore-tasks
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ~>
41
+ - !ruby/object:Gem::Version
42
+ segments:
43
+ - 0
44
+ - 3
45
+ - 0
46
+ version: 0.3.0
47
+ type: :development
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: rspec
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ~>
56
+ - !ruby/object:Gem::Version
57
+ segments:
58
+ - 2
59
+ - 4
60
+ - 0
61
+ version: 2.4.0
62
+ type: :development
63
+ version_requirements: *id003
64
+ - !ruby/object:Gem::Dependency
65
+ name: yard
66
+ prerelease: false
67
+ requirement: &id004 !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ~>
71
+ - !ruby/object:Gem::Version
72
+ segments:
73
+ - 0
74
+ - 6
75
+ - 0
76
+ version: 0.6.0
77
+ type: :development
78
+ version_requirements: *id004
79
+ description: A Rack compatible pure Ruby HTTP Server.
80
+ email: postmodern.mod3@gmail.com
81
+ executables: []
82
+
83
+ extensions: []
84
+
85
+ extra_rdoc_files:
86
+ - README.md
87
+ - ChangeLog.md
88
+ - LICENSE.txt
89
+ files:
90
+ - .document
91
+ - .gemtest
92
+ - .rspec
93
+ - .yardopts
94
+ - ChangeLog.md
95
+ - LICENSE.txt
96
+ - README.md
97
+ - Rakefile
98
+ - gemspec.yml
99
+ - lib/net/http/server.rb
100
+ - lib/net/http/server/daemon.rb
101
+ - lib/net/http/server/parser.rb
102
+ - lib/net/http/server/requests.rb
103
+ - lib/net/http/server/responses.rb
104
+ - lib/net/http/server/server.rb
105
+ - lib/net/http/server/version.rb
106
+ - lib/rack/handler/http.rb
107
+ - net-http-server.gemspec
108
+ - spec/rack/handler/helpers/test_request.rb
109
+ - spec/rack/handler/http_spec.rb
110
+ - spec/rack/handler/images/image.jpg
111
+ - spec/server/daemon_spec.rb
112
+ - spec/server/parser_spec.rb
113
+ - spec/server/requests_spec.rb
114
+ - spec/server/responses_spec.rb
115
+ - spec/server/server_spec.rb
116
+ - spec/spec_helper.rb
117
+ has_rdoc: yard
118
+ homepage: http://github.com/postmodern/net-http-server
119
+ licenses:
120
+ - MIT
121
+ post_install_message:
122
+ rdoc_options: []
123
+
124
+ require_paths:
125
+ - lib
126
+ required_ruby_version: !ruby/object:Gem::Requirement
127
+ none: false
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ segments:
132
+ - 0
133
+ version: "0"
134
+ required_rubygems_version: !ruby/object:Gem::Requirement
135
+ none: false
136
+ requirements:
137
+ - - ">="
138
+ - !ruby/object:Gem::Version
139
+ segments:
140
+ - 0
141
+ version: "0"
142
+ requirements: []
143
+
144
+ rubyforge_project: net-http-server
145
+ rubygems_version: 1.3.7
146
+ signing_key:
147
+ specification_version: 3
148
+ summary: A pure Ruby HTTP Server
149
+ test_files:
150
+ - spec/server/daemon_spec.rb
151
+ - spec/server/requests_spec.rb
152
+ - spec/server/parser_spec.rb
153
+ - spec/server/responses_spec.rb
154
+ - spec/server/server_spec.rb
155
+ - spec/rack/handler/http_spec.rb