eventmachine_httpserver 0.0.1 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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