webrick-high-performance 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +27 -0
- data/Manifest.txt +5 -0
- data/README +54 -0
- data/Rakefile +69 -0
- data/lib/webrick/highperformanceserver.rb +156 -0
- metadata +67 -0
data/LICENSE
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
Copyright 2005 Eric Hodel, The Robot Co-op. All rights reserved.
|
2
|
+
|
3
|
+
Redistribution and use in source and binary forms, with or without
|
4
|
+
modification, are permitted provided that the following conditions
|
5
|
+
are met:
|
6
|
+
|
7
|
+
1. Redistributions of source code must retain the above copyright
|
8
|
+
notice, this list of conditions and the following disclaimer.
|
9
|
+
2. Redistributions in binary form must reproduce the above copyright
|
10
|
+
notice, this list of conditions and the following disclaimer in the
|
11
|
+
documentation and/or other materials provided with the distribution.
|
12
|
+
3. Neither the names of the authors nor the names of their contributors
|
13
|
+
may be used to endorse or promote products derived from this software
|
14
|
+
without specific prior written permission.
|
15
|
+
|
16
|
+
THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS
|
17
|
+
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
18
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
19
|
+
ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
|
20
|
+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
21
|
+
OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
22
|
+
OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
23
|
+
BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
24
|
+
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
25
|
+
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
26
|
+
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
27
|
+
|
data/Manifest.txt
ADDED
data/README
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
= WEBrick High Performance
|
2
|
+
|
3
|
+
Rubyforge Project:
|
4
|
+
|
5
|
+
http://rubyforge.org/projects/rctools/
|
6
|
+
|
7
|
+
Documentation:
|
8
|
+
|
9
|
+
http://dev.robotcoop.com/Libraries/webrick-high-performance/
|
10
|
+
|
11
|
+
== About
|
12
|
+
|
13
|
+
WEBrick High Performance adds a new HTTP server class that takes advantage of
|
14
|
+
sendfile(2) and fork(2) to drastically improve static file server performance.
|
15
|
+
|
16
|
+
Since HighPerformanceServer is a forking webserver it may also speed up regular
|
17
|
+
WEBrick servlets by spreading load across multiple CPUs.
|
18
|
+
|
19
|
+
The sendfile(2) system call allows web server writers to offload the job of
|
20
|
+
transfering files from the disk to the socket onto the kernel. The work of
|
21
|
+
parsing HTTP headers is very easy and very fast and WEBrick is nearly fast
|
22
|
+
enough to match Apache.
|
23
|
+
|
24
|
+
When additional work is needed to look up or validate file access (for example,
|
25
|
+
the file is stored in MogileFS) it is more performant to write the code in Ruby
|
26
|
+
and use HighPerformanceServer than to write a FastCGI handler and easier than writing an Apache module.
|
27
|
+
|
28
|
+
== Installing webrick-high-performance
|
29
|
+
|
30
|
+
webrick-high-performance depends upon socket_sendfile, and as of 1.0.0
|
31
|
+
socket_sendfile is only known to work on FreeBSD.
|
32
|
+
|
33
|
+
So if you've got FreeBSD you only need to install the gem:
|
34
|
+
|
35
|
+
$ sudo gem install webrick-high-performance
|
36
|
+
|
37
|
+
== Using webrick-high-performance
|
38
|
+
|
39
|
+
#!/usr/local/bin/ruby -w
|
40
|
+
|
41
|
+
require 'rubygems'
|
42
|
+
require 'webrick'
|
43
|
+
require 'webrick/highperformanceserver'
|
44
|
+
|
45
|
+
config = {}
|
46
|
+
config[:Port] = 8000
|
47
|
+
config[:Root] = File.expand_path '~/public_html'
|
48
|
+
|
49
|
+
WEBrick::HighPerformanceServer.create config do |server|
|
50
|
+
trap 'INT' do server.shutdown end
|
51
|
+
trap 'TERM' do server.shutdown end
|
52
|
+
server.start
|
53
|
+
end
|
54
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
require 'rake/testtask'
|
4
|
+
require 'rake/rdoctask'
|
5
|
+
require 'rake/gempackagetask'
|
6
|
+
|
7
|
+
$VERBOSE = nil
|
8
|
+
|
9
|
+
spec = Gem::Specification.new do |s|
|
10
|
+
s.name = 'webrick-high-performance'
|
11
|
+
s.version = '1.0.0'
|
12
|
+
s.summary = 'A high-performance WEBrick server'
|
13
|
+
s.description = 'A high-performance WEBrick server that takes advantage of sendfile(2) and fork(2) to serve static files really fast.'
|
14
|
+
s.author = 'Eric Hodel'
|
15
|
+
s.email = 'eric@robotcoop.com'
|
16
|
+
|
17
|
+
s.has_rdoc = true
|
18
|
+
s.files = File.read('Manifest.txt').split($/)
|
19
|
+
s.require_path = 'lib'
|
20
|
+
|
21
|
+
s.test_files = Dir.glob('test/test_*.rb')
|
22
|
+
|
23
|
+
s.add_dependency 'socket_sendfile', '>= 1.1.0'
|
24
|
+
s.add_dependency 'socket_accept_filter', '>= 1.0.0'
|
25
|
+
end
|
26
|
+
|
27
|
+
desc 'Run tests'
|
28
|
+
task :default => [ :test ]
|
29
|
+
|
30
|
+
Rake::TestTask.new('test') do |t|
|
31
|
+
t.libs << 'test'
|
32
|
+
t.pattern = 'test/test_*.rb'
|
33
|
+
t.verbose = true
|
34
|
+
end
|
35
|
+
|
36
|
+
desc 'Update Manifest.txt'
|
37
|
+
task :update_manifest do
|
38
|
+
sh "find . -type f | sed -e 's%./%%' | egrep -v 'svn|swp|~' | egrep -v '^(doc|pkg)/' | sort > Manifest.txt"
|
39
|
+
end
|
40
|
+
|
41
|
+
desc 'Generate RDoc'
|
42
|
+
Rake::RDocTask.new :rdoc do |rd|
|
43
|
+
rd.rdoc_dir = 'doc'
|
44
|
+
rd.rdoc_files.add 'lib', 'README', 'LICENSE'
|
45
|
+
rd.main = 'README'
|
46
|
+
rd.options << '-d' if `which dot` =~ /\/dot/
|
47
|
+
end
|
48
|
+
|
49
|
+
desc 'Generate RDoc for dev.robotcoop.com'
|
50
|
+
Rake::RDocTask.new :dev_rdoc do |rd|
|
51
|
+
rd.rdoc_dir = '../../../www/trunk/dev/html/Libraries/webrick-high-performance'
|
52
|
+
rd.rdoc_files.add 'lib', 'README', 'LICENSE'
|
53
|
+
rd.main = 'README'
|
54
|
+
rd.options << '-d' if `which dot` =~ /\/dot/
|
55
|
+
end
|
56
|
+
|
57
|
+
desc 'Build Gem'
|
58
|
+
Rake::GemPackageTask.new spec do |pkg|
|
59
|
+
pkg.need_tar = true
|
60
|
+
end
|
61
|
+
|
62
|
+
desc 'Clean up'
|
63
|
+
task :clean => [ :clobber_rdoc, :clobber_package ]
|
64
|
+
|
65
|
+
desc 'Clean up'
|
66
|
+
task :clobber => [ :clean ]
|
67
|
+
|
68
|
+
# vim: syntax=Ruby
|
69
|
+
|
@@ -0,0 +1,156 @@
|
|
1
|
+
require 'webrick'
|
2
|
+
require 'socket_accept_filter' rescue LoadError
|
3
|
+
require 'socket_sendfile'
|
4
|
+
|
5
|
+
class WEBrick::HTTPResponse # :nodoc:
|
6
|
+
|
7
|
+
alias old_send_body_io send_body_io
|
8
|
+
alias old_chunked? chunked?
|
9
|
+
|
10
|
+
def chunked?
|
11
|
+
return @body.is_a?(File) ? false : @chunked
|
12
|
+
end
|
13
|
+
|
14
|
+
##
|
15
|
+
# Copied from WEBrick::HTTPResponse to add sendfile support.
|
16
|
+
|
17
|
+
def send_body_io(socket)
|
18
|
+
socket.setsockopt Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1 # HACK yuck
|
19
|
+
|
20
|
+
if @request_method == "HEAD"
|
21
|
+
# do nothing
|
22
|
+
elsif @body.kind_of? File
|
23
|
+
socket.sendfile @body
|
24
|
+
elsif chunked?
|
25
|
+
while buf = @body.read(BUFSIZE)
|
26
|
+
next if buf.empty?
|
27
|
+
data = ""
|
28
|
+
data << format("%x", buf.size) << CRLF
|
29
|
+
data << buf << CRLF
|
30
|
+
_write_data(socket, data)
|
31
|
+
@sent_size += buf.size
|
32
|
+
end
|
33
|
+
_write_data(socket, "0#{CRLF}#{CRLF}")
|
34
|
+
else
|
35
|
+
size = @header['content-length'].to_i
|
36
|
+
_send_file(socket, @body, 0, size)
|
37
|
+
@sent_size = size
|
38
|
+
end
|
39
|
+
ensure
|
40
|
+
@body.close
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
module WEBrick::Config
|
46
|
+
|
47
|
+
##
|
48
|
+
# HighPerformanceServer default configuration.
|
49
|
+
|
50
|
+
HighPerformance = HTTP.dup.update(
|
51
|
+
:RequestTimeout => 2,
|
52
|
+
:Processes => 8
|
53
|
+
)
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# A high performance WEBrick server that takes advantage of sendfile(2) and
|
59
|
+
# fork(2) to drastically increase the performance of serving static files.
|
60
|
+
#
|
61
|
+
# Instead of starting a HighPerformanceServer like a regular HTTPServer, use
|
62
|
+
# HighPerformanceServer::create.
|
63
|
+
|
64
|
+
class WEBrick::HighPerformanceServer < WEBrick::HTTPServer
|
65
|
+
|
66
|
+
##
|
67
|
+
# This process starts up a bunch of listeners than forks children to do the
|
68
|
+
# actual work.
|
69
|
+
|
70
|
+
@listeners = []
|
71
|
+
|
72
|
+
class << self
|
73
|
+
|
74
|
+
##
|
75
|
+
# Server sockets for my children.
|
76
|
+
|
77
|
+
attr_accessor :listeners
|
78
|
+
|
79
|
+
##
|
80
|
+
# Creates :Processes new HighPerformanceServers all listening on the same
|
81
|
+
# server sockets.
|
82
|
+
#
|
83
|
+
# +config+ and +default+ work the same as they do for HTTPServer.
|
84
|
+
#
|
85
|
+
# yields each forked child's server object. The server will not be
|
86
|
+
# started nor will signals be caught.
|
87
|
+
#
|
88
|
+
# Returns the pids of the created HighPerformanceServer children.
|
89
|
+
#
|
90
|
+
# Typical usage:
|
91
|
+
#
|
92
|
+
# WEBrick::HighPerformanceServer.create do |server|
|
93
|
+
# server.mount '/', WEBrick::HTTPServlet::FileHandler,
|
94
|
+
# '/usr/local/www/data'
|
95
|
+
# trap 'INT' do server.shutdown end
|
96
|
+
# trap 'TERM' do server.shutdown end
|
97
|
+
# server.start
|
98
|
+
# end
|
99
|
+
|
100
|
+
def create(config = {}, default = WEBrick::Config::HighPerformance)
|
101
|
+
config = default.dup.update config
|
102
|
+
bind_address = config[:BindAddress]
|
103
|
+
port = config[:Port]
|
104
|
+
processes = config[:Processes]
|
105
|
+
config[:Logger] ||= WEBrick::Log.new
|
106
|
+
|
107
|
+
@listeners = WEBrick::Utils.create_listeners bind_address, port
|
108
|
+
if @listeners.first.respond_to? :set_accept_filter then
|
109
|
+
@listeners.each do |server|
|
110
|
+
server.set_accept_filter 'httpready'
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
pids = []
|
115
|
+
|
116
|
+
processes.times do
|
117
|
+
pids << fork do
|
118
|
+
server = self.new config, default
|
119
|
+
yield server
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
return pids
|
124
|
+
end
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
##
|
129
|
+
# Only need to override default.
|
130
|
+
|
131
|
+
def initialize(config = {}, default = WEBrick::Config::HighPerformance)
|
132
|
+
super config, default
|
133
|
+
end
|
134
|
+
|
135
|
+
##
|
136
|
+
# HighPerformanceServer doesn't log. Oh you want access logs? Well tough!
|
137
|
+
|
138
|
+
def access_log(*args)
|
139
|
+
end
|
140
|
+
|
141
|
+
##
|
142
|
+
# Our listeners have already been created, so suck them in from the class.
|
143
|
+
|
144
|
+
def listen(address, port)
|
145
|
+
@listeners = self.class.listeners
|
146
|
+
end
|
147
|
+
|
148
|
+
##
|
149
|
+
# Don't close the listeners, just stop.
|
150
|
+
|
151
|
+
def shutdown
|
152
|
+
stop
|
153
|
+
end
|
154
|
+
|
155
|
+
end
|
156
|
+
|
metadata
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.11.6
|
3
|
+
specification_version: 1
|
4
|
+
name: webrick-high-performance
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: 1.0.0
|
7
|
+
date: 2006-03-24 00:00:00 -08:00
|
8
|
+
summary: A high-performance WEBrick server
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: eric@robotcoop.com
|
12
|
+
homepage:
|
13
|
+
rubyforge_project:
|
14
|
+
description: A high-performance WEBrick server that takes advantage of sendfile(2) and fork(2) to serve static files really fast.
|
15
|
+
autorequire:
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
post_install_message:
|
29
|
+
authors:
|
30
|
+
- Eric Hodel
|
31
|
+
files:
|
32
|
+
- LICENSE
|
33
|
+
- Manifest.txt
|
34
|
+
- README
|
35
|
+
- Rakefile
|
36
|
+
- lib/webrick/highperformanceserver.rb
|
37
|
+
test_files: []
|
38
|
+
|
39
|
+
rdoc_options: []
|
40
|
+
|
41
|
+
extra_rdoc_files: []
|
42
|
+
|
43
|
+
executables: []
|
44
|
+
|
45
|
+
extensions: []
|
46
|
+
|
47
|
+
requirements: []
|
48
|
+
|
49
|
+
dependencies:
|
50
|
+
- !ruby/object:Gem::Dependency
|
51
|
+
name: socket_sendfile
|
52
|
+
version_requirement:
|
53
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: 1.1.0
|
58
|
+
version:
|
59
|
+
- !ruby/object:Gem::Dependency
|
60
|
+
name: socket_accept_filter
|
61
|
+
version_requirement:
|
62
|
+
version_requirements: !ruby/object:Gem::Version::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: 1.0.0
|
67
|
+
version:
|