webrick-high-performance 1.0.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/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:
|