eventmachine_httpserver 0.0.1 → 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -1,85 +1,92 @@
1
1
  # $Id: Rakefile 3546 2006-12-31 21:01:27Z francis $
2
- # Rakefile for the Bayshore configurable LDAP server.
3
- #
4
-
5
2
 
6
3
  require 'rake/gempackagetask'
7
4
  require 'rake/clean'
5
+ require 'rake/testtask'
8
6
 
9
-
10
-
11
- $can_minitar = false
12
- begin
13
- require 'archive/tar/minitar'
14
- require 'zlib'
15
- $can_minitar = true
16
- rescue LoadError
7
+ Rake::TestTask.new do |t|
8
+ t.libs += %w(ext)
9
+ t.test_files = FileList['test/test_*.rb']
10
+ t.verbose = true
17
11
  end
18
12
 
19
- $version = "0.0.1"
20
- $distdir = "eventmachine_httpserver-#{$version}"
21
- $tardist = "#$distdir.tar.gz"
22
- $name = "eventmachine_httpserver"
23
-
13
+ namespace :build do
14
+ sources = FileList['ext/*.{cpp,c,h}']
24
15
 
25
- spec = eval(File.read("eventmachine_httpserver.gemspec"))
26
- spec.version = $version
27
- desc "Build the RubyGem for EventMachine HTTP Server"
28
- task :gem => ["pkg/eventmachine_httpserver-#{$version}.gem"]
29
- Rake::GemPackageTask.new(spec) do |g|
30
- if $can_minitar
31
- g.need_tar = true
32
- g.need_zip = true
16
+ file 'ext/Makefile' => 'ext/extconf.rb' do
17
+ Dir.chdir 'ext' do
18
+ ruby 'extconf.rb'
19
+ end
33
20
  end
34
- g.package_dir = "pkg"
35
- end
36
-
37
-
38
- specbinary = eval(File.read("eventmachine_httpserver-binary.gemspec"))
39
- specbinary.version = $version
40
- desc "Build a binary RubyGem for EventMachine HTTP Server"
41
- task :gembinary => ["pkg/eventmachine_httpserver-binary-#{$version}.gem"]
42
- Rake::GemPackageTask.new(specbinary) do |g|
43
- if $can_minitar
44
- g.need_tar = true
45
- g.need_zip = true
21
+ CLEAN.include('ext/Makefile')
22
+ CLEAN.include('ext/*.log')
23
+
24
+ libfile = "ext/eventmachine_httpserver.#{Config::CONFIG['DLEXT']}"
25
+ file libfile => ['ext/Makefile', *sources] do
26
+ Dir.chdir 'ext' do
27
+ make = case RUBY_PLATFORM
28
+ when /mswin32/
29
+ 'nmake'
30
+ else
31
+ # typical gcc stack, might need a case for gmake on some
32
+ 'make'
33
+ end
34
+ sh make
35
+ end
46
36
  end
47
- g.package_dir = "pkg"
37
+ CLEAN.include(libfile)
38
+
39
+ task :makefile => 'ext/Makefile'
40
+
41
+ task :extension => libfile
48
42
  end
49
43
 
44
+ desc "Build the extension inside the ext dir"
45
+ task :build => :"build:extension"
46
+
47
+ desc "Build as necessary, then run tests"
48
+ task :test => :build
49
+
50
+ namespace :gem do
51
+ # TODO : use rake-compiler (github.com/luislavena/rake-compiler) for this!
52
+ # specbinary = eval(File.read("eventmachine_httpserver-binary.gemspec"))
53
+ # specbinary.version = $version
54
+ # desc "Build a binary RubyGem for EventMachine HTTP Server"
55
+ # task :gembinary => ["pkg/eventmachine_httpserver-binary-#{$version}.gem"]
56
+ # Rake::GemPackageTask.new(specbinary)
57
+
58
+ def gemspec
59
+ # The template executes some ruby code to make a manifest, so we just eval
60
+ # it. Later you could fill it with an ERB processor or whatever. It must
61
+ # return a valid gemspec object.
62
+ @gemspec ||= eval(File.read("eventmachine_httpserver.gemspec.tmpl"))
63
+ end
50
64
 
65
+ def version
66
+ gemspec.version
67
+ end
51
68
 
52
- def run_test_package test, filename_array
53
- require 'test/unit/testsuite'
54
- require 'test/unit/ui/console/testrunner'
55
-
56
- runner = Test::Unit::UI::Console::TestRunner
57
-
58
- $LOAD_PATH.unshift('test')
59
- $stderr.puts "Checking for test cases:" if test.verbose
60
- filename_array.each do |testcase|
61
- $stderr.puts "\t#{testcase}" if test.verbose
62
- load testcase
69
+ file "eventmachine_httpserver.gemspec" => 'eventmachine_httpserver.gemspec.tmpl' do |t|
70
+ open(t.name, 'w') { |f| f.write gemspec.to_ruby }
63
71
  end
64
72
 
65
- suite = Test::Unit::TestSuite.new($name)
73
+ desc "Generate the gemspec from template"
74
+ task :spec => "eventmachine_httpserver.gemspec"
66
75
 
67
- ObjectSpace.each_object(Class) do |testcase|
68
- suite << testcase.suite if testcase < Test::Unit::TestCase
76
+ file "eventmachine_httpserver-#{version}.gem" => :"gem:spec" do
77
+ sh "gem build eventmachine_httpserver.gemspec"
69
78
  end
70
79
 
71
- runner.run(suite)
72
- end
80
+ desc "Build the RubyGem for EventMachine HTTP Server"
81
+ task :build => "eventmachine_httpserver-#{version}.gem"
73
82
 
74
- desc "Run the tests for #$name."
75
- task :test do |t|
76
- run_test_package t, Dir['test/*.rb']
77
- end
83
+ desc "run gem install on the built gem"
84
+ task :install => :build do
85
+ sh 'gem inst eventmachine_httpserver*.gem'
86
+ end
78
87
 
79
- desc "Run the application tests"
80
- task :test_application do |t|
81
- run_test_package t, Dir['test/app.rb']
88
+ CLOBBER.include("eventmachine_httpserver.gemspec")
89
+ CLEAN.include("eventmachine_httpserver-#{version}.gem")
82
90
  end
83
91
 
84
- task :default => [:test]
85
-
92
+ task :default => :test
File without changes
File without changes
File without changes
@@ -0,0 +1,33 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{eventmachine_httpserver}
5
+ s.version = "0.1.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Francis Cianfrocca"]
9
+ s.cert_chain = nil
10
+ s.date = %q{2007-03-16}
11
+ s.description = %q{}
12
+ s.email = %q{garbagecat10@gmail.com}
13
+ s.extensions = ["ext/extconf.rb"]
14
+ s.extra_rdoc_files = ["docs/COPYING", "docs/README", "docs/RELEASE_NOTES"]
15
+ s.files = ["Rakefile", "docs/COPYING", "docs/README", "docs/RELEASE_NOTES", "eventmachine_httpserver.gemspec", "eventmachine_httpserver.gemspec.tmpl", "ext/extconf.rb", "ext/http.cpp", "ext/http.h", "ext/rubyhttp.cpp", "lib/evma_httpserver.rb", "lib/evma_httpserver/response.rb", "test/test_app.rb", "test/test_delegated.rb", "test/test_response.rb"]
16
+ s.has_rdoc = true
17
+ s.homepage = %q{http://rubyeventmachine.com}
18
+ s.rdoc_options = ["--title", "EventMachine_HttpServer", "--main", "docs/README", "--line-numbers"]
19
+ s.require_paths = ["lib"]
20
+ s.required_ruby_version = Gem::Requirement.new("> 0.0.0")
21
+ s.rubygems_version = %q{1.3.1}
22
+ s.summary = %q{EventMachine HTTP Server}
23
+
24
+ if s.respond_to? :specification_version then
25
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
26
+ s.specification_version = 1
27
+
28
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
29
+ else
30
+ end
31
+ else
32
+ end
33
+ end
@@ -0,0 +1,23 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = %q{eventmachine_httpserver}
3
+ s.version = "0.1.1"
4
+
5
+ s.specification_version = 1 if s.respond_to? :specification_version=
6
+
7
+ s.required_rubygems_version = nil if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Francis Cianfrocca"]
9
+ s.cert_chain = nil
10
+ s.date = %q{2007-03-16}
11
+ s.description = %q{}
12
+ s.email = %q{garbagecat10@gmail.com}
13
+ s.extensions = ["ext/extconf.rb"]
14
+ s.extra_rdoc_files = `git ls-files docs`.split
15
+ s.files = `git ls-files | grep -v .gitignore`.split
16
+ s.has_rdoc = true
17
+ s.homepage = %q{http://rubyeventmachine.com}
18
+ s.rdoc_options = ["--title", "EventMachine_HttpServer", "--main", "docs/README", "--line-numbers"]
19
+ s.require_paths = ["lib"]
20
+ s.required_ruby_version = Gem::Requirement.new("> 0.0.0")
21
+ s.rubygems_version = %q{1.3.1}
22
+ s.summary = %q{EventMachine HTTP Server}
23
+ end
@@ -1,5 +1,3 @@
1
- # $Id: extconf.rb 3896 2007-03-06 20:21:01Z francis $
2
- #
3
1
  #----------------------------------------------------------------------------
4
2
  #
5
3
  # Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
@@ -116,6 +114,13 @@ else
116
114
  end
117
115
  # on Unix we need a g++ link, not gcc.
118
116
  CONFIG['LDSHARED'] = "$(CXX) -shared"
117
+
118
+ # Modify the mkmf constant LINK_SO so the generated shared object is stripped.
119
+ # You might think modifying CONFIG['LINK_SO'] would be a better way to do this,
120
+ # but it doesn't work because mkmf doesn't look at CONFIG['LINK_SO'] again after
121
+ # it initializes.
122
+ # linkso = Object.send :remove_const, "LINK_SO"
123
+ # LINK_SO = linkso + "; strip $@"
119
124
  end
120
125
 
121
126
  if $CPPFLAGS
@@ -1,7 +1,5 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: http.cpp 3967 2007-03-16 11:53:55Z francis $
4
-
5
3
  File: http.cpp
6
4
  Date: 21Apr06
7
5
 
@@ -27,6 +25,8 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
27
25
 
28
26
  #include <iostream>
29
27
  #include <string>
28
+ #include <cstdlib>
29
+ #include <cstring>
30
30
  #include <sstream>
31
31
  #include <stdexcept>
32
32
  #include <stdio.h>
@@ -564,5 +564,3 @@ void HttpConnection_t::_SendError (int code)
564
564
 
565
565
  SendData (ss.str().c_str(), ss.str().length());
566
566
  }
567
-
568
-
data/ext/http.h CHANGED
@@ -1,7 +1,5 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: http.h 3966 2007-03-16 11:52:05Z francis $
4
-
5
3
  File: http.h
6
4
  Date: 21Apr06
7
5
 
@@ -1,7 +1,5 @@
1
1
  /*****************************************************************************
2
2
 
3
- $Id: rubyhttp.cpp 3966 2007-03-16 11:52:05Z francis $
4
-
5
3
  File: libmain.cpp
6
4
  Date: 06Apr06
7
5
 
@@ -87,6 +85,10 @@ void RubyHttpConnection_t::CloseConnection (bool after_writing)
87
85
  }
88
86
 
89
87
 
88
+ /*************************************
89
+ RubyHttpConnection_t::ReceivePostData
90
+ *************************************/
91
+
90
92
  void RubyHttpConnection_t::ReceivePostData (const char *data, int len)
91
93
  {
92
94
  VALUE data_val = Qnil;
@@ -205,6 +207,7 @@ t_receive_post_data
205
207
  static VALUE t_receive_post_data (VALUE self, VALUE data)
206
208
  {
207
209
  /** This is a NOOP. It should be overridden. **/
210
+ return Qnil;
208
211
  }
209
212
 
210
213
  /********
@@ -1,5 +1,3 @@
1
- # $Id: evma_httpserver.rb 3897 2007-03-06 20:21:08Z francis $
2
- #
3
1
  # EventMachine HTTP Server
4
2
  #
5
3
  # Author:: blackhedd (gmail address: garbagecat10).
@@ -1,5 +1,3 @@
1
- # $Id: response.rb 3897 2007-03-06 20:21:08Z francis $
2
- #
3
1
  # EventMachine HTTP Server
4
2
  # HTTP Response-support class
5
3
  #
@@ -34,6 +32,22 @@
34
32
 
35
33
  module EventMachine
36
34
 
35
+ # This class provides a wide variety of features for generating and
36
+ # dispatching HTTP responses. It allows you to conveniently generate
37
+ # headers and content (including chunks and multiparts), and dispatch
38
+ # responses (including deferred or partially-complete responses).
39
+ #
40
+ # Although HttpResponse is coded as a class, it's not complete as it
41
+ # stands. It assumes that it has certain of the behaviors of
42
+ # EventMachine::Connection. You must add these behaviors, either by
43
+ # subclassing HttpResponse, or using the alternate version of this
44
+ # class, DelegatedHttpResponse. See the test cases for current information
45
+ # on which behaviors you have to add.
46
+ #
47
+ # TODO, someday it would be nice to provide a version of this functionality
48
+ # that is coded as a Module, so it can simply be mixed into an instance of
49
+ # EventMachine::Connection.
50
+ #
37
51
  class HttpResponse
38
52
  attr_accessor :status, :content, :headers, :chunks, :multiparts
39
53
 
@@ -108,7 +122,7 @@ module EventMachine
108
122
  def generate_header_lines in_hash
109
123
  out_ary = []
110
124
  in_hash.keys.sort.each {|k|
111
- v = @headers[k]
125
+ v = in_hash[k]
112
126
  if v.is_a?(Array)
113
127
  v.each {|v1| out_ary << "#{k}: #{v1}\r\n" }
114
128
  else
@@ -257,7 +271,7 @@ module EventMachine
257
271
  end
258
272
  end
259
273
 
260
- #
274
+ # TODO, this is going to be way too slow. Cache up the uuidgens.
261
275
  #
262
276
  def self.concoct_multipart_boundary
263
277
  @multipart_index ||= 0
@@ -278,3 +292,22 @@ module EventMachine
278
292
  end
279
293
  end
280
294
 
295
+ #----------------------------------------------------------------------------
296
+
297
+ require 'forwardable'
298
+
299
+ module EventMachine
300
+ class DelegatedHttpResponse < HttpResponse
301
+ extend Forwardable
302
+ def_delegators :@delegate,
303
+ :send_data,
304
+ :close_connection,
305
+ :close_connection_after_writing
306
+
307
+ def initialize dele
308
+ super()
309
+ @delegate = dele
310
+ end
311
+ end
312
+ end
313
+
@@ -0,0 +1,239 @@
1
+ require 'test/unit'
2
+ require 'evma_httpserver'
3
+
4
+ begin
5
+ once = false
6
+ require 'eventmachine'
7
+ rescue LoadError => e
8
+ raise e if once
9
+ once = true
10
+ require 'rubygems'
11
+ retry
12
+ end
13
+
14
+
15
+
16
+ #--------------------------------------
17
+
18
+ module EventMachine
19
+ module HttpServer
20
+ def process_http_request
21
+ send_data generate_response()
22
+ close_connection_after_writing
23
+ end
24
+ end
25
+ end
26
+
27
+ #--------------------------------------
28
+
29
+ require 'socket'
30
+
31
+ class TestApp < Test::Unit::TestCase
32
+
33
+ TestHost = "127.0.0.1"
34
+ TestPort = 8911
35
+
36
+ TestResponse_1 = <<EORESP
37
+ HTTP/1.0 200 ...
38
+ Content-length: 4
39
+ Content-type: text/plain
40
+ Connection: close
41
+
42
+ 1234
43
+ EORESP
44
+
45
+ Thread.abort_on_exception = true
46
+
47
+ def test_simple_get
48
+ received_response = nil
49
+
50
+ EventMachine::HttpServer.module_eval do
51
+ def generate_response
52
+ TestResponse_1
53
+ end
54
+ end
55
+
56
+
57
+ EventMachine.run do
58
+ EventMachine.start_server TestHost, TestPort, EventMachine::HttpServer
59
+ EventMachine.add_timer(1) {raise "timed out"} # make sure the test completes
60
+
61
+ cb = proc do
62
+ tcp = TCPSocket.new TestHost, TestPort
63
+ tcp.write "GET / HTTP/1.0\r\n\r\n"
64
+ received_response = tcp.read
65
+ end
66
+ eb = proc { EventMachine.stop }
67
+ EventMachine.defer cb, eb
68
+ end
69
+
70
+ assert_equal( TestResponse_1, received_response )
71
+ end
72
+
73
+
74
+
75
+
76
+ # This frowsy-looking protocol handler allows the test harness to make some
77
+ # its local variables visible, so we can set them here and they can be asserted later.
78
+ class MyTestServer < EventMachine::Connection
79
+ include EventMachine::HttpServer
80
+ def initialize *args
81
+ super
82
+ end
83
+ def generate_response
84
+ @assertions.call
85
+ TestResponse_1
86
+ end
87
+ end
88
+
89
+
90
+
91
+ def test_parameters
92
+ path_info = "/test.html"
93
+ query_string = "a=b&c=d"
94
+ cookie = "eat_me=I'm a cookie"
95
+ etag = "12345"
96
+
97
+ # collect all the stuff we want to assert outside the actual test,
98
+ # to ensure it gets asserted even if the test catches some exception.
99
+ received_response = nil
100
+ request_parms = {}
101
+
102
+
103
+ EventMachine.run do
104
+ EventMachine.start_server(TestHost, TestPort, MyTestServer) do |conn|
105
+ # In each accepted connection, set up a procedure that will copy
106
+ # the request parameters into a local variable visible here, so
107
+ # we can assert the values later.
108
+ conn.instance_eval do
109
+ @assertions = proc {
110
+ parms = %w( PATH_INFO QUERY_STRING HTTP_COOKIE IF_NONE_MATCH
111
+ CONTENT_TYPE REQUEST_METHOD REQUEST_URI )
112
+ parms.each {|parm|
113
+ # request_parms is bound to a local variable visible in this context.
114
+ request_parms[parm] = ENV[parm]
115
+ }
116
+ }
117
+ end
118
+ end
119
+ EventMachine.add_timer(1) {raise "timed out"} # make sure the test completes
120
+
121
+ cb = proc do
122
+ tcp = TCPSocket.new TestHost, TestPort
123
+ data = [
124
+ "GET #{path_info}?#{query_string} HTTP/1.1\r\n",
125
+ "Cookie: #{cookie}\r\n",
126
+ "If-none-match: #{etag}\r\n",
127
+ "\r\n"
128
+ ].join
129
+ tcp.write(data)
130
+ received_response = tcp.read
131
+ end
132
+ eb = proc { EventMachine.stop }
133
+ EventMachine.defer cb, eb
134
+ end
135
+
136
+ assert_equal( TestResponse_1, received_response )
137
+ assert_equal( path_info, request_parms["PATH_INFO"] )
138
+ assert_equal( query_string, request_parms["QUERY_STRING"] )
139
+ assert_equal( cookie, request_parms["HTTP_COOKIE"] )
140
+ assert_equal( etag, request_parms["IF_NONE_MATCH"] )
141
+ assert_equal( nil, request_parms["CONTENT_TYPE"] )
142
+ assert_equal( "GET", request_parms["REQUEST_METHOD"] )
143
+ assert_equal( path_info, request_parms["REQUEST_URI"] )
144
+ end
145
+
146
+
147
+ def test_headers
148
+ received_header_string = nil
149
+ received_header_ary = nil
150
+
151
+ EventMachine.run do
152
+ EventMachine.start_server(TestHost, TestPort, MyTestServer) do |conn|
153
+ # In each accepted connection, set up a procedure that will copy
154
+ # the request parameters into a local variable visible here, so
155
+ # we can assert the values later.
156
+ # The @http_headers is set automatically and can easily be parsed.
157
+ # It isn't automatically parsed into Ruby values because that is
158
+ # a costly operation, but we should provide an optional method that
159
+ # does the parsing so it doesn't need to be done by users.
160
+ conn.instance_eval do
161
+ @assertions = proc do
162
+ received_header_string = @http_headers
163
+ received_header_ary = @http_headers.split(/\0/).map {|line| line.split(/:\s*/, 2) }
164
+ end
165
+ end
166
+ end
167
+
168
+ cb = proc do
169
+ tcp = TCPSocket.new TestHost, TestPort
170
+ data = [
171
+ "GET / HTTP/1.1\r\n",
172
+ "aaa: 111\r\n",
173
+ "bbb: 222\r\n",
174
+ "ccc: 333\r\n",
175
+ "ddd: 444\r\n",
176
+ "\r\n"
177
+ ].join
178
+ tcp.write data
179
+ received_response = tcp.read
180
+ end
181
+ eb = proc { EventMachine.stop }
182
+ EventMachine.defer cb, eb
183
+
184
+ EventMachine.add_timer(1) {raise "timed out"} # make sure the test completes
185
+ end
186
+
187
+ assert_equal( "aaa: 111\0bbb: 222\0ccc: 333\0ddd: 444\0\0", received_header_string )
188
+ assert_equal( [["aaa","111"], ["bbb","222"], ["ccc","333"], ["ddd","444"]], received_header_ary )
189
+ end
190
+
191
+
192
+
193
+
194
+
195
+ def test_post
196
+ received_header_string = nil
197
+ post_content = "1234567890"
198
+ content_type = "text/plain"
199
+ received_post_content = ""
200
+ received_content_type = ""
201
+
202
+ EventMachine.run do
203
+ EventMachine.start_server(TestHost, TestPort, MyTestServer) do |conn|
204
+ # In each accepted connection, set up a procedure that will copy
205
+ # the request parameters into a local variable visible here, so
206
+ # we can assert the values later.
207
+ # The @http_post_content variable is set automatically.
208
+ conn.instance_eval do
209
+ @assertions = proc do
210
+ received_post_content = @http_post_content
211
+ received_content_type = ENV["CONTENT_TYPE"]
212
+ end
213
+ end
214
+ end
215
+ EventMachine.add_timer(1) {raise "timed out"} # make sure the test completes
216
+
217
+ cb = proc do
218
+ tcp = TCPSocket.new TestHost, TestPort
219
+ data = [
220
+ "POST / HTTP/1.1\r\n",
221
+ "Content-type: #{content_type}\r\n",
222
+ "Content-length: #{post_content.length}\r\n",
223
+ "\r\n",
224
+ post_content
225
+ ].join
226
+ tcp.write(data)
227
+ received_response = tcp.read
228
+ end
229
+ eb = proc do
230
+ EventMachine.stop
231
+ end
232
+ EventMachine.defer cb, eb
233
+ end
234
+
235
+ assert_equal( received_post_content, post_content )
236
+ assert_equal( received_content_type, content_type )
237
+ end
238
+
239
+ end