ebb 0.1.0 → 0.2.0

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/libev/ev_vars.h CHANGED
@@ -1,3 +1,42 @@
1
+ /*
2
+ * loop member variable declarations
3
+ *
4
+ * Copyright (c) 2007,2008 Marc Alexander Lehmann <libev@schmorp.de>
5
+ * All rights reserved.
6
+ *
7
+ * Redistribution and use in source and binary forms, with or without modifica-
8
+ * tion, are permitted provided that the following conditions are met:
9
+ *
10
+ * 1. Redistributions of source code must retain the above copyright notice,
11
+ * this list of conditions and the following disclaimer.
12
+ *
13
+ * 2. Redistributions in binary form must reproduce the above copyright
14
+ * notice, this list of conditions and the following disclaimer in the
15
+ * documentation and/or other materials provided with the distribution.
16
+ *
17
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
19
+ * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
20
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
21
+ * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
25
+ * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
26
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
27
+ *
28
+ * Alternatively, the contents of this file may be used under the terms of
29
+ * the GNU General Public License ("GPL") version 2 or any later version,
30
+ * in which case the provisions of the GPL are applicable instead of
31
+ * the above. If you wish to allow the use of your version of this file
32
+ * only under the terms of the GPL and not to allow others to use your
33
+ * version of this file under the BSD license, indicate your decision
34
+ * by deleting the provisions above and replace them with the notice
35
+ * and other provisions required by the GPL. If you do not delete the
36
+ * provisions above, a recipient may use your version of this file under
37
+ * either the BSD or the GPL.
38
+ */
39
+
1
40
  #define VARx(type,name) VAR(name, type name)
2
41
 
3
42
  VARx(ev_tstamp, now_floor) /* last time we refreshed rt_time */
@@ -16,6 +55,9 @@ VARx(ev_tstamp, backend_fudge) /* assumed typical timer resolution */
16
55
  VAR (backend_modify, void (*backend_modify)(EV_P_ int fd, int oev, int nev))
17
56
  VAR (backend_poll , void (*backend_poll)(EV_P_ ev_tstamp timeout))
18
57
 
58
+ VAR (evpipe, int evpipe [2])
59
+ VARx(ev_io, pipeev)
60
+
19
61
  #if !defined(_WIN32) || EV_GENWRAP
20
62
  VARx(pid_t, curpid)
21
63
  #endif
@@ -98,6 +140,13 @@ VARx(int, forkmax)
98
140
  VARx(int, forkcnt)
99
141
  #endif
100
142
 
143
+ VARx(EV_ATOMIC_T, gotasync)
144
+ #if EV_ASYNC_ENABLE || EV_GENWRAP
145
+ VARx(struct ev_async **, asyncs)
146
+ VARx(int, asyncmax)
147
+ VARx(int, asynccnt)
148
+ #endif
149
+
101
150
  #if EV_USE_INOTIFY || EV_GENWRAP
102
151
  VARx(int, fs_fd)
103
152
  VARx(ev_io, fs_w)
data/libev/ev_win32.c CHANGED
@@ -1,32 +1,40 @@
1
1
  /*
2
- * libev win32 compatibility cruft
2
+ * libev win32 compatibility cruft (_not_ a backend)
3
3
  *
4
4
  * Copyright (c) 2007 Marc Alexander Lehmann <libev@schmorp.de>
5
5
  * All rights reserved.
6
6
  *
7
- * Redistribution and use in source and binary forms, with or without
8
- * modification, are permitted provided that the following conditions are
9
- * met:
7
+ * Redistribution and use in source and binary forms, with or without modifica-
8
+ * tion, are permitted provided that the following conditions are met:
9
+ *
10
+ * 1. Redistributions of source code must retain the above copyright notice,
11
+ * this list of conditions and the following disclaimer.
12
+ *
13
+ * 2. Redistributions in binary form must reproduce the above copyright
14
+ * notice, this list of conditions and the following disclaimer in the
15
+ * documentation and/or other materials provided with the distribution.
16
+ *
17
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
18
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
19
+ * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
20
+ * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
21
+ * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
23
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
24
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
25
+ * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
26
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
10
27
  *
11
- * * Redistributions of source code must retain the above copyright
12
- * notice, this list of conditions and the following disclaimer.
13
- *
14
- * * Redistributions in binary form must reproduce the above
15
- * copyright notice, this list of conditions and the following
16
- * disclaimer in the documentation and/or other materials provided
17
- * with the distribution.
18
- *
19
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
+ * Alternatively, the contents of this file may be used under the terms of
29
+ * the GNU General Public License ("GPL") version 2 or any later version,
30
+ * in which case the provisions of the GPL are applicable instead of
31
+ * the above. If you wish to allow the use of your version of this file
32
+ * only under the terms of the GPL and not to allow others to use your
33
+ * version of this file under the BSD license, indicate your decision
34
+ * by deleting the provisions above and replace them with the notice
35
+ * and other provisions required by the GPL. If you do not delete the
36
+ * provisions above, a recipient may use your version of this file under
37
+ * either the BSD or the GPL.
30
38
  */
31
39
 
32
40
  #ifdef _WIN32
data/libev/ev_wrap.h CHANGED
@@ -13,6 +13,8 @@
13
13
  #define backend_fudge ((loop)->backend_fudge)
14
14
  #define backend_modify ((loop)->backend_modify)
15
15
  #define backend_poll ((loop)->backend_poll)
16
+ #define evpipe ((loop)->evpipe)
17
+ #define pipeev ((loop)->pipeev)
16
18
  #define curpid ((loop)->curpid)
17
19
  #define postfork ((loop)->postfork)
18
20
  #define vec_ri ((loop)->vec_ri)
@@ -61,6 +63,10 @@
61
63
  #define forks ((loop)->forks)
62
64
  #define forkmax ((loop)->forkmax)
63
65
  #define forkcnt ((loop)->forkcnt)
66
+ #define gotasync ((loop)->gotasync)
67
+ #define asyncs ((loop)->asyncs)
68
+ #define asyncmax ((loop)->asyncmax)
69
+ #define asynccnt ((loop)->asynccnt)
64
70
  #define fs_fd ((loop)->fs_fd)
65
71
  #define fs_w ((loop)->fs_w)
66
72
  #define fs_hash ((loop)->fs_hash)
@@ -78,6 +84,8 @@
78
84
  #undef backend_fudge
79
85
  #undef backend_modify
80
86
  #undef backend_poll
87
+ #undef evpipe
88
+ #undef pipeev
81
89
  #undef curpid
82
90
  #undef postfork
83
91
  #undef vec_ri
@@ -126,6 +134,10 @@
126
134
  #undef forks
127
135
  #undef forkmax
128
136
  #undef forkcnt
137
+ #undef gotasync
138
+ #undef asyncs
139
+ #undef asyncmax
140
+ #undef asynccnt
129
141
  #undef fs_fd
130
142
  #undef fs_w
131
143
  #undef fs_hash
data/ruby_lib/ebb.rb CHANGED
@@ -3,33 +3,37 @@
3
3
  # See README file for details.
4
4
  require 'stringio'
5
5
  module Ebb
6
+ VERSION = "0.2.0"
6
7
  LIBDIR = File.dirname(__FILE__)
7
- require Ebb::LIBDIR + '/../src/ebb_ext'
8
8
  autoload :Runner, LIBDIR + '/ebb/runner'
9
+ autoload :FFI, LIBDIR + '/../src/ebb_ext'
9
10
 
10
11
  def self.start_server(app, options={})
11
- port = (options[:port] || 4001).to_i
12
- if options.has_key?(:threaded_processing)
13
- threaded_processing = options[:threaded_processing] ? true : false
12
+ if options.has_key?(:fileno)
13
+ fd = options[:fileno].to_i
14
+ FFI::server_listen_on_fd(fd)
15
+ log.puts "Ebb is listening on file descriptor #{fd}"
16
+ elsif options.has_key?(:unix_socket)
17
+ socketfile = options[:unix_socket]
18
+ FFI::server_listen_on_unix_socket(socketfile)
19
+ log.puts "Ebb is listening on unix socket #{socketfile}"
14
20
  else
15
- threaded_processing = true
21
+ port = (options[:port] || 4001).to_i
22
+ FFI::server_listen_on_port(port)
23
+ log.puts "Ebb is listening at http://0.0.0.0:#{port}/"
16
24
  end
25
+ log.puts "Ebb PID #{Process.pid}"
17
26
 
18
- Client::BASE_ENV['rack.multithread'] = threaded_processing
19
-
20
- FFI::server_listen_on_port(port)
21
27
  @running = true
22
28
  trap('INT') { stop_server }
23
29
 
24
- log.puts "Ebb listening at http://0.0.0.0:#{port}/ (#{threaded_processing ? 'threaded' : 'sequential'} processing, PID #{Process.pid})"
25
-
26
30
  while @running
27
31
  FFI::server_process_connections()
28
- while client = FFI::waiting_clients.shift
29
- if threaded_processing
30
- Thread.new(client) { |c| process(app, c) }
31
- else
32
+ while client = FFI::server_waiting_clients.shift
33
+ if app.respond_to?(:deferred?) and !app.deferred?(client.env)
32
34
  process(app, client)
35
+ else
36
+ Thread.new(client) { |c| process(app, c) }
33
37
  end
34
38
  end
35
39
  end
@@ -45,34 +49,40 @@ module Ebb
45
49
  end
46
50
 
47
51
  def self.process(app, client)
48
- begin
49
- status, headers, body = app.call(client.env)
50
- rescue
51
- raise if $DEBUG
52
- status = 500
53
- headers = {'Content-Type' => 'text/plain'}
54
- body = "Internal Server Error\n"
55
- end
52
+ #p client.env
53
+ status, headers, body = app.call(client.env)
56
54
 
55
+ # Write the status
57
56
  client.write_status(status)
58
57
 
59
- if headers.respond_to?(:[]=) and body.respond_to?(:length) and status != 304
60
- headers['Connection'] = 'close'
58
+ # Add Content-Length to the headers.
59
+ if headers['Content-Length'].nil? and
60
+ headers.respond_to?(:[]=) and
61
+ body.respond_to?(:length) and
62
+ status != 304
63
+ then
61
64
  headers['Content-Length'] = body.length.to_s
62
65
  end
63
66
 
67
+ # Decide if we should keep the connection alive or not
68
+ if headers['Connection'].nil?
69
+ if headers['Content-Length'] and client.should_keep_alive?
70
+ headers['Connection'] = 'Keep-Alive'
71
+ else
72
+ headers['Connection'] = 'close'
73
+ end
74
+ end
75
+
76
+ # Write the headers
64
77
  headers.each { |field, value| client.write_header(field, value) }
65
- client.write("\r\n")
66
78
 
79
+ # Write the body
67
80
  if body.kind_of?(String)
68
- client.write(body)
69
- client.body_written()
70
- client.begin_transmission()
81
+ client.write_body(body)
71
82
  else
72
- client.begin_transmission()
73
- body.each { |p| client.write(p) }
74
- client.body_written()
83
+ body.each { |p| client.write_body(p) }
75
84
  end
85
+
76
86
  rescue => e
77
87
  log.puts "Ebb Error! #{e.class} #{e.message}"
78
88
  log.puts e.backtrace.join("\n")
@@ -88,16 +98,12 @@ module Ebb
88
98
  @@log
89
99
  end
90
100
 
91
- # This array is created and manipulated in the C extension.
92
- def FFI.waiting_clients
93
- @waiting_clients
94
- end
95
-
96
101
  class Client
102
+ attr_reader :fd, :body_head, :content_length
97
103
  BASE_ENV = {
98
104
  'SERVER_NAME' => '0.0.0.0',
99
105
  'SCRIPT_NAME' => '',
100
- 'SERVER_SOFTWARE' => "Ebb #{Ebb::VERSION}",
106
+ 'SERVER_SOFTWARE' => "Ebb-Ruby #{Ebb::VERSION}",
101
107
  'SERVER_PROTOCOL' => 'HTTP/1.1',
102
108
  'rack.version' => [0, 1],
103
109
  'rack.errors' => STDERR,
@@ -107,9 +113,11 @@ module Ebb
107
113
  }
108
114
 
109
115
  def env
110
- env = FFI::client_env(self).update(BASE_ENV)
111
- env['rack.input'] = RequestBody.new(self)
112
- env
116
+ @env ||= begin
117
+ env = FFI::client_env(self).update(BASE_ENV)
118
+ env['rack.input'] = RequestBody.new(self)
119
+ env
120
+ end
113
121
  end
114
122
 
115
123
  def write_status(status)
@@ -117,8 +125,8 @@ module Ebb
117
125
  FFI::client_write_status(self, s, HTTP_STATUS_CODES[s])
118
126
  end
119
127
 
120
- def write(data)
121
- FFI::client_write(self, data)
128
+ def write_body(data)
129
+ FFI::client_write_body(self, data)
122
130
  end
123
131
 
124
132
  def write_header(field, value)
@@ -127,50 +135,53 @@ module Ebb
127
135
  end
128
136
  end
129
137
 
130
- def body_written
131
- FFI::client_set_body_written(self, true)
138
+ def release
139
+ FFI::client_release(self)
132
140
  end
133
141
 
134
- def begin_transmission
135
- FFI::client_begin_transmission(self)
142
+ def set_keep_alive
143
+ FFI::client_set_keep_alive(self)
136
144
  end
137
145
 
138
- def release
139
- FFI::client_release(self)
146
+ def should_keep_alive?
147
+ if env['HTTP_VERSION'] == 'HTTP/1.0'
148
+ return true if env['HTTP_CONNECTION'] =~ /Keep-Alive/i
149
+ else
150
+ return true unless env['HTTP_CONNECTION'] =~ /close/i
151
+ end
152
+ false
140
153
  end
141
154
  end
142
155
 
143
156
  class RequestBody
144
157
  def initialize(client)
145
- @client = client
158
+ @content_length = client.content_length
159
+ if client.body_head
160
+ @body_head = StringIO.new(client.body_head)
161
+ if @body_head.length < @content_length
162
+ @socket = IO.new(client.fd)
163
+ end
164
+ end
165
+ @total_read = 0
146
166
  end
147
167
 
148
168
  def read(len = nil)
149
- if @io
150
- @io.read(len)
151
- else
152
- if len.nil?
153
- s = ''
154
- while(chunk = read(10*1024)) do
155
- s << chunk
156
- end
157
- s
158
- else
159
- FFI::client_read_input(@client, len)
160
- end
169
+ to_read = len.nil? ? @content_length - @total_read : min(len, @content_length - @total_read)
170
+ return nil if to_read == 0 or @body_head.nil?
171
+ unless out = @body_head.read(to_read)
172
+ return nil if @socket.nil?
173
+ out = @socket.read(to_read)
161
174
  end
175
+ @total_read += out.length
176
+ out
162
177
  end
163
178
 
164
179
  def gets
165
- io.gets
180
+ raise NotImplemented
166
181
  end
167
182
 
168
183
  def each(&block)
169
- io.each(&block)
170
- end
171
-
172
- def io
173
- @io ||= StringIO.new(read)
184
+ raise NotImplemented
174
185
  end
175
186
  end
176
187
 
@@ -215,3 +226,19 @@ module Ebb
215
226
  505 => 'HTTP Version not supported'
216
227
  }.freeze
217
228
  end
229
+
230
+
231
+ module Rack
232
+ module Handler
233
+ module Ebb
234
+ def self.run(app, options={})
235
+ ::Ebb.start_server(app, options)
236
+ end
237
+ end
238
+ end
239
+ end
240
+
241
+ # cause i don't want to create an array
242
+ def min(a,b)
243
+ a > b ? b : a
244
+ end
@@ -58,8 +58,7 @@ module Ebb
58
58
  @parser = OptionParser.new
59
59
  @options = {
60
60
  :port => 4001,
61
- :timeout => 60,
62
- :threaded_processing => true
61
+ :timeout => 60
63
62
  }
64
63
  end
65
64
 
@@ -69,8 +68,8 @@ module Ebb
69
68
  extra_options if respond_to?(:extra_options)
70
69
 
71
70
  @parser.separator ""
72
- # opts.on("-s", "--socket SOCKET", "listen on socket") { |socket| options[:socket] = socket }
73
- @parser.on("-p", "--port PORT", "(default: #{@options[:port]})") { |p| @options[:port]=p }
71
+ @parser.on("-p", "--port PORT", "(default: #{@options[:port]})") { |p| @options[:port] = p }
72
+ @parser.on("-s", "--socket SOCKET", "listen on unix domain socket") { |socket| options[:unix_socket] = socket }
74
73
  @parser.on("-d", "--daemonize", "Daemonize") { @options[:daemonize] = true }
75
74
  @parser.on("-l", "--log-file FILE", "File to redirect output") { |f| @options[:log_file]=f }
76
75
  @parser.on("-P", "--pid-file FILE", "File to store PID") { |f| @options[:pid_file]=f }
@@ -82,7 +81,7 @@ module Ebb
82
81
  exit
83
82
  end
84
83
  @parser.on_tail('-v', '--version', "Show version") do
85
- Ebb.log.puts "Ebb #{Ebb::VERSION}"
84
+ Ebb.log.puts Ebb::Client::BASE_ENV['SERVER_SOFTWARE']
86
85
  exit
87
86
  end
88
87