ebb 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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