-- cgit v1.2.3-24-ge0c7 -- cgit v1.2.3-24-ge0c7 From 4025130860699c0de55efb4cce7ff06797983192 Mon Sep 17 00:00:00 2001 From: evanweaver Date: Sat, 15 Dec 2007 04:50:36 +0000 Subject: backport #15631 to 1-1-2 git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-1@897 19e92222-5c0b-0410-8929-a290d50e31e9 --- lib/mongrel.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mongrel.rb b/lib/mongrel.rb index e0dcab1..178762b 100644 --- a/lib/mongrel.rb +++ b/lib/mongrel.rb @@ -213,7 +213,7 @@ module Mongrel worker[:started_on] = Time.now if not worker[:started_on] if mark - worker[:started_on] > @timeout + @throttle - STDERR.puts "Thread #{w.inspect} is too old, killing." + STDERR.puts "Thread #{worker.inspect} is too old, killing." worker.raise(TimeoutError.new(error_msg)) end end -- cgit v1.2.3-24-ge0c7 From 3fc88a245465831723c6fd4941ad690c9c41577b Mon Sep 17 00:00:00 2001 From: evanweaver Date: Sat, 15 Dec 2007 04:52:01 +0000 Subject: backport revision 5418 to 1-1-2 git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-1@898 19e92222-5c0b-0410-8929-a290d50e31e9 --- lib/mongrel/gems.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mongrel/gems.rb b/lib/mongrel/gems.rb index c1264bb..eb6d0d6 100644 --- a/lib/mongrel/gems.rb +++ b/lib/mongrel/gems.rb @@ -8,7 +8,7 @@ module Mongrel rescue LoadError, RuntimeError => e begin # ActiveSupport breaks 'require' by making it always return a true value - require 'rubygems' + Kernel.require 'rubygems' version ? gem(library, version) : gem(library) retry rescue Gem::LoadError, LoadError, RuntimeError -- cgit v1.2.3-24-ge0c7 From 134246ea8e78b45eedbb63ecb116cd4d0d959b7f Mon Sep 17 00:00:00 2001 From: evanweaver Date: Sat, 15 Dec 2007 05:43:19 +0000 Subject: update changelog for 1-1-2 git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-1@906 19e92222-5c0b-0410-8929-a290d50e31e9 --- CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index f4b7eb6..fcdf1ba 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,6 @@ +v1.1.2. Fix worker termination bug; fix JRuby 1.0.3 load order issue; fix require issue on systems without Rubygems. + v1.1.1. Fix mongrel_rails restart bug; fix bug with Rack status codes. v1.1. Pure Ruby URIClassifier. More modular architecture. JRuby support. Move C URIClassifier into mongrel_experimental project. -- cgit v1.2.3-24-ge0c7 From 6beff3f81a0bc69a70c4a75d3f52dcd58c019f66 Mon Sep 17 00:00:00 2001 From: evanweaver Date: Sat, 15 Dec 2007 05:43:30 +0000 Subject: update hardcoded version strings for 1-1-2 git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-1@907 19e92222-5c0b-0410-8929-a290d50e31e9 --- ext/http11/http11.c | 2 +- lib/mongrel/const.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/http11/http11.c b/ext/http11/http11.c index e59b248..b93a715 100644 --- a/ext/http11/http11.c +++ b/ext/http11/http11.c @@ -384,7 +384,7 @@ void Init_http11() DEF_GLOBAL(server_protocol, "SERVER_PROTOCOL"); DEF_GLOBAL(server_protocol_value, "HTTP/1.1"); DEF_GLOBAL(http_host, "HTTP_HOST"); - DEF_GLOBAL(mongrel_version, "Mongrel 1.1.1"); /* XXX Why is this defined here? */ + DEF_GLOBAL(mongrel_version, "Mongrel 1.1.2"); /* XXX Why is this defined here? */ DEF_GLOBAL(server_software, "SERVER_SOFTWARE"); DEF_GLOBAL(port_80, "80"); diff --git a/lib/mongrel/const.rb b/lib/mongrel/const.rb index 6c6742b..1ceb332 100644 --- a/lib/mongrel/const.rb +++ b/lib/mongrel/const.rb @@ -65,7 +65,7 @@ module Mongrel REQUEST_URI='REQUEST_URI'.freeze REQUEST_PATH='REQUEST_PATH'.freeze - MONGREL_VERSION="1.1.1".freeze + MONGREL_VERSION="1.1.2".freeze MONGREL_TMP_BASE="mongrel".freeze -- cgit v1.2.3-24-ge0c7 From 04cf081f433338a5b7773be08f02fba187518747 Mon Sep 17 00:00:00 2001 From: evanweaver Date: Sat, 15 Dec 2007 06:02:16 +0000 Subject: fix server versioning string in Java 1-1-2 git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-1@908 19e92222-5c0b-0410-8929-a290d50e31e9 --- ext/http11_java/org/jruby/mongrel/Http11.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/http11_java/org/jruby/mongrel/Http11.java b/ext/http11_java/org/jruby/mongrel/Http11.java index 4b2fd2e..c1e353b 100644 --- a/ext/http11_java/org/jruby/mongrel/Http11.java +++ b/ext/http11_java/org/jruby/mongrel/Http11.java @@ -215,7 +215,7 @@ public class Http11 extends RubyObject { req.setInstanceVariable("@http_body", RubyString.newString(runtime, new ByteList(hp.parser.buffer, at, length))); req.aset(runtime.newString("SERVER_PROTOCOL"),runtime.newString("HTTP/1.1")); - req.aset(runtime.newString("SERVER_SOFTWARE"),runtime.newString("Mongrel 1.0.1")); + req.aset(runtime.newString("SERVER_SOFTWARE"),runtime.newString("Mongrel 1.1.2")); } }; -- cgit v1.2.3-24-ge0c7 From 6161ec88f7cd5ac7957062103ad5be36771b989b Mon Sep 17 00:00:00 2001 From: evanweaver Date: Sat, 15 Dec 2007 06:31:31 +0000 Subject: java doesn't depend on cgi_multipart_eof_fix anymore git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-1@909 19e92222-5c0b-0410-8929-a290d50e31e9 --- Rakefile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index 7251c1c..a25c230 100644 --- a/Rakefile +++ b/Rakefile @@ -10,7 +10,7 @@ e = Echoe.new("mongrel") do |p| p.rdoc_pattern = ['README', 'LICENSE', 'CHANGELOG', 'COPYING', 'lib/**/*.rb', 'doc/**/*.rdoc'] p.ignore_pattern = /^(pkg|site|projects|doc|log)|CVS|\.log/ p.ruby_version = '>= 1.8.4' - p.dependencies = ['gem_plugin >=0.2.3', 'cgi_multipart_eof_fix >=2.4'] + p.dependencies = ['gem_plugin >=0.2.3'] (p.rdoc_template = `allison --path`.chomp) rescue nil p.need_tar_gz = false @@ -31,6 +31,7 @@ e = Echoe.new("mongrel") do |p| extensions.clear self.files += ['lib/http11.so'] self.platform = Gem::Platform::WIN32 + add_dependency('cgi_multipart_eof_fix', '>= 2.4') when /java/ extensions.clear self.files += ['lib/http11.jar'] @@ -38,6 +39,7 @@ e = Echoe.new("mongrel") do |p| else add_dependency('daemons', '>= 1.0.3') add_dependency('fastthread', '>= 1.0.1') + add_dependency('cgi_multipart_eof_fix', '>= 2.4') end end -- cgit v1.2.3-24-ge0c7 From b199cd0a7c40c1018343230e20f55f91dbc3c3e3 Mon Sep 17 00:00:00 2001 From: evanweaver Date: Sat, 15 Dec 2007 08:17:46 +0000 Subject: close 16319 in 1-1-2 git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-1@911 19e92222-5c0b-0410-8929-a290d50e31e9 --- lib/mongrel.rb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/mongrel.rb b/lib/mongrel.rb index 178762b..9451748 100644 --- a/lib/mongrel.rb +++ b/lib/mongrel.rb @@ -1,4 +1,5 @@ +# Standard libraries require 'socket' require 'tempfile' require 'yaml' @@ -7,13 +8,16 @@ require 'etc' require 'uri' require 'stringio' -require 'mongrel/gems' +# Compiled Mongrel extension +require 'http11' +# Gem conditional loader +require 'mongrel/gems' Mongrel::Gems.require 'cgi_multipart_eof_fix' Mongrel::Gems.require 'fastthread' require 'thread' -require 'http11' +# Ruby Mongrel require 'mongrel/cgi' require 'mongrel/handlers' require 'mongrel/command' -- cgit v1.2.3-24-ge0c7 From 5b69bdcf19fb25bdc21cc4ef86aa8a988b5718a0 Mon Sep 17 00:00:00 2001 From: evanweaver Date: Sat, 15 Dec 2007 08:19:19 +0000 Subject: rakefile fixes for cross-packaging and java testing in 1-1-2 git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-1@912 19e92222-5c0b-0410-8929-a290d50e31e9 --- Rakefile | 56 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/Rakefile b/Rakefile index a25c230..def399b 100644 --- a/Rakefile +++ b/Rakefile @@ -1,6 +1,6 @@ require 'rubygems' -gem 'echoe', '>=2.7' +gem 'echoe', '>=2.7.5' require 'echoe' e = Echoe.new("mongrel") do |p| @@ -10,30 +10,30 @@ e = Echoe.new("mongrel") do |p| p.rdoc_pattern = ['README', 'LICENSE', 'CHANGELOG', 'COPYING', 'lib/**/*.rb', 'doc/**/*.rdoc'] p.ignore_pattern = /^(pkg|site|projects|doc|log)|CVS|\.log/ p.ruby_version = '>= 1.8.4' - p.dependencies = ['gem_plugin >=0.2.3'] - (p.rdoc_template = `allison --path`.chomp) rescue nil - + p.dependencies = ['gem_plugin >=0.2.3'] + p.extension_pattern = nil + p.certificate_chain = ['~/p/configuration/gem_certificates/mongrel/mongrel-public_cert.pem', + '~/p/configuration/gem_certificates/evan_weaver-mongrel-public_cert.pem'] + p.need_tar_gz = false p.need_tgz = true - # case RUBY_PLATFORM - # when /mswin/ - # p.certificate_chain = ['~/gem_certificates/mongrel-public_cert.pem', - # '~/gem_certificates/luislavena-mongrel-public_cert.pem'] - # else - p.certificate_chain = ['~/p/configuration/gem_certificates/mongrel/mongrel-public_cert.pem', - '~/p/configuration/gem_certificates/evan_weaver-mongrel-public_cert.pem'] - # end + case RUBY_PLATFORM + when /mswin/ + # p.certificate_chain = ['~/gem_certificates/mongrel-public_cert.pem', + # '~/gem_certificates/luislavena-mongrel-public_cert.pem'] + when /java/ + else + p.extension_pattern = ["ext/**/extconf.rb"] + end p.eval = proc do case RUBY_PLATFORM when /mswin/ - extensions.clear self.files += ['lib/http11.so'] self.platform = Gem::Platform::WIN32 add_dependency('cgi_multipart_eof_fix', '>= 2.4') when /java/ - extensions.clear self.files += ['lib/http11.jar'] self.platform = 'jruby' else @@ -63,16 +63,7 @@ task :ragel do end end -#### XXX Hack around JRuby test/unit interaction problems - -desc "Run each test suite in isolation on JRuby" -task :test_java do - e.test_pattern.each do |f| - sh "/opt/local/jruby/bin/jruby -w -Ilib:ext:bin:test -e 'require \"#{f}\"'" rescue nil - end -end - -#### XXX Hack around RubyGems and Echoe for pre-compiled extensions. +#### Pre-compiled extensions for alternative platforms def move_extensions Dir["ext/**/*.#{Config::CONFIG['DLEXT']}"].each { |file| mv file, "lib/" } @@ -103,6 +94,14 @@ when /mswin/ task :compile => [filename] when /java/ + + # Avoid JRuby in-process launching problem + begin + require 'jruby' + JRuby.runtime.instance_config.run_ruby_in_process = false + rescue LoadError + end + filename = "lib/http11.jar" file filename do build_dir = "ext/http11_java/classes" @@ -138,8 +137,11 @@ task :package_all => [:package] do sub_project("mongrel_console", :package) sub_project("mongrel_cluster", :package) sub_project("mongrel_experimental", :package) - sub_project("mongrel_service", :package) if RUBY_PLATFORM =~ /mswin/ + sh("rake java package") unless RUBY_PLATFORM =~ /java/ + + # XXX Broken by RubyGems 0.9.5 + # sub_project("mongrel_service", :package) if RUBY_PLATFORM =~ /mswin/ # sh("rake mswin package") unless RUBY_PLATFORM =~ /mswin/ end @@ -200,9 +202,6 @@ namespace :site do FileList["**/*.gem"].each { |gem| mv gem, "pkg/gems" } FileList["**/*.tgz"].each {|tgz| mv tgz, "pkg/tars" } - # XXX Hack, because only Luis can package for Win32 right now - sh "cp ~/Downloads/mongrel-#{e.version}-mswin32.gem pkg/gems/" - sh "cp ~/Downloads/mongrel_service-0.3.3-mswin32.gem pkg/gems/" sh "rm -rf pkg/mongrel*" sh "gem generate_index -d pkg" sh "scp -r CHANGELOG pkg/* rubyforge.org:/var/www/gforge-projects/mongrel/releases/" @@ -215,6 +214,7 @@ namespace :site do task :web do # Requires the 'webgem' gem sh "cd site; webgen; webgen; curl 'http://feed43.com/mongrel.xml' > output/rss.xml; rsync -azv --no-perms --no-times output/* rubyforge.org:/var/www/gforge-projects/mongrel/" + puts "\nMake sure to re-run the site update 6 hours later if you updated the news. This delay is required for Feed43 to pick up the site changes." end desc "Upload the rdocs" -- cgit v1.2.3-24-ge0c7 From ce8100640a28a1ad53b058f05bd09f4bf03ac446 Mon Sep 17 00:00:00 2001 From: evanweaver Date: Sat, 15 Dec 2007 08:27:04 +0000 Subject: update site news git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-1@913 19e92222-5c0b-0410-8929-a290d50e31e9 --- site/src/news.include | 11 ++++++++++- site/src/news.page | 4 ++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/site/src/news.include b/site/src/news.include index 8e2873c..aa20fcd 100644 --- a/site/src/news.include +++ b/site/src/news.include @@ -1,8 +1,17 @@
+
Dec-15-2007
+
+
Mongrel 1.1.2, holiday edition
+ +

Mongrel 1.1.2 is out. It fixes a few bugs and adds JRuby 1.0.x compatibility.

+ Download + more

+
+
Nov-12-2007
Mongrel 1.1.1, never forget
- +

Mongrel 1.1.1 is out. It fixes the mongrel_rails restart bug.

Download more

diff --git a/site/src/news.page b/site/src/news.page index 545ccd4..712d584 100644 --- a/site/src/news.page +++ b/site/src/news.page @@ -7,6 +7,10 @@ ordering: 2 h1. Latest News +h2. Dec 15: Mongrel 1.1.2, holiday edition. + +Mongrel 1.1.2 is out. It fixes a few bugs and adds JRuby 1.0.x compatibility. + h2. Nov 12: Mongrel 1.1.1, never forget. Mongrel 1.1.1 is out. It fixes the mongrel_rails restart bug that annoyed everybody, as well as a couple of other things. -- cgit v1.2.3-24-ge0c7 From e807d9ac385740c671b0936a3270f4b60a8df26e Mon Sep 17 00:00:00 2001 From: wayneeseguin Date: Sat, 29 Dec 2007 02:55:04 +0000 Subject: Applied Zed's patch to fix a vulnerability recently introduced whereby url's like "/.%252e/.%252e/.%252e/.%252e/.%252e/.%252e/.%252e/etc/passwd" could serve the password file. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-1@927 19e92222-5c0b-0410-8929-a290d50e31e9 --- lib/mongrel/handlers.rb | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/lib/mongrel/handlers.rb b/lib/mongrel/handlers.rb index ee76179..9b9798e 100644 --- a/lib/mongrel/handlers.rb +++ b/lib/mongrel/handlers.rb @@ -132,8 +132,12 @@ module Mongrel # Add the drive letter or root path req_path = File.join(@path, req_path) if @path req_path = File.expand_path req_path - - if File.exist? req_path + + # do not remove the check for @path at the beginning, it's what prevents + # the serving of arbitrary files (and good programmer Rule #1 Says: If + # you don't understand something, it's not because I'm stupid, it's + # because you are). + if req_path.index(@path) == 0 and File.exist? req_path # It exists and it's in the right location if File.directory? req_path # The request is for a directory @@ -153,7 +157,7 @@ module Mongrel return req_path end else - # does not exist or isn't in the right spot + # does not exist or isn't in the right spot or isn't valid because not start with @path return nil end end -- cgit v1.2.3-24-ge0c7 From 1d3f272f4d70753ac78b1cd52018c59231771f02 Mon Sep 17 00:00:00 2001 From: luislavena Date: Sat, 29 Dec 2007 06:01:22 +0000 Subject: * ext/http11/http11.c: bumped version to 1.1.3. * Rakefile: workaround and ugly hack to get PURE_RUBY version of gem built. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-1@933 19e92222-5c0b-0410-8929-a290d50e31e9 --- CHANGELOG | 2 ++ Rakefile | 40 +++++++++++++++++++++++----------------- ext/http11/http11.c | 2 +- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index fcdf1ba..a578579 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,6 @@ +v1.1.3. Fix security flaw of DirHandler; reported on mailing list. + v1.1.2. Fix worker termination bug; fix JRuby 1.0.3 load order issue; fix require issue on systems without Rubygems. v1.1.1. Fix mongrel_rails restart bug; fix bug with Rack status codes. diff --git a/Rakefile b/Rakefile index def399b..9614194 100644 --- a/Rakefile +++ b/Rakefile @@ -2,6 +2,7 @@ require 'rubygems' gem 'echoe', '>=2.7.5' require 'echoe' +FORCE_PURE = ENV['FORCE_PURE'] || false e = Echoe.new("mongrel") do |p| p.summary = "A small fast HTTP library and server that runs Rails, Camping, Nitro and Iowa apps." @@ -9,7 +10,7 @@ e = Echoe.new("mongrel") do |p| p.clean_pattern = ['ext/http11/*.{bundle,so,o,obj,pdb,lib,def,exp}', 'lib/*.{bundle,so,o,obj,pdb,lib,def,exp}', 'ext/http11/Makefile', 'pkg', 'lib/*.bundle', '*.gem', 'site/output', '.config', 'lib/http11.jar', 'ext/http11_java/classes', 'coverage'] p.rdoc_pattern = ['README', 'LICENSE', 'CHANGELOG', 'COPYING', 'lib/**/*.rb', 'doc/**/*.rdoc'] p.ignore_pattern = /^(pkg|site|projects|doc|log)|CVS|\.log/ - p.ruby_version = '>= 1.8.4' + p.ruby_version = '>=1.8.4' p.dependencies = ['gem_plugin >=0.2.3'] p.extension_pattern = nil p.certificate_chain = ['~/p/configuration/gem_certificates/mongrel/mongrel-public_cert.pem', @@ -20,29 +21,34 @@ e = Echoe.new("mongrel") do |p| case RUBY_PLATFORM when /mswin/ - # p.certificate_chain = ['~/gem_certificates/mongrel-public_cert.pem', - # '~/gem_certificates/luislavena-mongrel-public_cert.pem'] + p.certificate_chain = [ + '~/projects/gem_certificates/mongrel-public_cert.pem', + '~/projects/gem_certificates/luislavena-mongrel-public_cert.pem' + ] when /java/ else p.extension_pattern = ["ext/**/extconf.rb"] end - p.eval = proc do - case RUBY_PLATFORM - when /mswin/ - self.files += ['lib/http11.so'] - self.platform = Gem::Platform::WIN32 - add_dependency('cgi_multipart_eof_fix', '>= 2.4') - when /java/ - self.files += ['lib/http11.jar'] - self.platform = 'jruby' - else - add_dependency('daemons', '>= 1.0.3') - add_dependency('fastthread', '>= 1.0.1') - add_dependency('cgi_multipart_eof_fix', '>= 2.4') + unless FORCE_PURE + p.eval = proc do + case RUBY_PLATFORM + when /mswin/ + self.files += ['lib/http11.so'] + self.platform = Gem::Platform::CURRENT + add_dependency('cgi_multipart_eof_fix', '>= 2.4') + when /java/ + self.files += ['lib/http11.jar'] + self.platform = 'jruby' + else + add_dependency('daemons', '>= 1.0.3') + add_dependency('fastthread', '>= 1.0.1') + add_dependency('cgi_multipart_eof_fix', '>= 2.4') + end end + else + p.extension_pattern = ["ext/**/extconf.rb"] end - end #### Ragel builder diff --git a/ext/http11/http11.c b/ext/http11/http11.c index b93a715..6603745 100644 --- a/ext/http11/http11.c +++ b/ext/http11/http11.c @@ -384,7 +384,7 @@ void Init_http11() DEF_GLOBAL(server_protocol, "SERVER_PROTOCOL"); DEF_GLOBAL(server_protocol_value, "HTTP/1.1"); DEF_GLOBAL(http_host, "HTTP_HOST"); - DEF_GLOBAL(mongrel_version, "Mongrel 1.1.2"); /* XXX Why is this defined here? */ + DEF_GLOBAL(mongrel_version, "Mongrel 1.1.3"); /* XXX Why is this defined here? */ DEF_GLOBAL(server_software, "SERVER_SOFTWARE"); DEF_GLOBAL(port_80, "80"); -- cgit v1.2.3-24-ge0c7 From 0030c44e6483bdd6fc44656b03f1aa91ba0bed89 Mon Sep 17 00:00:00 2001 From: evanweaver Date: Sat, 29 Dec 2007 08:37:19 +0000 Subject: add git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-1@937 19e92222-5c0b-0410-8929-a290d50e31e9 --- site/src/news.include | 10 ++++++++++ site/src/news.page | 4 ++++ 2 files changed, 14 insertions(+) diff --git a/site/src/news.include b/site/src/news.include index aa20fcd..646ad6c 100644 --- a/site/src/news.include +++ b/site/src/news.include @@ -1,4 +1,14 @@
+ +
Dec-29-2007
+
+
Mongrel 1.1.3 and 1.0.5, security update
+ +

Mongrel 1.1.3 and 1.0.5 are out. They fix a security flaw in the DirHandler as reported on the list. You should upgrade when you get the chance.

+ Download + more

+
+
Dec-15-2007
Mongrel 1.1.2, holiday edition
diff --git a/site/src/news.page b/site/src/news.page index 712d584..322aab0 100644 --- a/site/src/news.page +++ b/site/src/news.page @@ -7,6 +7,10 @@ ordering: 2 h1. Latest News +h2. Dec 29: Mongrel 1.1.3 and 1.0.5, security update. For serious. + +Mongrel 1.1.3 and 1.0.5 are out. They fix a security flaw in the DirHandler as reported on the list. The flaw may or may not be already mitigated by your proxy configuration, but you should upgrade when you get the chance (or downgrade to 1.0.3). + h2. Dec 15: Mongrel 1.1.2, holiday edition. Mongrel 1.1.2 is out. It fixes a few bugs and adds JRuby 1.0.x compatibility. -- cgit v1.2.3-24-ge0c7 From 8c43849b25cf70af66ac1fe4a206690b61fb1a6b Mon Sep 17 00:00:00 2001 From: evanweaver Date: Sat, 29 Dec 2007 08:37:41 +0000 Subject: that was supposed to be "add a news item about the 1.0.5 and 1.1.3 releases" git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-1@938 19e92222-5c0b-0410-8929-a290d50e31e9 --- site/src/news.include | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/src/news.include b/site/src/news.include index 646ad6c..1ba0e99 100644 --- a/site/src/news.include +++ b/site/src/news.include @@ -7,7 +7,7 @@

Mongrel 1.1.3 and 1.0.5 are out. They fix a security flaw in the DirHandler as reported on the list. You should upgrade when you get the chance.

Download more

-
+
Dec-15-2007
-- cgit v1.2.3-24-ge0c7 From f4fc291fc70792a27241789d4d816727ed266438 Mon Sep 17 00:00:00 2001 From: evanweaver Date: Mon, 31 Dec 2007 17:34:46 +0000 Subject: repair Rakefile git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-1@941 19e92222-5c0b-0410-8929-a290d50e31e9 --- Rakefile | 53 +++++++++++++++++++++++++---------------------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/Rakefile b/Rakefile index 9614194..f47d7a2 100644 --- a/Rakefile +++ b/Rakefile @@ -2,53 +2,50 @@ require 'rubygems' gem 'echoe', '>=2.7.5' require 'echoe' -FORCE_PURE = ENV['FORCE_PURE'] || false e = Echoe.new("mongrel") do |p| p.summary = "A small fast HTTP library and server that runs Rails, Camping, Nitro and Iowa apps." p.author ="Zed A. Shaw" p.clean_pattern = ['ext/http11/*.{bundle,so,o,obj,pdb,lib,def,exp}', 'lib/*.{bundle,so,o,obj,pdb,lib,def,exp}', 'ext/http11/Makefile', 'pkg', 'lib/*.bundle', '*.gem', 'site/output', '.config', 'lib/http11.jar', 'ext/http11_java/classes', 'coverage'] + p.url = "http://mongrel.rubyforge.org" p.rdoc_pattern = ['README', 'LICENSE', 'CHANGELOG', 'COPYING', 'lib/**/*.rb', 'doc/**/*.rdoc'] p.ignore_pattern = /^(pkg|site|projects|doc|log)|CVS|\.log/ p.ruby_version = '>=1.8.4' p.dependencies = ['gem_plugin >=0.2.3'] p.extension_pattern = nil - p.certificate_chain = ['~/p/configuration/gem_certificates/mongrel/mongrel-public_cert.pem', - '~/p/configuration/gem_certificates/evan_weaver-mongrel-public_cert.pem'] + + p.certificate_chain = case ENV['USER'] + when 'eweaver' + ['~/p/configuration/gem_certificates/mongrel/mongrel-public_cert.pem', + '~/p/configuration/gem_certificates/evan_weaver-mongrel-public_cert.pem'] + when 'luislavena' + ['~/gem_certificates/mongrel-public_cert.pem', + '~/gem_certificates/luislavena-mongrel-public_cert.pem'] + end p.need_tar_gz = false p.need_tgz = true - case RUBY_PLATFORM + if RUBY_PLATFORM !~ /mswin|java/ + p.extension_pattern = ["ext/**/extconf.rb"] + end + + p.eval = proc do + case RUBY_PLATFORM when /mswin/ - p.certificate_chain = [ - '~/projects/gem_certificates/mongrel-public_cert.pem', - '~/projects/gem_certificates/luislavena-mongrel-public_cert.pem' - ] + self.files += ['lib/http11.so'] + self.platform = Gem::Platform::WIN32 + add_dependency('cgi_multipart_eof_fix', '>= 2.4') when /java/ + self.files += ['lib/http11.jar'] + self.platform = 'jruby' # XXX Is this right? else - p.extension_pattern = ["ext/**/extconf.rb"] - end - - unless FORCE_PURE - p.eval = proc do - case RUBY_PLATFORM - when /mswin/ - self.files += ['lib/http11.so'] - self.platform = Gem::Platform::CURRENT - add_dependency('cgi_multipart_eof_fix', '>= 2.4') - when /java/ - self.files += ['lib/http11.jar'] - self.platform = 'jruby' - else - add_dependency('daemons', '>= 1.0.3') - add_dependency('fastthread', '>= 1.0.1') - add_dependency('cgi_multipart_eof_fix', '>= 2.4') - end + add_dependency('daemons', '>= 1.0.3') + add_dependency('fastthread', '>= 1.0.1') + add_dependency('cgi_multipart_eof_fix', '>= 2.4') end - else - p.extension_pattern = ["ext/**/extconf.rb"] end + end #### Ragel builder -- cgit v1.2.3-24-ge0c7 From 29feea86555bc75f126779e5278909d564fc473f Mon Sep 17 00:00:00 2001 From: evanweaver Date: Wed, 2 Jan 2008 04:35:02 +0000 Subject: updated version number to 1.1.3 git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-1@943 19e92222-5c0b-0410-8929-a290d50e31e9 --- ext/http11_java/org/jruby/mongrel/Http11.java | 2 +- lib/mongrel/const.rb | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ext/http11_java/org/jruby/mongrel/Http11.java b/ext/http11_java/org/jruby/mongrel/Http11.java index c1e353b..68cb665 100644 --- a/ext/http11_java/org/jruby/mongrel/Http11.java +++ b/ext/http11_java/org/jruby/mongrel/Http11.java @@ -215,7 +215,7 @@ public class Http11 extends RubyObject { req.setInstanceVariable("@http_body", RubyString.newString(runtime, new ByteList(hp.parser.buffer, at, length))); req.aset(runtime.newString("SERVER_PROTOCOL"),runtime.newString("HTTP/1.1")); - req.aset(runtime.newString("SERVER_SOFTWARE"),runtime.newString("Mongrel 1.1.2")); + req.aset(runtime.newString("SERVER_SOFTWARE"),runtime.newString("Mongrel 1.1.3")); } }; diff --git a/lib/mongrel/const.rb b/lib/mongrel/const.rb index 1ceb332..8a6982a 100644 --- a/lib/mongrel/const.rb +++ b/lib/mongrel/const.rb @@ -65,7 +65,7 @@ module Mongrel REQUEST_URI='REQUEST_URI'.freeze REQUEST_PATH='REQUEST_PATH'.freeze - MONGREL_VERSION="1.1.2".freeze + MONGREL_VERSION="1.1.3".freeze MONGREL_TMP_BASE="mongrel".freeze -- cgit v1.2.3-24-ge0c7 From 5d7220eb42d7aadfdb0e4c6f712e386fecec97c3 Mon Sep 17 00:00:00 2001 From: evanweaver Date: Tue, 12 Feb 2008 09:27:22 +0000 Subject: Remove site from stable branch now that the data has been ported. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-1@957 19e92222-5c0b-0410-8929-a290d50e31e9 --- site/config.yml | 12 - site/src/adoption.page | 54 -- site/src/attributions.page | 66 -- site/src/books.page | 19 - site/src/certified.page | 63 -- site/src/default.css | 428 ------------- site/src/default.template | 102 --- site/src/docs/SimpleLighttpdMongrelSetup.jpg | Bin 13747 -> 0 bytes site/src/docs/apache.page | 556 ---------------- site/src/docs/choosing_deployment.page | 178 ------ site/src/docs/contrib.page | 199 ------ site/src/docs/debian-sarge.page | 289 --------- site/src/docs/distributed_worker.page | 105 ---- site/src/docs/frameworks.page | 34 - site/src/docs/gem_plugin.page | 335 ---------- site/src/docs/how_many_mongrels.page | 90 --- site/src/docs/howto.page | 490 --------------- site/src/docs/index.page | 104 --- site/src/docs/lighttpd.page | 278 -------- site/src/docs/litespeed.page | 84 --- site/src/docs/mongrel_cluster.page | 138 ---- site/src/docs/osx.page | 124 ---- site/src/docs/pen_balance.page | 57 -- site/src/docs/pound.page | 148 ----- site/src/docs/security.page | 94 --- site/src/docs/started.page | 83 --- site/src/docs/upload_progress.page | 136 ---- site/src/docs/upload_progress_form.rhtml | 53 -- site/src/docs/upload_progress_javascript.js | 113 ---- site/src/docs/upload_progress_rails.rb | 14 - site/src/docs/win32.page | 131 ---- site/src/dogs.page | 40 -- site/src/faq.page | 411 ------------ site/src/images/250878012_55b96c985c_o.jpg | Bin 29423 -> 0 bytes site/src/images/3930442_6cbcae1335.jpg | Bin 65804 -> 0 bytes site/src/images/3colls_p1.jpg | Bin 1947 -> 0 bytes site/src/images/3colls_p2.jpg | Bin 3137 -> 0 bytes site/src/images/3colls_p3.jpg | Bin 2825 -> 0 bytes site/src/images/6267035_eeec5b0f16.jpg | Bin 60872 -> 0 bytes site/src/images/63325054_12298eb2a3.jpg | Bin 153710 -> 0 bytes site/src/images/79968762_e063fc1317.jpg | Bin 210233 -> 0 bytes site/src/images/85895062_beb6249744.jpg | Bin 184501 -> 0 bytes site/src/images/86461088_9a747a6a5e.jpg | Bin 136781 -> 0 bytes site/src/images/87022458_3981942f0c.jpg | Bin 137677 -> 0 bytes site/src/images/90208926_7d64788f30.jpg | Bin 17455 -> 0 bytes site/src/images/92211824_d01a4ce59c.jpg | Bin 159314 -> 0 bytes site/src/images/98452447_1be256a96c.jpg | Bin 110181 -> 0 bytes site/src/images/bug_votes.png | Bin 2368 -> 0 bytes site/src/images/config_tool_snap.png | Bin 38023 -> 0 bytes site/src/images/index.page | 7 - site/src/images/iron_mongrel.jpg | Bin 25054 -> 0 bytes site/src/images/li1a-c1.gif | Bin 131 -> 0 bytes site/src/images/li1a.gif | Bin 130 -> 0 bytes site/src/images/li1b-c1.gif | Bin 122 -> 0 bytes site/src/images/li1b.gif | Bin 122 -> 0 bytes site/src/images/li2-c1.gif | Bin 59 -> 0 bytes site/src/images/li2.gif | Bin 59 -> 0 bytes site/src/images/li3-c1.gif | Bin 59 -> 0 bytes site/src/images/li3.gif | Bin 59 -> 0 bytes site/src/images/li4.gif | Bin 65 -> 0 bytes site/src/images/mongrel_not_scgi.jpg | Bin 19908 -> 0 bytes site/src/images/rss.png | Bin 3341 -> 0 bytes site/src/images/side_p1.gif | Bin 6968 -> 0 bytes site/src/images/side_p2.gif | Bin 7097 -> 0 bytes site/src/images/side_p3.gif | Bin 9366 -> 0 bytes site/src/images/tl_contact-c1-on.gif | Bin 79 -> 0 bytes site/src/images/tl_contact-c1.gif | Bin 79 -> 0 bytes site/src/images/tl_contact-on.gif | Bin 79 -> 0 bytes site/src/images/tl_contact.gif | Bin 79 -> 0 bytes site/src/images/tl_home-c1-on.gif | Bin 77 -> 0 bytes site/src/images/tl_home-c1.gif | Bin 77 -> 0 bytes site/src/images/tl_home-on.gif | Bin 77 -> 0 bytes site/src/images/tl_home.gif | Bin 77 -> 0 bytes site/src/images/tl_sitemap-c1-on.gif | Bin 79 -> 0 bytes site/src/images/tl_sitemap-c1.gif | Bin 79 -> 0 bytes site/src/images/tl_sitemap-on.gif | Bin 79 -> 0 bytes site/src/images/tl_sitemap.gif | Bin 79 -> 0 bytes site/src/images/tn_bg1.gif | Bin 56 -> 0 bytes site/src/images/tn_bg2.gif | Bin 56 -> 0 bytes site/src/images/visual.jpg | Bin 24008 -> 0 bytes site/src/images/visual_dog.jpg | Bin 114202 -> 0 bytes site/src/index.page | 62 -- site/src/license.page | 73 --- site/src/news.include | 112 ---- site/src/news.page | 907 --------------------------- site/src/not_mongrel.page | 97 --- site/src/plugins.page | 22 - site/src/security.page | 75 --- site/src/sitemap.page | 10 - 89 files changed, 6393 deletions(-) delete mode 100644 site/config.yml delete mode 100644 site/src/adoption.page delete mode 100644 site/src/attributions.page delete mode 100644 site/src/books.page delete mode 100644 site/src/certified.page delete mode 100644 site/src/default.css delete mode 100644 site/src/default.template delete mode 100644 site/src/docs/SimpleLighttpdMongrelSetup.jpg delete mode 100644 site/src/docs/apache.page delete mode 100644 site/src/docs/choosing_deployment.page delete mode 100644 site/src/docs/contrib.page delete mode 100644 site/src/docs/debian-sarge.page delete mode 100644 site/src/docs/distributed_worker.page delete mode 100644 site/src/docs/frameworks.page delete mode 100644 site/src/docs/gem_plugin.page delete mode 100644 site/src/docs/how_many_mongrels.page delete mode 100644 site/src/docs/howto.page delete mode 100644 site/src/docs/index.page delete mode 100644 site/src/docs/lighttpd.page delete mode 100644 site/src/docs/litespeed.page delete mode 100644 site/src/docs/mongrel_cluster.page delete mode 100644 site/src/docs/osx.page delete mode 100644 site/src/docs/pen_balance.page delete mode 100644 site/src/docs/pound.page delete mode 100644 site/src/docs/security.page delete mode 100644 site/src/docs/started.page delete mode 100644 site/src/docs/upload_progress.page delete mode 100644 site/src/docs/upload_progress_form.rhtml delete mode 100644 site/src/docs/upload_progress_javascript.js delete mode 100644 site/src/docs/upload_progress_rails.rb delete mode 100644 site/src/docs/win32.page delete mode 100644 site/src/dogs.page delete mode 100644 site/src/faq.page delete mode 100644 site/src/images/250878012_55b96c985c_o.jpg delete mode 100644 site/src/images/3930442_6cbcae1335.jpg delete mode 100644 site/src/images/3colls_p1.jpg delete mode 100644 site/src/images/3colls_p2.jpg delete mode 100644 site/src/images/3colls_p3.jpg delete mode 100644 site/src/images/6267035_eeec5b0f16.jpg delete mode 100644 site/src/images/63325054_12298eb2a3.jpg delete mode 100644 site/src/images/79968762_e063fc1317.jpg delete mode 100644 site/src/images/85895062_beb6249744.jpg delete mode 100644 site/src/images/86461088_9a747a6a5e.jpg delete mode 100644 site/src/images/87022458_3981942f0c.jpg delete mode 100644 site/src/images/90208926_7d64788f30.jpg delete mode 100644 site/src/images/92211824_d01a4ce59c.jpg delete mode 100644 site/src/images/98452447_1be256a96c.jpg delete mode 100644 site/src/images/bug_votes.png delete mode 100644 site/src/images/config_tool_snap.png delete mode 100644 site/src/images/index.page delete mode 100644 site/src/images/iron_mongrel.jpg delete mode 100644 site/src/images/li1a-c1.gif delete mode 100644 site/src/images/li1a.gif delete mode 100644 site/src/images/li1b-c1.gif delete mode 100644 site/src/images/li1b.gif delete mode 100644 site/src/images/li2-c1.gif delete mode 100644 site/src/images/li2.gif delete mode 100644 site/src/images/li3-c1.gif delete mode 100644 site/src/images/li3.gif delete mode 100644 site/src/images/li4.gif delete mode 100644 site/src/images/mongrel_not_scgi.jpg delete mode 100644 site/src/images/rss.png delete mode 100644 site/src/images/side_p1.gif delete mode 100644 site/src/images/side_p2.gif delete mode 100644 site/src/images/side_p3.gif delete mode 100644 site/src/images/tl_contact-c1-on.gif delete mode 100644 site/src/images/tl_contact-c1.gif delete mode 100644 site/src/images/tl_contact-on.gif delete mode 100644 site/src/images/tl_contact.gif delete mode 100644 site/src/images/tl_home-c1-on.gif delete mode 100644 site/src/images/tl_home-c1.gif delete mode 100644 site/src/images/tl_home-on.gif delete mode 100644 site/src/images/tl_home.gif delete mode 100644 site/src/images/tl_sitemap-c1-on.gif delete mode 100644 site/src/images/tl_sitemap-c1.gif delete mode 100644 site/src/images/tl_sitemap-on.gif delete mode 100644 site/src/images/tl_sitemap.gif delete mode 100644 site/src/images/tn_bg1.gif delete mode 100644 site/src/images/tn_bg2.gif delete mode 100644 site/src/images/visual.jpg delete mode 100644 site/src/images/visual_dog.jpg delete mode 100644 site/src/index.page delete mode 100644 site/src/license.page delete mode 100644 site/src/news.include delete mode 100644 site/src/news.page delete mode 100644 site/src/not_mongrel.page delete mode 100644 site/src/plugins.page delete mode 100644 site/src/security.page delete mode 100644 site/src/sitemap.page diff --git a/site/config.yml b/site/config.yml deleted file mode 100644 index 54093e3..0000000 --- a/site/config.yml +++ /dev/null @@ -1,12 +0,0 @@ -# Configuration file for webgen -# Used to set the parameters of the plugins -FileCopyHandler: - paths: - - "**/*.css" - - "**/*.jpg" - - "**/*.png" - - "**/*.gif" - - "**/*.js" - - "**/*.html" - - "**/*.rb" - diff --git a/site/src/adoption.page b/site/src/adoption.page deleted file mode 100644 index 3e0f9b3..0000000 --- a/site/src/adoption.page +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: Adoption -inMenu: true -directoryName: Adoption -ordering: 4 ---- - -h1. Adoption of Mongrel - -Many people have adopted Mongrel as their deployment or development server of choice, but we need some new success stories to post here. If you have a one, post it to the "mailing list":http://rubyforge.org/mailman/listinfo/mongrel-users. Your project doesn't have to be public, just tell us how Mongrel made your life easier and what you like about it. - -h2. Mac OS X - -Mongrel and its dependencies are bundled with Mac OS X 10.5. - -h2. OpenSUSE - -"OpenSUSE":http://www.opensuse.org/ has a "page dedicated to Ruby":http://en.opensuse.org/Ruby -that also includes information on Ruby in their build service, how to install -Ruby on Rails, and Mongrel rpms. - -Mongrel is also a part of the "SUSE Linux Enterprise 10 SDK":http://developer.novell.com/wiki/index.php/SLES_SDK -which I think was the first commercial distro. - -It's maintained by Marcus Rückert. - -h2. CHOW.com - -"CHOW.com":http://www.chow.com, a CNET Networks property, serves over 400,000 pageviews a day from a pack of 24 Mongrels. One of the Mongrel contributors, Evan Weaver, works there. - -h2. Matt Pelletier ("EastMedia Group, Inc.":http://www.eastmedia.com/) - -Matt uses Mongrel on nearly everything including the recent "VeriSign PIP Project":http://pip.verisignlabs.com/ project. - -h2. Josh Goebel - -His "Pastie":http://pastie.caboo.se/ uses Mongrel and it's a slick little paste site with a nice IRC integrated bot. - -h2. Benjamin Curtis - -I saw your email to the list about Mongrel documentation, including the Adoption page, and I thought I'd toss my info your way. I'm using Mongrel for both "tesly.com":http://www.tesly.com/ and "agilewebdevelopment.com":http://www.agilewebdevelopment.com/, both running on the same VPS being proxied from lighty. This has turned out to be a much more stable solution than lighty + fcgi. My VPS is running Debian, so I've created init scripts to get those Mongrels going at boot time, and it works like a charm. - -h2. "Jonathan Weiss":http://blog.innerewut.de - -"MeinProf.de":http://meinprof.de/ was the first site to deploy Mongrel with Apache 2.2 and mod_proxy_balancer. We evaluated Mongrel as an alternative to FastCGI and were impressed by the ease of use and simplicity of the setup. Since then Mongrel drives up to 250.000 requests per day on MeinProf.de without any problems. - -h1. Actually Adopting A Mongrel - -If you're thinking of getting dog, consider adopting a real Mongrel -instead. - -* Rescue a racing dog from "Greyhound Connection":http://www.greyhoundconnection.com/ -* Adopt a homeless buddy from "The Humane Society":http://www.hsus.org/ -* We judge people by how they treat beings weaker than themselves, and the "SPCA":http://www.aspca.org/site/PageServer are good people. diff --git a/site/src/attributions.page b/site/src/attributions.page deleted file mode 100644 index 6e7f7d8..0000000 --- a/site/src/attributions.page +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: Attributions -inMenu: true -directoryName: Attributions -ordering: 100 ---- -h1. The People Who Made It Possible - -There's quite a few people who either directly or indirectly helped to make Mongrel. If we missed anyone then just e-mail us and we'll put your name here. - -* Mongrel was started by "Zed A. Shaw":http://www.zedshaw.com/. -* Win32 support for services was done by Luis Lavena. -* Specialized Win32 gems were setup by Wilson Bilkovich. -* Why the lucky stiff implemented initial Camping support as well as improvements to Mongrel's file processing. -* Dan Kubb contributed conditional HTTP responses. -* MenTaL guY made Ruby threading not suck. -* Filipe Lautert handled various bugfixes. -* The JRuby team has been very supportive despite all the bugs we filed against them. -* Evan Weaver has been driving the 1.0.3 and 1.1 releases. - -Also with lots of testing from tons of people who are really appreciated. - -h1. Who To Contact - -The easiest way to contact the Mongrel team is to mail the "Mongrel List":http://rubyforge.org/mailman/listinfo/mongrel-users. If for some reason that's not appropriate, the best individuals to contact right now are probably "Filipe Lautert":https://rubyforge.org/users/filipe/, "Luis Lavena":http://blog.mmediasys.com/, or "Evan Weaver":http://blog.evanweaver.com. - -h1. Commercial Sponsorship - -Mongrel is a free open source web server and will always remain that way, but that doesn't mean that companies don't help to make it better. - -Mongrel received sponsorship from "EastMedia Group":http://www.eastmedia.com in partnership with "VeriSign":http://www.verisign.com/ to make Mongrel fast and stable enough for their "PIP":http://pip.verisignlabs.com/ which should be a great Single Sign-On application and is being released open source. - -Other companies benefiting from Ruby should take this as an example. We can think of quite a few things that need some serious commercial cash to get them in gear. If you're making cash off Ruby consider hiring a developer part-time, full-time, or posting a bounty for something you need as well as the community needs. There's no better time for enlightened self-interest than now. - -h2. Site Template - -The site's look and template is from "OWD":http://openwebdesign.org and is specifically Copyright © 2006 "Evgeni Dinev":http://www.evgenidinev.com/ under the "Creative Commons":http://creativecommons.org license. - - -h2. Photos - -The photos were found on "Flickr":http://flickr.com and are all licensed under the -"Creative Commons":http://creativecommons.org license. The following images are -attributed to the people based on their Flickr accounts: - -* "Bantay meets the world":http://www.flickr.com/photos/colloidfarl/39744440/in/set-625842/ -* "Caution: Beetlejam":http://www.flickr.com/photos/gyuvallos/90208926/ -* "Resting":http://flickr.com/photos/ashey/95638805/ -* "Allen Wrench Mess":http://www.flickr.com/photos/eklektikos/79968762/ -* "Tools":http://www.flickr.com/photos/book_slut/87022458/ -* "Big Wrench":http://flickr.com/photos/actionatadistance/63325054/in/set-1367823/ -* "Bolt":http://www-us.flickr.com/photos/lwr/6267035/in/set-775375/ -* "Book Collage":http://www.flickr.com/photos/muybridge/85895062/ -* "The Spinto Band at The Social":http://flickr.com/photo_zoom.gne?id=250878012 - -Thanks to those people who publish their photos with the "Creative Commons":http://creativecommons.org -license so others can see their photography (and look at their dogs). - -h2. Tools - -* "RubyForge":http://rubyforge.org/ for providing space and hooking it all up. -* "Webgen":http://webgen.rubyforge.org/ - -h2. Testing - -Lots of people from the "Mongrel List":http://rubyforge.org/mailman/listinfo/mongrel-users, the "Ruby on Rails mailing list":http://lists.rubyonrails.org/mailman/listinfo/rails and the "Ruby-lang mailing list":http://www.ruby-lang.org/en/20020104.html found bugs and reported them. diff --git a/site/src/books.page b/site/src/books.page deleted file mode 100644 index 5e433b2..0000000 --- a/site/src/books.page +++ /dev/null @@ -1,19 +0,0 @@ ---- -title: Books -inMenu: true -directoryName: Books ---- - -h1. Books About or Mentioning Mongrel - -Pretty much every book about Rails mentions Mongrel these days. If you want yours to be listed here, pop a message to the "mailing list":http://rubyforge.org/mailman/listinfo/mongrel-users. We are especially interested in books that aren't primarily about Rails. - -h2. Mongrel: Serving, Deploying, and Extending Your Ruby Applications - -This is of course the more or less official book, but don't take that to mean the others are bad. It focuses entirely on Mongrel and is written by the Mongrel founder (Zed Shaw) and Matt Pelletier. - -"You can buy it online as a PDF.":http://www.awprofessional.com/bookstore/product.asp?isbn=0321483502&rl=1 - -h2. Repensando a web com Rails - -This book was written by Fabio Akita with contributions from Zed and Piers Harding. It is a book in Brazilian Portuguese and seems to cover quite a bit of material. "You can read the blog for the site for more information.":http://www.balanceonrails.com.br/ diff --git a/site/src/certified.page b/site/src/certified.page deleted file mode 100644 index 46c3459..0000000 --- a/site/src/certified.page +++ /dev/null @@ -1,63 +0,0 @@ ---- -title: Certified -inMenu: true -directoryName: Certified ---- -h1. Get Mongrel Certified! - -I'm not one to be overpowered by the great ideas of other open source projects. -But, the second I smell cash to be had from hapless tools using my software I am THERE! Once I -read "the CakePHP Certification plans":http://www.cakefoundation.org/pages/certification -I thought, "Holy crap, I could make more money than Don King's ring finger doing that!" - -After much deliberation with absolutely nobody, I am proud to announce the -official *Mongrel Ultimate Deployment Certified Rails Aptitude Program(tm)(sm)(patent pending)*. - -The only certification you need to get that cushy job making developers beg you -for system administration services while you surf porn instead of doing your -real job. Nothing says "professionalism" more than having MUDCRAP-CE after your -name. - -Start now and even you could append up to *nine* (yes nine!) letters -after your name and get a guaranteed pay raise or that great job without know *anything* -other than how to tell other people how to pronounce your particular certification acronym. - -Prices are also very high, since your manager knows that the cost of a certification -program directly relates to its quality. The more you spend the more you show management -that you're a team player. No, a MUDCRAP Team Player! - - -h2. How To Get That Cert! - -MUDCRAP certification involves intensive training courses from me (Zed A. Shaw) the creator of Mongrel. -I am only available at specific conferences and will only teach a select chosen few -MUDCRAPers per conference. Each set of courses trains the prospective MUDCRAPer in: - -* Defending your job with claims of "security", "scalability", and "capability" -just like the Enterprise guys. -* Inventing performance numbers for fun and profit. Nothing lies better than complex well crafted -statistics. Learn to use them to compete with other people's fake statistics. -* Using the new OSX virtual desktop features to hide your chosen fetish porn while you work. -* Inventing your very own security policies to do even less work. Management has entrusted -you with managing the systems, and that means you get to set the policies everyone follows. Use -this power to make your life easier. -* Avoiding automating your system administration job so that you always have something to pretend -working on. -* Blaming *developers* for your mistakes. *EXTRA* This course now covers -using complex permissioning systems and shared directories to "protect" your servers from -the developers while actually only protecting your job. -* Unlearning everything you probably didn't know about Configuration Management and collaboration. -Nobody needs you to cooperate when you're the *king of the kingdom*. - -And this is just a few of the great lessons awaiting you in these wonderful classes. - -h2. Ordering Information - -E-mail zedshaw at zedshaw.com to reserve a seat. The next class is at RubyConf and will -only seat 10 people. That's how dedicated I am to the quality of my courses. You -will leave my course feeling confident, empowered, and capable enough to avoid learning anything -ever again for at least 10 years. - -Act now to become the first MUDCRAPer! Seats are filling fast! - - diff --git a/site/src/default.css b/site/src/default.css deleted file mode 100644 index cd0d4ca..0000000 --- a/site/src/default.css +++ /dev/null @@ -1,428 +0,0 @@ -html, body { - margin: 0; - padding: 0; - border: 0; - height: 100%; -} - -body { - background-color: #fff; - color: #444; - font-size: 84%; - font-family: "Trebuchet MS", Arial, sans-serif; - text-align: center; -} - -a { - color: #556379; -} - -a:hover { - color: #8496B3; - text-decoration: none; -} - -h1 { - font-size: 1.3em; - font-family: Arial; - color: #7B98F8; - margin: 0; - padding-bottom: 8px; -} - -h2 { - font-size: 0.9em; - font-family: Arial; - color: #62C916; - text-transform: uppercase; - margin: 0; - padding: 8px 0; -} - -h3 { - font-size: 0.9em; - font-family: Arial; - margin: 0; - padding-bottom: 8px; -} - -h4 { - font-size: 0.8em; - font-family: Arial; - color: #8CA1AA; - text-transform: uppercase; - margin: 0; - padding-bottom: 8px; -} - -p { - margin: 0; - padding-bottom: 8px; -} - -hr { - clear: both; - height: 1px; - border-top: solid 1px #AACCD5; -} - -img { - border: none; -} - -#wrapper { - margin: 0 auto; - width: 833px; - text-align: left; - height: 100%; -} - -#head { - background-color: #F0F8FA; - height: 90px; - color: #606d82; - border-bottom: 1px solid #fff; -} - -#head div { - float: left; - clear: right; - height: 65px; -} - -#logo { - width: 185px; -} - -#logo a { - display: block; - padding: 46px 0 0 14px; - font-size: 18px; - letter-spacing: 0; - text-transform: uppercase; - text-decoration: none; -} - -#slogan { - width: 474px; - border-left: 1px solid #A2ADB9; -} - -#slogan span { - display: block; - padding: 28px 0 0 14px; - font-size: 38px; - letter-spacing: -2px; - color: #91b3bc; -} - -#toplinks { - width: 73px; -} - -#toplinks ul { - margin: 0; - padding: 0; - list-style: none; -} - -#toplinks li { - float: left; - display: inline; - margin-top: 56px; -} - -#toplinks a { - display: block; - width: 18px; - height: 9px; -} - -#toplinks span { - display: none; -} - -#tl_home { - background-image: url(images/tl_home.gif); - background-repeat: no-repeat; -} - -#tl_contact { - background-image: url(images/tl_contact.gif); - background-repeat: no-repeat; -} - -#tl_sitemap { - background-image: url(images/tl_sitemap.gif); - background-repeat: no-repeat; -} - -#tl_home a:hover { - background-image: url(images/tl_home-on.gif); - background-repeat: no-repeat; -} - -#tl_contact a:hover { - background-image: url(images/tl_contact-on.gif); - background-repeat: no-repeat; -} - -#tl_sitemap a:hover { - background-image: url(images/tl_sitemap-on.gif); - background-repeat: no-repeat; -} - -#body { - float: right; - margin-top: 3px; - width: 648px; - clear: both; -} - -#visual { - margin: 16px 0; - height: 166px; - background-image: url(images/visual.jpg); - background-repeat: no-repeat; -} - -#content { - float: left; - padding-right: 14px; - width: 456px; - border-right: 1px solid #AACCD5; -} - -#news { - margin-left: 480px; - width: 165px; -} - -#news dl { - padding: 0; - margin: 0; -} - -#news dt { - padding: 6px 10px 4px 10px; - margin: 0; - border-top: 1px solid #DEECF0; - background-image: url(images/li3.gif); - background-position: 0 11px; - background-repeat: no-repeat; - font-size: .7em; - color: #8CA1AA; -} - -#news dd { - padding: 0; - margin: 0; - font-size: .8em; -} - -#news h5 { - margin: 0; - padding-bottom: 2px; - font-size: 1.0em; - font-weight: normal; -} - -#threecells { - clear: both; -} - -#threecells div { - float: left; - font-size: .9em; - clear: right; -} - -#threecells a { - display: block; - width: 162px; - height: 48px; - margin-bottom: 10px; -} - -#threecells span { - display: none; -} - -#cell_1 { - width: 162px; - padding-right: 15px; -} - -#cell_1 a { - background-image: url(images/3colls_p1.jpg); -} - -#cell_2 { - width: 162px; - padding: 0 15px 0 15px; - border-left: 1px solid #AACCD5; - border-right: 1px solid #AACCD5; -} - -#cell_2 a { - background-image: url(images/3colls_p2.jpg); -} - -#cell_3 { - width: 162px; - padding-left: 15px; -} - -#cell_3 a { - background-image: url(images/3colls_p3.jpg); -} - -#side { - padding-bottom: 8px; - border-top: 3px solid #fff; - width: 165px; - background-color: #EAF4F6; - height: 100%; -} - -#menu { - padding: 0; - margin: 0; -} - -#menu a { - text-decoration: none; - display:block; -} - -#menu ul { - padding: 0; - margin: 0; - list-style: none; -} - -#menu li { - margin: 0; - padding: 0; - font-size: 11px; - font-family: Arial; -} - -#menu ul li a { - margin-top: 8px; - padding: 0 28px; - height: 21px; - line-height: 21px; - font-weight: bold; - text-transform: uppercase; - border-top: 1px solid #AACCD5; - border-bottom: 1px solid #AACCD5; - background-image: url(images/li1a.gif); - background-position: 13px 5px; - background-repeat: no-repeat; -} - -#menu ul li ul li a { - margin-top: 0; - height:19px; - line-height: 19px; - font-weight:normal; - text-transform: capitalize; - background-image: url(images/li2.gif); - background-color: #DEECF0 ; - background-position: 13px 5px; - background-repeat: no-repeat; - border-top: 1px solid #EEF5F7; - border-bottom: 1px none #EEF5F7; -} - -#menu ul li ul li ul li a { - background-color: #C2DCE3; - background-image: none; -} - -#menu li li li li a { - padding-left: 36px; -} - -#menu ul li ul li ul li ul li a { - background-color: #A1CEDB; - background-image: none; -} - -#ads { - padding: 0; - margin: 0; -} - -#ads dt { - padding: 0; - margin: 6px; - border-top: 1px solid #fff; - border-bottom: 1px solid #fff; -} - -#ads dd { - margin: 0; - padding: 4px 12px; - border-bottom: 1px solid #EEF5F7; - font-size: .8em; - border-bottom: 1px solid #AACCD5; - line-height: 1.2em; -} - -#foot { - clear: both; - padding: 1em; - background-color: #fff; - background-image: url(images/logo_small.gif); - background-repeat: no-repeat; - font-size: .8em; - line-height: 1.4em; - text-align: center; - position: relative; -} - -#top_nav { - display: none; - padding-left: 185px; - background-color: #DEECF0; - height: 20px; -} - -#top_nav ul { - margin: 0; - padding: 0; - list-style: none; - border-left: 1px solid #fff; - background-image: url(images/tn_bg1.gif); - background-position: right top; - background-repeat: no-repeat; - height: 20px; -} - -#top_nav li { - float: left; - margin: 0; - padding: 0; - border-top: 2px solid #f60; - border-right: 1px solid #fff; - background-color: #E5F1F3; -} - -#top_nav a { - display: block; - padding: 0 1.3em; - line-height: 18px; - font-family: Arial; - font-size: 11px; - font-weight: bold; - text-align: center; - text-decoration: none; - text-transform: uppercase; -} - -#top_nav a:hover { - background-color: #f60; - color: #fff; -} diff --git a/site/src/default.template b/site/src/default.template deleted file mode 100644 index 1abd577..0000000 --- a/site/src/default.template +++ /dev/null @@ -1,102 +0,0 @@ - - - - - Mongrel: {title: } - - - - - - -
- - -
-
- -
- {block: } -
- -
-

NEWS

- <%= open("src/news.include").read %> -
-
- -
-
-
- -
- - -
-

-
-

Downloads: Grab new gear.

-
- -

-
-

Documentation: RTFM.

-
- -
Bugs
-
-

Tracker: Found a bug? Well then report it already!

-
- -
-
-
-

Mailing list: Mongrel making you sad? Why not say something?

-
- -
-
-
-

Attributions: Who made it happen. Who to talk to.

-
- -
-
-
-

Other: Hit the project page for all sorts of other - goodies.

-
- -
-
- - -
- - diff --git a/site/src/docs/SimpleLighttpdMongrelSetup.jpg b/site/src/docs/SimpleLighttpdMongrelSetup.jpg deleted file mode 100644 index bdb2bb1..0000000 Binary files a/site/src/docs/SimpleLighttpdMongrelSetup.jpg and /dev/null differ diff --git a/site/src/docs/apache.page b/site/src/docs/apache.page deleted file mode 100644 index 28ebe3c..0000000 --- a/site/src/docs/apache.page +++ /dev/null @@ -1,556 +0,0 @@ ---- -title: Apache -inMenu: true -directoryName: Apache ---- - -h1. Apache Best Practice Deployment - -h3. By Charles Brian Quinn - -The preferred setup (for now) is to put Mongrel behind an Apache 2.2.x -server running mod_proxy_balancer. Apache is a proven web server, runs -half the Internet, and is a pain to configure. These instructions should -get you started, but refer to the Apache folks for anything more complex -or weird. - -When you're just starting out, don't bother with doing anything but -running just Mongrel. Mongrel is slower than Apache, but not so slow that -small installations will notice it. The worst thing you can do is -try to learn Apache configuration when you're also trying to learn Ruby on Rails -and Mongrel too. Start small, then *when you need*, build up to the big stuff. - -h2. A simple single mongrel configuration - -Start up a single mongrel instance on port 8000: - -

-  $ mongrel_rails start -d -p 8000 \
-   -e production -P /full/path/to/log/mongrel-1.pid
-
- -Now, we'll tell Apache to simply proxy all requests to the mongrel server -running on port 8000. Simply add the following to your httpd.conf or in -a vhost.conf file: - -

-  
-    ServerName myapp.com
-    ServerAlias www.myapp.com
-
-    ProxyPass / http://www.myapp.com:8000/
-    ProxyPassReverse / http://www.myapp.com:8000
-    ProxyPreserveHost on
-  
-
- -That's it, in a nutshell. Several things to note in this configuration: - -1) This configuration forwards all traffic to mongrel. This means mongrel -will serve images, javascript, files, and everything else. It's quite fast -at this, but Apache can do it better. - -Here are some basic proxypass rules you can add to tell the ProxyPass not -to forward on requests to certain documents/requests: - -

-ProxyPass /images ! 
-ProxyPass /stylesheets ! 
-#continue with other static files that should be served by apache
-
-Alias /images /path/to/public/images
-Alias /stylesheets /path/to/public/stylesheets 
-#continue with aliases for static content
-
- -For a more detailed set of rules for forwarding on all dynamic content to mongrel, -see the more detailed configuration below for more details. - -2) In this configuration, it is entirely possible that two users (web -requests) could hit your application at the exact same time, and one would -have to wait literally milliseconds until the first request is finished -before having a turn at the mongrel instance. Unless you've got some really -long HTTP processes, the nature of the HTTP protocol is pretty good at waiting -in line. Only you can determine ("through metrics":http://mongrel.rubyforge.org/docs/how_many_mongrels.html) how long and -how many users will come at your application at the exact same time. - -Sufficient to say, if you're ready to start scaling with multiple mongrel -instances, read on. - -h2. Using multiple mongrel instances with mod_proxy_balancer - -First, let's start up a few mongrel instances (linux/freesd): - -

-$ mongrel_rails start -d -p 8001 \
-   -e production -P log/mongrel-1.pid
-$ mongrel_rails start -d -p 8002 \
-   -e production -P log/mongrel-2.pid
-$ mongrel_rails start -d -p 8003 \
-   -e production -P log/mongrel-3.pid
-$ mongrel_rails start -d -p 8004 \
-   -e production -P log/mongrel-4.pid
-
- -You can also use "mongrel_cluster":http://mongrel.rubyforge.org/docs/mongrel_cluster.html by "Bradley Taylor":http://fluxura.com/ for -managing several mongrel instances with a configuration file (and sysv init -scripts for -nix-flavor servers). - -We're going to be requiring the use of mod_proxy_balancer, a "new feature":http://httpd.apache.org/docs/2.2/new_features_2_2.html in -Apache 2.1/2.2 and above to proxy requests to -our mongrel instances. This software based HTTP load balancer will distribute -requests evenly (applying a weighting and selection algorithm) to our mongrel -instance(s). It even comes with a swell load-balancing manager page for -monitoring incoming requests. For more information, see: -"Apache's mod_proxy_balancer Documentation":http://httpd.apache.org/docs/2.2/mod/mod_proxy_balancer.html. - -h2. Obtaining Apache 2(.1+) - -I won't go into too many details, as windows and the various linux -distributions all have several methods for obtaining apache2, but you will need -the use of the following modules: - - * mod_proxy, mod_proxy-html, and mod_proxy_balancer - * mod_rewrite - * mod_deflate - * mod_headers - * (optional) mod_cache and one of mod_memcache or mod_filecache - * (optional) mod_ssl - -If you're compiling from source, this configuration should do the trick: - -

-#./configure --enable-deflate --enable-proxy --enable-proxy-html \ 
---enable-proxy-balancer --enable-rewrite --enable-cache  \ 
---enable-mem-cache --enable-ssl --enable-headers
-
- -Note: If you're going to be serving only Mongrel instances (Mongrel -serving up Ruby on Rails or any other ActiveRecord containing framework), -some have noted better performance and stability using the MPM worker class -instead of the pre-fork. If you don't know what this means, it's safe to -ignore. - -Essentially, in the default pre-fork worker mode, Apache will spawn several -processes when it starts up (pre-forking) and will spawn more if more requests -come in that need to be handled. On a heavily trafficked, very dynamic (not -much cached content/assets) Rails site, if you are doing nothing but servicing -Rails, it doesn't make sense to spawn 20 apache processes, in front of 3 -Mongrel processes, as Mongrel will be queuing them up, anyways. - -h2. Configuring Apache2 - -A good practice is the separation of apache configuration files. Recommended -by several other good guides, we'll be storing information for our application -in several different files. Put these files somewhere that apache2 knows -about. Apache is quite good about scanning for all .conf files in certain -directories. - -h3. myapp.common - -Apache lets you include common configuration items into another configuration -so you can cut down on repetition. What we're going to do is make a file -that has all the common junk that every Mongrel application needs to -work at all, then we'll just include this in little .conf files for -any application we deploy. - -Notice that this file doesn't end in .conf since it's not a real configuration -file, but you can name it however you wish. - -Important Update: "typo fixed in IE deflate rules":http://rubyforge.org/pipermail/mongrel-users/2006-October/001868.html - -

-  ServerName myapp.com
-  DocumentRoot /var/www/myapp.com/current/public
-
-  
-    Options FollowSymLinks
-    AllowOverride None
-    Order allow,deny
-    Allow from all
-  
-
-  RewriteEngine On
-
-  # Uncomment for rewrite debugging
-  #RewriteLog logs/myapp_rewrite_log
-  #RewriteLogLevel 9 
-
-  # Check for maintenance file and redirect all requests
-  #  ( this is for use with Capistrano's disable_web task )
-  RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
-  RewriteCond %{SCRIPT_FILENAME} !maintenance.html
-  RewriteRule ^.*$ /system/maintenance.html [L]
-
-  # Rewrite index to check for static
-  RewriteRule ^/$ /index.html [QSA] 
-
-  # Rewrite to check for Rails cached page
-  RewriteRule ^([^.]+)$ $1.html [QSA]
-
-  # Redirect all non-static requests to cluster
-  RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
-  RewriteRule ^/(.*)$ balancer://mongrel_cluster%{REQUEST_URI} [P,QSA,L]
-
-  # Deflate
-  AddOutputFilterByType DEFLATE text/html text/plain text/css
-  # ... text/xml application/xml application/xhtml+xml text/javascript 
-  BrowserMatch ^Mozilla/4 gzip-only-text/html
-  BrowserMatch ^Mozilla/4.0[678] no-gzip
-  BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
-
-  # Uncomment for deflate debugging
-  #DeflateFilterNote Input input_info
-  #DeflateFilterNote Output output_info
-  #DeflateFilterNote Ratio ratio_info
-  #LogFormat '"%r" %{output_info}n/%{input_info}n (%{ratio_info}n%%)' deflate
-  #CustomLog logs/myapp_deflate_log deflate
-
- -h3. myapp.conf - -We then take the above commmon file and include it in our configuration file -for this application deployment. - -If you're using virtual hosting (a pretty good idea, even when you're the only -one on the server), your sample configuration can be this simple: - -

-  
-    Include /etc/httpd/conf.d/myapp.common
-
-    ErrorLog logs/myapp_errors_log
-    CustomLog logs/myapp_log combined
-  
-
- -h3. myapp.proxy_cluster.conf - -This is the meat of our configuration, and goes hand in hand with our mongrel -(or mongrel_cluster) configuration. This configuration tells the apache2 -mod_proxy_balancer to proxy requests to 3 mongrel instances running on ports -8000, 8001, and 8002. - -

-  
-    BalancerMember http://127.0.0.1:8000
-    BalancerMember http://127.0.0.1:8001
-    BalancerMember http://127.0.0.1:8002
-  
-
- -If you had an seperate application server, you could balance to it easily by -replacing the 127.0.0.1 with the ip or hostname of your application server, but -be sure to make them listen on an external interface (rather than 127.0.0.1). - -When you add an additional mongrel to your mongrel_cluster, you can simply add -an additional BalancerMember to this file, restart apache (or reload) and -you're all set. - -h3. (optional) myapp.proxy_frontend.conf - -This optional file will setup the balancer-manager -- a simple front-end for -viewing how your requests are being handled. This balancer in the -configuration below will only work from the localhost, so no one else (or -possibly you) can view it unless you alter the "Deny" and "Allow" lines. - -

-Listen 8080
-
-  
-    SetHandler balancer-manager
-    Deny from all
-    Allow from localhost
-  
-
-
- -h3. SSL Requirements - -In order for mongrel to know that this request has a forwarded protocol of -https, we'll need to add a special header (hence the addition of mod_header, -included in most apache2 builds). - -

-  Include /etc/httpd/conf.d/myapp.common
-
-  # This is required to convince Rails (via mod_proxy_balancer) that we're
-  # actually using HTTPS.
-  RequestHeader set X_FORWARDED_PROTO 'https'
-
- -You need this mostly so that redirects go back to https and so you can -spot when people are coming through SSL or not. - -h2. Automation, Automation, Automation - -There are several great tools that automate the setup of Apache for use with -mongrel and mongrel_cluster. The "RailsMachine gem":https://support.railsmachine.com/index.php?pg=kb.chapter&id=18 can -automate an entire setup of a Rails application. Also, "Slingshot Hosting":http://www.slingshothosting.com/ has -a sample set of "Capistrano recipes":http://www.slingshothosting.com/support/capistrano that automatically setup Apache2 and mongrel -through the @rake remote:setup@ task. Be sure to check out both for some ideas. - -h2. Running Multiple Rails Apps with Mongrel - -The newest version of Mongrel supports multiple Rails applications through -the use of the --prefix command. The Apache magic for proxying a -single application is here assuming your prefix is app1: - -

-ProxyPass /app1 http://127.0.0.1:3000/app1
-ProxyPassReverse /app1 http://127.0.0.1:3000/app1
-
- -You need to have the proxy pass the new directory name. - -Thanks to Joey Geiger and others of the mongrel list for these -instructions. - -h2. Success Stories - -Martins on the mongrel-list has submitted this simple apache configuration. It serves up static content with apache, and forwards dynamic content on to mongrel using ProxyPass. Thanks Martins: - -

-
-       ServerName myapp.tld
-       ServerAlias www.myapp.tld
-
-       DocumentRoot /var/www/sites/myapp/current/public
-
-       
-               Options FollowSymLinks
-               AllowOverride None
-               Order allow,deny
-               Allow from all
-       
-
-       RewriteEngine On
-
-       # Check for maintenance file. Let apache load it if it exists
-       RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
-       RewriteRule . /system/maintenance.html [L]
-
-       # Let apache serve static files
-       RewriteCond %{DOCUMENT_ROOT}%{REQUEST_URI} -f
-       RewriteRule (.*) $1 [L]
-
-       # Don't do forward proxying
-       ProxyRequests Off
-
-       # Enable reverse proxying
-       
-               Order deny,allow
-               Allow from all
-       
-
-       # Pass other requests to mongrel instance
-       ProxyPass / http://127.0.0.1:8200/
-       ProxyPassReverse / http://127.0.0.1:8200/
-
-
-
- -Phillip Hallstrom has submitted this apache configuration, which includes support for having static directories handled by Apache, php support, and hiding svn directories. - -

-
-
-  ServerName myserver.com
-  DocumentRoot /path/to/my/app/public
-
-  
-    Options FollowSymLinks
-    AllowOverride None
-    Order allow,deny
-    Allow from all
-  
-
-  
-    BalancerMember http://127.0.0.1:8805
-  
-
-  RewriteEngine On
-
-  RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} -d
-  RewriteRule ^(.+[^/])$ $1/ [R]
-
-  RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} \.php
-  RewriteRule ^(.*)$ $1 [QSA,L]
-
-  RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
-  RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME}/index.html -f
-  RewriteRule ^(.*)$ $1/index.html [QSA,L]
-
-  RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
-  RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME}/index.php -f
-  RewriteRule ^(.*)$ $1/index.php [QSA,L]
-
-  RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} -d
-  RewriteRule ^(.*)[^/]$ $1/ [QSA,L]
-
-  RewriteCond %{DOCUMENT_ROOT}/%{REQUEST_FILENAME} !-f
-  RewriteRule ^/(.*)$ balancer://mongrel_cluster%{REQUEST_URI} [P,QSA,L]
-
-  AddOutputFilterByType DEFLATE text/html
-  AddOutputFilterByType DEFLATE application/x-javascript
-  AddOutputFilterByType DEFLATE text/css
-  AddOutputFilterByType DEFLATE text/plain
-  AddOutputFilterByType DEFLATE text/xml
-  AddOutputFilterByType DEFLATE application/xml
-  AddOutputFilterByType DEFLATE application/xhtml+xml
-
-  BrowserMatch ^Mozilla/4 gzip-only-text/html
-  BrowserMatch ^Mozilla/4.0[678] no-gzip
-  BrowserMatch bMSIE !no-gzip !gzip-only-text/html
-
-  php_value include_path /path/to/my/app/php:/usr/local/lib/php:.
-  php_value auto_prepend_file /path/to/my/app/php/auto_prepend.php
-
-  # this not only blocks access to .svn directories, but makes it appear
-  # as though they aren't even there, not just that they are forbidden
-  
-    ErrorDocument 403 /404.html
-    Order allow,deny
-    Deny from all
-    Satisfy All
-  
-
-
-
- -Jens Kraemer reports this differing proxy setup that uses the P option in Rewrite rules so as not to use the ProxyPass directive: - -

-  # Don't do forward proxying
-   ProxyRequests Off
-
-   # Enable reverse proxying
-   
-     Order deny,allow
-     Allow from all
-   
-
-   RewriteEngine On
-
-   # Check for maintenance file. Let apache load it if it exists
-   RewriteCond %{DOCUMENT_ROOT}/system/maintenance.html -f
-   RewriteRule . /system/maintenance.html [L]
-
-   # Rewrite index to check for static
-   RewriteRule ^/$ /index.html [QSA]
-
-   # Let apache serve static files (send everything via mod_proxy that
-   # is *no* static file (!-f)
-   RewriteCond %{DOCUMENT_ROOT}%{REQUEST_FILENAME} !-f
-   RewriteRule .* http://127.0.0.1:8200%{REQUEST_URI} [L,P,QSA]
-
- -the P option to the last rule replaces the ProxyPass and -ProxyPassReverse directives. - - -h2. SVN Security - -If you use svn to issue checkouts instead of exports, you'll need to hide those pesky .svn directories. This works: - -

-# this not only blocks access to .svn directories, but makes it appear
-  # as though they aren't even there, not just that they are forbidden
-  
-    ErrorDocument 403 /404.html
-    Order allow,deny
-    Deny from all
-    Satisfy All
-  
-
-
-
- -h2. Sending Environment variables to mongrel through proxy - -Jon Reads reports successfully reading the REMOTE_USER variable: - -
-After many hours trying to solve the same problem I found this post: "Forcing a proxied host to generate REMOTE_USER":http://www.nabble.com/Forcing-a-proxied-host-to-generate-REMOTE_USER-tf1114364.html#a2914465 - -and can confirm that the following works for me when put in the Proxy directive on Apache 2: -
- -

-   RewriteEngine On
-   RewriteCond %{LA-U:REMOTE_USER} (.+)
-   RewriteRule . - [E=RU:%1]
-   RequestHeader add X-Forwarded-User %{RU}e
-
- -*Update:* - -Satya reports that this works better: - -

-RewriteEngine On
-RewriteCond %{IS_SUBREQ} ^false$
-RewriteCond %{LA-U:REMOTE_USER} (.+)
-RewriteRule . - [E=RU:%1]
-RequestHeader add Remote-User %{RU}e
-
- -His explanation: - -
-Note the first RewriteCond. The LA-U in the 2nd RewriteCond causes an -internal subrequest, which causes inf recursion inside apache. Apache -eventually catches it, but it does bog down the server (and crashed our -shib, but that's not your problem). I think the 1st RewriteCond fixes -it. -
- -Peer Allen reports that you can send any environment variable through to mongrel: - -
-Here is the Apache config I used to forward the GEOIP_COUNTRY_CODE from the -Maxmind mod_geoip module. It is basically the same as the REMOTE_USER -forwarding, but since the GEOIP variable is an environment variable in -Apache you have to access it differently in the RewriteCond with the "ENV" -prefix. See the mod_rewrite documentation for this: -
- -

-2. %\{ENV:variable}, where variable can be any environment variable, is
-also available. This is looked-up via internal Apache structures and (if not
-found there) via getenv() from the Apache server process. 
-
---"http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html#RewriteRule":http://httpd.apache.org/docs/2.0/mod/mod_rewrite.html#RewriteRule - -

-# Forward the GEOIP_COUNTRY_CODE
-RewriteCond %\{ENV:GEOIP_COUNTRY_CODE} (.+)
-RewriteRule . - [E=RU:%1]
-RequestHeader add X-Forwarded-GeoIP %{RU}e
-
- -h2. Caveats - -Jason Hoffman reports: - -
-Apache's mod_proxy_balancer module is a fully blocking module and with -the default httpd.conf you're going to max out in the 120-160 requests/ -second range on a decent box. You can tune up its proxying to about a -1000 req/sec. - -So yes the net result is that you can really only put a couple of -mongrels behind apache's proxy engine (about 2 "hello world" rails -mongrels). -
- -h2. References and Other Guides - -[1] "Time For A Grown-Up Server: Rails, Mongrel, Apache, Capistrano and You":http://blog.codahale.com/2006/06/19/time-for-a-grown-up-server-rails-mongrel-apache-capistrano-and-you/ - -[2] "Bradley Taylor's Fluxura":http://fluxura.com/ and "RailsMachine":http://www.railsmachine.com/ - -[3] "Slingshot Hosting Automated Capistrano Recipe":http://www.slingshothosting.com/support/capistrano - -Thanks to many users on the mongrel list for making it easy for me to compile all these tips and tricks as they come across the list. - diff --git a/site/src/docs/choosing_deployment.page b/site/src/docs/choosing_deployment.page deleted file mode 100644 index 7a91e25..0000000 --- a/site/src/docs/choosing_deployment.page +++ /dev/null @@ -1,178 +0,0 @@ ---- -title: Choosing Deployment -inMenu: false -directoryName: Choosing Deployment ---- - -h1. Choosing The Best Deployment - -A major motivation for writing Mongrel was to make it easy to deploy Ruby web applications -within existing infrastructures and organizations. Most of the companies I tried to -pitch "Ruby on Rails":http://www.rubyonrails.org/ to loved how fast and easy it was to develop, -but ran screaming when I talked about FastCGI. - -Mongrel fixes this by just being a plain HTTP server that is still very fast. It's easy to -deploy, cluster, manage, and scale with existing web application technologies. You can -put it behind hardware load balancers, load balancing web servers, proxy servers, or just -by itself. - -With this flexibility comes a bit of confusion though. Many people start off wondering how best to -deploy Mongrel and then get confused with all the different options available. This document -hopefully will help you pick the right deployment for your needs. They are listed in order -from smallest/simpler to largest/complex. - -h2. Deployment Considerations - -There are a few initial things you'll have to consider when picking a deployment: - -* Concurrency -- Rails is not thread safe, so if you have giant actions that take -minutes to complete then take that into consideration. -* Requests/Second -- Notice I didn't say "users"? Users is a useless measurement of -your performance requirements. You want to know how many *requests per second* you have to process. -* Content Size -- What's the size of the content you're serving. Mongrel is pretty decent -at static files, but it can't beat a good solid web server for pushing out big files. -* Dynamic vs. Static -- Mongrel can serve static content for small sites, and of course do -dynamic Ruby generated content, but you'll want to figure out what the mix is so you can scale it later. -* Available Resources -- You can't cram a truck into a breadbox. Make sure you have the right deployment -for your resources such as memory, disk, CPU, etc. - -h3. Scalability Means Expansion Not Speed - -I'm not sure where the term "scalability" changed from it's original meaning, but you should -throw out any notion of scalability meaning "high performance". Scalability is about resources -and how easy it is for you to expand those resources to meet new demand. This does not mean -how many resources you can buy now for *all* the demand you'll ever need. It means the ability -to start small now, and then *after* you're the next google you can expand. - -h3. Start Small - -Everyone immediately jumps to the end of this document and starts with the absolute most complex and -"scalable" deployment they can muster. What you really want to do is start with a very small and simple -setup, and then expand as needed. This mitigates the risk that you'll buy a bunch of stuff you really -don't need and keeps your initial pain and costs low. - -h3. Automate, Automate, Automate - -You're a damn programmer. You should be scripting the hell out of your deployment just like -you do your testing. Automation reduces human error, makes your setups consistent, and many -times can become a project itself just like "Capistrano":http://manuals.rubyonrails.com/read/book/17 -did. - -h1. The Recommendations - -Once you've figured out all the basic things about your planned deployment you can start deciding -which one you need at the moment, and what you might need in the future. - -Wait. You did *plan* this deployment right? Ok, go back and actually plan it. This document -is part of your planning, but you need to do your homework first to make a good decision. - -h2. Just Mongrel - -Mongrel is actually pretty fast even when compared with web servers like "Apache":http://httpd.apache.org/ -for serving static files. If your web application is just starting out, doesn't need to coexist with -things like PHP, and you don't need SSL, then consider just running Mongrel by itself. - -This is especially attractive if your application can utilize page caching. Mongrel is pretty quick -for page cached sites and is able to handle quite a few concurrent connections. - -h3. Disadvantages - -Mongrel will break down pretty quick if you have lots of people accessing Rails actions that are -slow. It can still perform like a champ for most small needs, but if you start getting more -serious then you need one of the next solutions. - -h3. Advantages - -The easiest to manage, especially on win32. You just turn it on and go home. Maybe write a -few /etc/init.d/ start-up scripts for your server if you're running a POSIX system. - - -h2. Behind TCP Balancers - -You still don't need SSL, but you do need to make a small cluster of Mongrel servers. If this -is the case, then you can simply grab "mongrel_cluster":/docs/mongrel_cluster.html and either -get "Pen":http://siag.nu/pen/ or "Balance":http://www.inlab.de/balance.html and do a simple -cluster. - -h3. Advantages - -This configuration is very easy to setup, gives you decent throughput and concurrency, and is -easy to manage. Using mongrel_cluster gives you simple commands to control whole clusters of -Mongrel servers and Pen or Balance simply accepts connections on one port and forwards them -to one of the backend Mongrel ports. - -h3. Disadvantages - -No SSL and you're still relying on Mongrel to serve the files. A cluster of Mongrel servers -is no slouch though. I think many sites that don't need SSL could run with this configuration -happily for years. A real good mix is to combine this with Rails' @asset server@ configuration -and a simple "thttpd":http://www.acme.com/software/thttpd/ install to serve your static files. - -h2. Behind HTTP Balancers - -If you need something like the above, but you also need SSL, then simply swap out Balance or Pen -and use "Pound":/docs/pound.html instead. Pound is a very flexible HTTP balancer that -also supports SSL. This gives you the same advantages of simple deployment but adds the security -you need. - -h3. Advantages - -The same as using a TCP balancer, except you now have SSL and you can do some more creative -routing. A good example is if your site has to use a PHP web app for serving ads. You can -have pound take requests for the advertising URIs and route them to the PHP application, and -then transmit everything else to your Mongrels. It's very flexible and much easier to install. - -h3. Disadvantages - -You're still relying on Mongrel to serve the files and passing that through Pound, but as -mentioned before Mongrel is pretty quick with static files. Don't underestimate it. - -h2. Behind Web Servers - -If you have complex static file serving needs, need to host a PHP application at the same time, -or have complex authentication requirements, then you should use a regular web server. Mongrel -has good instructions for quite a few web servers and supports any server that has some form -of @mod_proxy@ style support. - -* "Apache":/docs/apache.html -* "Litespeed":/docs/litespeed.html -* "Lighttpd":/docs/lighttpd.html *not recommended* - -Each of the above documents describe how to get an initial configuration of Mongrel running behind -that type of web server. You should also combine this with "mongrel_cluster":/docs/mongrel_cluster.html -to manage the cluster of mongrel servers. - -h3. Advantages - -Since you have a real web server handling the initial HTTP traffic you can easily do page caching -and other magic to speed things up and avoid even talking to Mongrel. It also means you can put -in authenticators, other web platforms, and extensions that your application might need. Many -web servers are also installed and configured by default on most platforms and you just need -to add the Mongrel specifics to get it going. - -h3. Disadvantages - -This configuration can quickly descend into madness with complexity. Apache is -notorious for having a horribly complex configuration file. Another -disadvantage of real web servers is they almost always start of as web servers, -and then proxy support is bolted on as an extra. Apache's latest proxy support is -really good as well as Litespeed's, but Lighttpd's proxy support is really bad (as of Mongrel 0.3.13). - - -h2. Behind Hardware - -If you are getting really really serious about your web application and you need to -serve up lots of Mongrels then you should take a look at a hardware load balancer. -They're really expensive, but they're usually worth it if you're in the big leagues. - -h3. Advantages - -Big big big loads and the ability to handle the SSL in hardware for many products. -Also things like smart virus filtering, routing and other goodies, but you'll -pay for it. - -h3. Disadvantages - -Expensive, Expensive, Expensive. Did I mention Expensive. One more time Expensive. -They're also a royal pain to setup properly, but then that's why their Expensive. - diff --git a/site/src/docs/contrib.page b/site/src/docs/contrib.page deleted file mode 100644 index 6f3c6c1..0000000 --- a/site/src/docs/contrib.page +++ /dev/null @@ -1,199 +0,0 @@ ---- -title: Contribute -inMenu: true -directoryName: Contribute ---- - -h1. Contributing To The Mongrel Canon - -The documentation for Mongrel is typically written by me (Zed), but other -people have contributed lots of blog articles about Mongrel, actual site -documentation, or reviews and enhancements. It's pretty easy to contribute -documentation to the Mongrel canon, although what gets in is strictly -controlled in order to make sure the information quality is high. - -We are always looking for grammar and spelling freaks to send in suggestions, -and anyone who has done a difficult deployment to post their experiences to -the mailing list. Typically if your experiences get a positive response -then you may be asked to write up some documentation on it for the canon. - - -h2. What We Need - -The Mongrel project strives to be simple to use so that people don't -necessarily need to read many wizardly tomes to get started. Once people have -Mongrel figured out they typically want to do advanced things like deploy their -application in a well configured production setting or extend it. - -With that in mind, we are not really looking for introductory documentation -unless it is in languages other than English. The initial getting started for -Mongrel is pretty thin because it is so simple. - -Also, the code for Mongrel is well documented and constantly updated as work is -done. If you find errors in the "Mongrel RDoc":/rdoc/index.html then tell the -"mailing list":http://rubyforge.org/mailman/listinfo/mongrel-users and it'll -get fixed right up. - -What we are looking for is anything that's blank on the main -"documentation":/docs/index.html page and anything that is suitable for the FAQ -or a quick tip or trick. - -When writing your documentation make sure you keep it very short and you focus -on the details people need to get something working. The end results should be -functioning, but maybe not a complete massive google capable cluster. A really -good model to follow is the "cut-and-paste HOWTO". In this style of -documentation it's assumed that people will simple select the commands they -have to type and it will work. - -Finally, do not focus on system specific issues such as Debian install, RedHat -package management, setting up MySQL, etc. These topics are really needed, but -they don't fit in with documentation on Mongrel. What you can do is place a -statement that lists what people should already have configured prior to -starting the instructions, especially referencing other instructions they -should read. - - -h2. Getting Credit - -A cornerstone of the Mongrel project is that everyone deserves credit for the -free work they do. There's an "attributions":/attributions.html page that I -try to use to list people who've contributed work, cash, coffee, comments, etc. -Sometimes people get dropped, but if you think you were missed then say -something. It's important that people who work for free get recognized for -their contributions. - -When you write your documentation, feel free to add a by-line at the top and -link to your blog. Keep in mind that "RubyForge":http://www.rubyforge.org/ -doesn't like people linking to commercial entities, but personal blogs or other -open source projects are just fine. If your boss sponsored the time for you to -develop the documentation and contribute it, then feel free to mention their -name in the documentation and say thanks. - -h2. Avoid "Works-For-Me Syndrome" - -A very, very important thing to strive for is that people can take your -documentation, and with a good knowledge of their own system, can get through -the instructions with minimal difficulty. Systems change, so you may have to -keep track of the latest releases of packages and how your instructions might -need an update. - -What you *don't* want to do is slam out some half-assed set of instructions -that really only work on your little custo-hacked Debian/RedHat frankenstack. -It's a really good idea to try your instructions out on a fresh machine using a -different flavor of Linux or Unix just to make sure that you didn't miss -anything. - -h1. Writing The Documentation - -Now that you've got something to say, it's time to go through the trouble of -saying it. You should read through the documentation that is currently written -and see if you can get the same flavor. Feel free to be quirky and write in -your own style, just make sure the instructions are good. - -To start writing you're going to need a few tools and to dip into subversion -land for a few seconds. - -h2. Installing Webgen And Friends - -The site is actually generated from static files that use -"webgen":http://webgen.rubyforge.org/ to generate the site. The contents are -"Textile":http://textism.com/tools/textile/ and you can use the "hobix textile -reference":http://hobix.com/textile/ to guide you. - -To install webgen do the following: - - gem install webgen bluecloth redcloth - -The install may complain that you need other gems installed, so feel free to -install those as well. You typically don't need them since you're just gonna -generate the site from the source so you can confirm that what you're writing -fits. - -You should also make sure that you have -"subversion":http://subversion.tigris.org/ and/or "svk":http://svk.elixus.org/ -installed. These instructions will use subversion. - -You may also want to install Rake and any tools your operating system needs to -build Mongrel itself, just in case you want to have a full build. This isn't -needed for writing documentation though. - -h2. Getting The Site - -You now just need to grab the source from the anonymous subversion repository: - - svn checkout svn://rubyforge.org/var/svn/mongrel mongrel - -People using svk can do this with: - - svk mirror svn://rubyforge.org/var/svn/mongrel //mirror/mongrel - -And then use the normal svk commands to check it out: - - svk checkout //mirror/mongrel mongrel - -You should probably make sure you're in some kind of *projects* directory so -that you don't have a bunch of garbage lying around. Keep in mind also that -svk is sensitive to you moving this directory--you have to "detach" it first. - -h2. Writing or Editing Your Page - -The Mongrel web site is held in the @doc/site@ directory. In this directory -there's a @src/docs@ directory where most of the documentation is kept. - -What you have to do is find the page you are going to edit it, and open it in -your "favorite editor":http://vim.sourceforge.net/ to go to work. You'll want -to make sure you have a preamble like this on any new pages: - -
-
- ---
- title: OneWordMenuTitle
- inMenu: true
- directoryName: MyTitle
- ---
-
-
- -@MyTitle@ can be pretty much any length, but I typically have it match the one -word title. The @OneWordMenuTitle@ will show up in the left hand navigation -menu, unless you set @inMenu@ to @false@. - -With that done, just use the "hobix textile -reference":http://hobix.com/textile/ and write your documentation. - -h2. Reviewing Before Submitting - -Reviewing your documentation requires that you simply run @webgen@ and then -look at the resulting .html page in your browser of choice. Some important -formatting issues to watch for are: - -* Make sure that you put <pre><code>...</code></pre> around code sections or use the textile syntax. -* Make sure that code sections you have are not too wide since the site has a fixed width -main section. -* You can include images if you think a diagram will make more sense. -* Use section heading to break up the instructions into discrete pieces. - -h2. Submitting Your Documentation - -The easiest way to submit changes to the documentation is to simple send me -(zedshaw AT zedshaw dot com) the page and I'll put it up after reviewing it. -If you have your own web site then you can also put the page on there -temporarily. - -When you have several changes to multiple documents then you'll need to -generate a patch and send that in. With svk you'll use the @svk patch@ command -and then mail me the results. With subversion you should be able to just do -@svn diff@ and I'll be able to use it. - -Make sure when you generate patches that you aren't including changes to the -Mongrel source (unless that's your intent). It's better to hand in site and -code patches separately. - - -h1. Getting And Giving Credit - -Don't forget that you deserve credit for working on this document, but that you -also need to reference sources you read while writing it. Put you name at the -top as the author, and then list at the bottom other documents you referenced -or people who helped you. - diff --git a/site/src/docs/debian-sarge.page b/site/src/docs/debian-sarge.page deleted file mode 100644 index 56ae075..0000000 --- a/site/src/docs/debian-sarge.page +++ /dev/null @@ -1,289 +0,0 @@ ---- -title: Debian HOWTO -inMenu: true -useERB: false -directoryName: Documentation ---- - -h1. Debian - -h3. By Chris McGrath - -There's been issues with people installing on Debian, so this document is an -attempt to detail how to do it. There are actually three different ways (at -least! You may find more). The easy way worked first time I attempted it on -a new VPS I was installing. The frankinstall way was discovered when I -attempted to recreate the easy way to test the process on a brand new local -Debian install. The backport your own way was worked out to avoid the -frankinstall you end up with using the second method. - -h2. How to find out which one you need - -Debian 3.1 only has Ruby 1.8.2, so you'll need to get Ruby 1.8.4 which is in testing. So -add the following to your /etc/apt/sources.list. - -
-  
-    deb ftp://ftp.uk.debian.org/debian/ testing main
-  
-
- -*Make sure and change the .uk. to your local mirror.* - -Now pin the testing repo so you don't install stuff from it accidentally. -You'll need to edit /etc/apt/preferences, which doesn't exist on a bare install -so create it and add the following three lines: - -
-  
-    Package: *
-    Pin: release a=testing
-    Pin-Priority: 200
-  
-
- -OK, now to find out whether you're a lucky bunny or you have displeased your -personal favorite deity. As root do: - -
-  
-    root# apt-get update
-    root# apt-get -s -t testing install ruby irb rdoc ri ruby1.8-dev \
-          libzlib-ruby libopenssl-ruby1.8
-    
-  
-
- -*Notice the -s it's important* - -Examine the output, if you see the following: - -
-  
-    The following packages will be REMOVED:
-      base-config initrd-tools kernel-image-2.6.8-2-386
-  
-
- -Then you're one of the unlucky ones, sorry. Skip to the backport way -(preferred) or if you're feeling brave the frankinstall way. - -h2. Installing the basic stack - -If your still reading, congratulations! You don't have kernel issues and you -should be up and running pretty quickly. - -h3. Ruby - -First actually install Ruby, so as root do: - -
-  
-    root# apt-get -t testing install ruby irb rdoc ri ruby1.8-dev \
-          libzlib-ruby libopenssl-ruby1.8
-  
-
- -h3. RubyGems - -Debian don't provide packages for RubyGems, so we have to get it from somewhere -else. A kind soul has made debs for RubyGems 0.8.11 available, so add the -following to your /etc/apt/sources.list - -
-  
-    deb http://www.sgtpepper.net/hyspro/deb unstable/
-  
-
- -The final / is important. To install RubyGems do: - -
-  
-    root# apt-get update
-    root# apt-get install rubygems
-  
-
- -This package doesn't copy gem files to /usr/bin, instead it puts them in -/var/lib/gems/1.8/bin so we need to add that to the path. Edit /etc/profile and -add :/var/lib/gems/1.8/bin to the end of each PATH statement, -there's one for root and one for other users in the standard Debian -install. You'll need to log in and out again to get your path setup -correctly. - -(NOTE: Some people say just install rubygems from source if this doesn't work -for you). - -h3. GCC & Friends - -We're nearly ready to install Mongrel, if you're doing a frankinstall go back -to that page for the details. For the rest of us, the command is: - -
-  
-    root# apt-get install build-essential
-  
-
- -h3. Rails & Mongrel - -Time to install Rails and Mongrel at last! - -
-  
-    root# gem install rails --include-dependencies
-    root# gem install mongrel mongrel_cluster --include-dependencies
-  
-
- -Pick the latest ruby version of Mongrel from the menu. Wait for it to finish. *CONGRATULATIONS* - -h3. Testing - -To make sure the congratulations weren't premature, lets check it works. Login -as a normal user and do: - -
-  
-    user$ rails test_app
-    user$ cd test_app
-    user$ script/generate controller HelloWorld index
-  
-
- -Edit app/views/hello_world/index.rhtml to look like: - -
-  
-    

Hello World

-

<%= Time.now.to_s(:long) %>

-
-
- -Lets check it's all running. - -
-  
-    user$ mongrel_rails start
-  
-
- -Point your browser at http://999.999.999.999:3000/hello_world - -(NOTE: Replace 999.999.999.999 with your IP address.) - -h1. Backporting 1.8.4 from testing - -Sorry you're here, but hey lets get this done. This involves building your own -debs for Ruby 1.8.4 from source, so you don't have to upgrade your kernel and -install the build tools from testing like in the frankinstall. - -h2. Building your own Ruby debs - -First up, you need to *remove* the line we added before in -/etc/apt/sources.list and clear out /etc/apt/preferences, so do that now. We're -going to get the source from testing, so add the following to -/etc/apt/sources.list - -
-  
-    deb-src ftp://ftp.uk.debian.org/debian testing main
-  
-
- -*Make sure and change the .uk. to your local mirror.* - -And do the following as root: - -
-  
-    root# apt-get update
-    root# apt-get install devscripts # if you don't have them already
-    root# mkdir scratch
-    root# cd scratch
-    root# apt-get source ruby1.8
-    root# apt-get build-dep ruby1.8 
-    root# cd ruby1.8-1.8.4
-    root# debuild -us -uc
-    root# cd ..
-    root# rm ruby1.8-elisp # unless of course you've emacs installed
-    root# dpkg -i *.deb
-    root# ln -s /usr/bin/ruby1.8 /usr/bin/ruby
-    root# ln -s /usr/bin/irb1.8 /usr/bin/irb
-    root# ln -s /usr/bin/ri1.8 /usr/bin/ri
-    root# ln -s /usr/bin/rdoc1.8 /usr/bin/rdoc
-  
-
- - -h3. To be worked out: - -* No libzlib-ruby deb made... couldn't figure out how to get it done -* Install rubygems - when I ignored that and tried to use Ezra's sgtpepper.net mirror it wants to install ruby-1.8.2 - - -h1. Frankinstall of Mongrel on Debian Sarge - -If you're here I'm really, really sorry. I hope this doesn't mess up your -machine. If you're going to do this I'd consider just using testing itself, or -Ubuntu or something. Anyways, it's here for completeness, I had to re-install -Debian four times to figure this out so I'm damn well writing it up. - -This details how to go from a basic debian-31r2-i386-netinst.iso install to -having Ruby 1.8.4, RubyGems, Rails and Mongrel running (and a good part of -testing). I'm not going to cover MySQL or any of that, this is purely about -the dog. - -When I say a basic install, I mean a basic install. I entered linux26 at the -boot menu to get a 2.6 based system. Let it do it's stuff, then when the -installer asks what kind of system you want I chose to manual package -selection, and only installed ssh. - -I'm going to assume you got as far as adding the testing stuff to -/etc/apt/sources.list and /etc/apt/preferences from the Debian HOWTO page. The -next thing you need to read is -"this":http://www200.pair.com/mecham/spam/kernel.html, which explains why we -have to do what we now have to do. - -h3. Upgrading the kernel - -
-  
-    root# apt-get -t testing install initrd-tools
-  
-
- -This installed 0.1.84.1, so next time to install an updated kernel that can handle udev. - -
-  
-    root# apt-get -t testing install linux-image-486
-  
-
- -Lots of stuff gets installed, including a 2.6.15 kernel. It asks you if you -want to upgrade glibc during this so say yes. When it's finished, reboot the -system. - -When it comes back up (and lets hope it does), time to install Ruby. Now you've -upgraded the kernel this is the same procedure the lucky people get to use. So -go and follow the instructions for Ruby and RubyGems there, then come back here -when it's time for GCC and it's toolchain. - -h3. Installing the testing version of the GCC toolchain - -Because of glibc issues now you've upgraded your kernel, you're back here. It's -actually not that different a command from the lucky people, it just installs a -bunch more stuff from testing than you might be comfortable with. - -
-  
-    root# apt-get -t testing install build-essential
-  
-
- -When it's finished, and you have your frankinstall, it's time to install Rails -and Mongrel at last! Back to the luck people page, it's the same from here on -in. Good luck! I don't guarantee you'll have a trouble free ride installing -whatever else you need to get going, but I hope you do. diff --git a/site/src/docs/distributed_worker.page b/site/src/docs/distributed_worker.page deleted file mode 100644 index a74913e..0000000 --- a/site/src/docs/distributed_worker.page +++ /dev/null @@ -1,105 +0,0 @@ ---- -title: Offloading -inMenu: true -directoryName: Offloading ---- - -h1. Long Tasks For Slow Rails - -You've got the best idea ever for a web site. It's a fantastic -Franken-stack that takes requests from the internet, converts them -to giant PDFs with latex, puts them onto 20 FTP servers, and then -encrypts them using 2^718 bit Eliptic Curve Encryption. - -Best of all, in order to avoid a "single point of failure" you've -decided that all this monstrous Rube Goldberg Architecture needs to -be run via a series of IO.popen calls to various Perl scripts. - - -h2. How Bad Ideas Begin - -Yes, this is contrived but not by much. I've actually had people report -architectures very close to this with pride. I have no idea why -making something complex suddenly makes it smart, but oh well, I just work -here. You do what you want, but hear me out for a second before you -continue down this path. - -Designs like this go very wrong very quickly for three main reasons: - -* Complex things are more fragile than simple things. Your application is going -down the same road as the Roman Empire, and just like them you don't realize it. -* Systems with large numbers of interconnections are slower simply because -everything takes time and more interconnections means more time to complete a process. -This isn't always the case, but given two systems that do the same work, I'll -take the simpler less connected version since I know I can make that faster. -* Complex things do not change easily, which feeds into their fragile nature and -means they can't improve in performance. - -An excellent example of the above three conditions is this wonderfully hilarious -"stack trace":http://ptrthomas.wordpress.com/2006/06/06/java-call-stack-from-http-upto-jdbc-as-a-picture/ (and the comments to back it up). Somehow it doesn't dawn on the author -that his "Business Logic" box is pointing at one line. The comments are full -of statements that support this type of design, but I bet half this crap isn't -really necessary. *This* my friends is the classic Rube Goldberg Architecture. - -Your Ruby brain is laughing at this, and now you want to do the exact same -thing? Start laughing at yourself my friend because you're next. - - -h2. Down With Complexity - -Before you start offloading tons of work to external programs and designing your -Franken-stack, step back and ask this very simple question: - - "How could I do the same thing with less stuff?" - -Your goal for the next two hours is to remove anything that can be done -simpler, isn't needed, or just simply adds overhead. You want to ignore -that voice in your head screaming, "*But how will you get a job!?*" Yell -back at it, "*I have a job!*" And then do your job. Create a system that -does what it's supposed to with the least amount of resources. No more, no -less. If you need to add something, add it later. Right now an 80% solution -that works is better than a 99% solution that's out 6 years from now. - - -h1. The Distributed Worker Pattern - -You've simplified your Rube Goldberg Architecture down to the bare minimum -and you've thought of simpler ways to do your processing, but you *still* -have to call an external program. There's no way to turn this program into -a server, and the program takes a long time to run. - -Whatever you do, don't use IO.popen() to run it. Don't use exec. Nothing. -People think that calling these functions to run an external program suspends -the current Rails request while the external program runs. That's right. What's -wrong is that it *suspends every other request as well*. Mongrel will still accept -connections and happily queue them all up, but it waits for Rails to exit this -request before it gives it the next one. - -What you *need* to do is give this request to a special server called a -"Distributed Worker". This is a simple pattern where you hand something -that takes forever to a server that knows how to do two things: - -# Run the request to produce a result. -# Report status to the requester when asked. - -The typical scenario for using a Distributed Worker is something like this: - -# You have a Rails server and a Worker server running. They talk using DRb. -# Request comes into Rails, and an action builds the information needed by the Worker. -# Rails submits the request to the Worker and takes a ticket. It stuffs this into the user's -session and then sends them to a "status action". -# The Worker begins working on the request identified by the ticket. -# At periodic intervals (probably with JavaScript) the client hits the status action which -in turn takes the ticket and asks the Worker for status. -# When the Worker is done it tells the status action in one of the status responses and -the status action goes to a "collector action" that picks up the results using the ticket. -# Finally, the collector gets the result from the worker and presents it to users. - -If you're smart, you can actually have all this going on in the "background" of the -user interface in such a way that the user just sees requests queue up and slowly change -state until they are done. - -The particulars of actually implementing this pattern are left to you, since -the idea is that it's probably different for everyone. There is one project -though that makes this whole process generic and fairly easy called -"BackrounDRb":http://backgroundrb.rubyforge.org/ thanks to Ezra Zygmuntowicz. diff --git a/site/src/docs/frameworks.page b/site/src/docs/frameworks.page deleted file mode 100644 index 7a55edb..0000000 --- a/site/src/docs/frameworks.page +++ /dev/null @@ -1,34 +0,0 @@ ---- -title: Frameworks -inMenu: true -directoryName: Frameworks ---- - -h1. Framework Issues - -As known issues specific to different frameworks are reported they get -posted here. Problems reported here aren't a sign that a framework is -worse or better than others, just a reflection of people's experiences. - -h2. Rails - -* Rails is not thread safe so if you have long running actions then you can potentially -block the server. Keep in mind that this is the case for *any* server, it's just more -pronounced for Rails. -* You can easily kill a Rails server by not closing files. Always open files in blocks. -* If you turn on @allow_concurrency@ them Mongrel will run your application without any thread locking. -This can be dangerous so test it first, and I'm pretty sure it won't work for most complex applications. -* Mongrel will honor a HUP request and try to do an internal reload, but this usually doesn't work the -way you think. Mongrel's shutdown process is very nice and safe, so just restart. - - -h2. Camping - -* Running Camping and Rails in the same Ruby interpreter -causes all sorts of problems with ActiveRecord. You either run one or the -other but not both. - - -h2. Nitro - -* None reported yet. diff --git a/site/src/docs/gem_plugin.page b/site/src/docs/gem_plugin.page deleted file mode 100644 index 0e2ec96..0000000 --- a/site/src/docs/gem_plugin.page +++ /dev/null @@ -1,335 +0,0 @@ ---- -title: Writing Plugins -inMenu: true -directoryName: Documentation ---- - -* Jun 16: These docs are out of date and will be updated soon. * - -h1. Writing Mongrel Plugins with GemPlugin - -Mongrel uses a system called "GemPlugin":http://mongrel.rubyforge.org/gem_plugin_rdoc -to let people create simple "RubyGems":http://rubyforge.org/projects/rubygems/ -extensions that get loaded dynamically when Mongrel starts. This help document -is more for experienced Ruby developers interested in extending Mongrel with -new commands. - -*NOTE:* You can currently only write new commands -such as "mongrel_rails dostuff". Handlers and -Filters are on their way. - -h2. Why Plugins for Mongrel? - -If you've ever used other systems that have plugins you'll find there are -several painful parts to writing your own plugin: - -* You don't have their developer tools so it takes forever to get started. -* You don't know how to structure the project or even where to start. -* Once you get it built you have to figure out how to register and install it. -* When you want to update it you have to somehow get the update out to users. -* You have to manage dependencies between your plugin and other plugins. -* Including and using your own resources (images, html files, etc.) or config files - is really painful. Not sure why this is but it's really annoying. - -Most people solve many of the problems by the "sourdough method". They -take a plugin that currently works, copy it, and base their plugin -on the prototype. This works great until you want to do something -original or until you find out the original author did something wrong. - -GemPlugin solves this problem by relying on the regular RubyGems -package management system to give you: - -* A simple way to package, distribute, manage, and update your Mongrel plugins. -* Dynamic loading based on the gem dependencies and not on specific configurations. -* Segregated extensions for Mongrel. -* All the capabilities of RubyGems. GemPlugin doesn't mess with them at all. -* A little generator that starts your project off right similar to how Rails generators work. -* The ability to package resources (images, configs, etc.) with your gem and then load them - dynamically no matter where the gem eventually gets installed. - -In the end GemPlugins are just RubyGems that get loaded a special way -so they are activated right away. The only extra thing is a bit of -"magic" that puts plugins into a nice little namespace outside of -the usual Ruby module and class hierarchy. - -The advantage for Mongrel is that people can write their own -plugins and distribute them easily without anything more complex -than what all Ruby developers already have: RubyGems. - -h2. How They Work - -Mongrel plugins (a.k.a. GemPlugins) are really very simple. Basically -when you use the GemPlugin API you tell it what kind of dependencies -will trigger a gem to be loaded. GemPlugin then goes through all of -the installed gems and loads any that meet the dependency description. -Then your plugin just registers itself in the right "plugin category" -and everything starts working. The user of your plugin won't have to -do too much unless you want to give them additional configuration. - -The best way to understand this is to actually build a plugin -and watch it work. - - -h2. Your First Plugin - -Make sure that you have rubygems, mongrel, gem_plugins, and -rake all installed and working right. - -Yes, this means that you are forced to use RubyGems. People who really don't -like RubyGems are free to take the core of the Mongrel Server API and re-use it -as they wish. Just using Mongrel doesn't require this return so feel free to -use it like crazy in your commercial software or other licensed project. - -Once you have all that installed you need to simply find a nice quiet -place to generate your initial plugin directory with the *gpgen* -command: - - $ gpgen myplugin - -Let's say we're going to reimplement the existing mongrel_status example -command which just prints out the PID of a running Mongrel server -on any POSIX system. (Win32 folks will have to play along). - -Just do the following: - - $ gpgen mongrel_status - Creating directory mongrel_status - Creating file mongrel_status/COPYING - Creating directory mongrel_status/lib - Creating file mongrel_status/LICENSE - Creating file mongrel_status/Rakefile - Creating file mongrel_status/README - Creating directory mongrel_status/resources - Creating directory mongrel_status/tools - Creating directory mongrel_status/lib/project - Creating file mongrel_status/lib/project/init.rb - Creating file mongrel_status/resources/defaults.yaml - Creating file mongrel_status/tools/rakehelp.rb - Creating proper 'mongrel_status/lib/mongrel_status/init.rb' file - -This creates the skeleton of your plugin project. There's not too many -files in here, but let's cover what each one does: - -* *mongrel_status/COPYING* -- Your license or copying restrictions. -* mongrel_status/lib -- Where you store your source for the plugin to use. -* *mongrel_status/LICENSE* -- Your license again. -* *mongrel_status/Rakefile* -- Builds your stuff. -* *mongrel_status/README* -- Instructions for using your plugin. -* mongrel_status/resources -- A place to put files your plugin might need. -* mongrel_status/tools -- Tools used by rake. -* mongrel_status/lib/mongrel_status -- Your init.rb goes here. -* *mongrel_status/lib/mongrel_status/init.rb* -- Required to initialize your plugin. -* mongrel_status/resources/defaults.yaml -- Default configuration options. -* mongrel_status/tools/rakehelp.rb -- Used by the Rakefile. - -The files in bold are the ones you're going to have to edit to create your -plugin. - - -h2. COPYING, LICENSE, and README - -At first you can probably just skip these, but when you go to -distribute your plugin you'll need to make sure that you have -some kind of license on it and some basic instructions for -people to read. - -Check "OSI":http://www.opensource.org/ for a list of some available licenses. - - -h2. Rakefile - -This is the first place you need to go in order to setup your Mongrel command -correctly as a Mongrel plugin. The file is pretty small, but if you're -not familiar with Rake syntax you can "read the Rake docs":http://rake.rubyforge.org/ -for more advanced help. - -To get you started though, here's what you have to change: - -Change the version from 'version="0.1"' to whatever you want. - -Go the setup_gem block and add mongrel as a dependency, set yourself as the author, and change the summary: - - setup_gem(name, version) do |spec| - spec.summary = "The mongrel_status GemPlugin" ## change this - spec.description = spec.summary - spec.author="Nobody" ## change this - spec.add_dependency('gem_plugin', '>= 0.2') - spec.add_dependency('mongrel', '>= 0.3.10') ## add this - spec.files += Dir.glob("resources/**/*") - end - -That's it for the Rakefile. It won't do much since you still have to setup the actual command -in the mongrel_status/lib/mongrel_status/init.rb file, but you could build this right now -and install it: - - $ rake - $ gem install pkg/mongrel_status-0.1.gem - -Not so glamorous yet you'll get there soon. - -*You might need to do 'gem uninstall mongrel_status' if you installed that already.* - - -h2. lib/mongrel_status/init.rb - -This is where the magic really start to happen. In this file is just a -little nothing class you need to edit in order to get everything working -right. Here's the contents that you should have: - - require 'gem_plugin' - class ChangeME < GemPlugin::Plugin "/somecategory" - end - -You'll want to change this file to be the following: - - require 'gem_plugin' - require 'mongrel' - class Status < GemPlugin::Plugin "/commands" - include Mongrel::Command::Base - end - -This doesn't quite do anything useful as a command yet, but now if we -remove the gem and rebuild we'll be able to see *mongrel_rails* list -the command as being available: - - $ gem uninstall mongrel_status - $ rake - $ gem install pkg/mongrel_status-0.1.gem - $ mongrel_rails - Available commands are: - - - restart - - start - - status - - stop - - Each command takes -h as an option to get help. - $ - -See how your list of available commands now has "status" listed? -Try doing 'gem uninstall mongrel_status' and run *mongrel_rails* -again to see the command go away. Keep doing this until the -magic wears off. - - -h2. Explaining the PFM - -How the hell does GemPlugin do that? I mean, you just tweaked a -Rakefile and made a class and *somehow* mongrel_rails gets -a brand new command without you ever touching Mongrel. Magic -right? No, PFM. - -Here's how all of this works (for the engineers who can't use -something until they've analysed it's complete chemical composition): - -# Your gem has two dependencies: gem_plugin and mongrel. -# Your gem also has a file lib/mongrel_status/init.rb -# This init.rb file has 'class Status < GemPlugin::Plugin "/commands"' - which registers it as a Plugin at the "/commands" category. -# When *mongrel_rails* starts it tells GemPlugin to load all the plugins (gems) - that depend on both gem_plugin and mongrel (but not rails). -# The GemPlugin system then goes through all the installed gems and simply - does a require on the init.rb when it finds a gem with the right dependencies. -# Since your gem depends on the right stuff, and has a lib/mongrel_status/init.rb - it gets loaded properly and *mongrel_rails* can list it. -# The only remaining magic is the Status class is loaded by init.rb and that - puts it into the /commands category of plugins. Mongrel rails considers - and plugin in this category to be a valid Mongrel command. - -What happens in someone else puts a Plugin in the /commands category? Well, -since *mongrel_rails* is only loading gems which depend on *both* gem_plugin -and *mongrel* then there's no problems. You Snafu project can be safe knowing -it's /commands won't get loaded. - -An additional piece of magic is that *mongrel_rails* holds off on loading -and GemPlugin that depends on gem_plugin, mongrel, *and* rails. These -plugins are intended to be rails specific extensions or other things -that you want Mongrel to have, but only *after* Rails is loaded and configured. - -What the above paragraph means is that, yes, you can actually distribute plugins -for Rails using the Mongrel GemPlugins without having to go through the usual -Rails plugin system. This isn't tested yet, but feel free to try it out. - - -h2. The Final Touches - -The only thing that would be left is to actually implement the full -mongrel_status command. Rather than put the code into this document, -you can just read what's in the -"Subversion repository":http://rubyforge.org/plugins/scmsvn/viewcvs.php/*checkout*/trunk/projects/mongrel_status/lib/mongrel_status/init.rb?root=mongrel&rev=91 -and put that into your own init.rb. - -What the code there does is first sets up the command line options available, -then validates them, and finally just runs the command in order to do it. -The code should be easy to follow but let me know. - -h3. A Note On Modules - -If you want you can put your plugin into a module and then it will be registered -under "/commands/modname::cmdname". So you did this: - - require 'gem_plugin' - require 'mongrel' - module Examples - class Status < GemPlugin::Plugin "/commands" - include Mongrel::Command::Base - end - end - -Then the command would show up from mongrel_rails as "examples::status" and -would be known as "/commands/examples::status". - - -h2. Big Tricks With GemPlugin - -"GemPlugin":http://mongrel.rubyforge.org/gem_plugin_rdoc/ has a couple of other -methods that will really help you when writing a plugin that needs to have -some default configurations or possibly have external data resources. - -The first is the GemPlugin::Manager.instance.resource method. What this method -does is when given a gem and a path, it find the actual path to that resource -in the installed gem directory. These resources are packaged up out of your resources/ -directory in your plugin source. - -Using the current example if I wanted to get to the mongrel_status/resources/defaults.yaml -file I'd do: - - defaults = GemPlugin::Manager.instance.resource "mongrel_status" "/defaults.yaml" - -And then try to load that as a YAML file. The *resource* method returns nil if -no such file exists for the given plugin, and the plugin has to be loaded first. - -The problem with doing this for something like default configuration options is -that you'll end up writing a ton of the same code for all your plugins. To help -with this, GemPlugin also has a *config* method which takes a set of options, and -then tries to load the *resources/defaults.yaml* file as a set of defaults (modified -by the options). - -Let's say you want to default to having debug off, but allow the user to pass in some -options to turn it on. This is how you'd do it: - - options = GemPlugin::Manager.instance.resource "mongrel_status", user_ops - -What this does is simply use the *resource* method to locate and load the resources/defaults.yaml -file, and then merge the *user_ops* hash into them so *user_ops* override the defaults. - -The point of these two pieces of functionality is that now you can completely package -all the external resources your plugin needs and access it without much user -intervention. It would be a good idea to let the user override these paths. - - -h2. Rails Plugins Without Rails Plugins - -Ruby on Rails already has "an extensive set of plugins":http://wiki.rubyonrails.org/rails/pages/Plugins -that you can choose from to make your application. One thing you can do though is -instead of using the normal Rails plugin system you could just make a GemPlugin -that depends on gem_plugin, mongrel, and *rails* gems. When you do this it will be loaded -after Mongrel configures Ruby on Rails. If you put your code in to the init.rb and -use the resources and configuration features of GemPlugin then you could package a -very nice little plugin without having people go through the normal plugin method. - -I'm not sure if this has any advantages or disadvantages over the current system, but -other Mongrel supported frameworks (like Camping and Nitro) can use this same technique -to load plugins that are specific to how Mongrel works. - - diff --git a/site/src/docs/how_many_mongrels.page b/site/src/docs/how_many_mongrels.page deleted file mode 100644 index 7911293..0000000 --- a/site/src/docs/how_many_mongrels.page +++ /dev/null @@ -1,90 +0,0 @@ ---- -title: Tuning -inMenu: true -directoryName: Tuning ---- - -h1. How Many Mongrel Instances Should I Run? - -There is no set number that is "best" since that depends on factors like the -type of application, server hardware, how dynamic the appication is, etc. - -I've found that 8-12 mongrel processes per CPU is about right, but I determined -this by starting with 1 and then doing the following: - -h2. Baseline Your Server - -Pick a URL to a small file that is running on your apache server and is not -served by Mongrel at all. This URL will be your "best possible baseline". - -Build your baseline measurement first. Using httperf, measure the speed of -your URL so that you know how fast you could possibly get if you served -everything static in ideal situations. - -**Make sure you do this on a different machine over an ideal network.** -Not your damn wifi over a phone line through sixteen poorly configured routers. -Right next to the box your testing with a fast switch and only one hop is the -best test situation. This removes network latency from your test as a -confounding factor. - - -h2. Baseline Rails and Mongrel - -Pick a page that's a good representative page for your application. Make sure -you disable logins to make this test easier to run. Hit this Rails page and -compare it to your baseline page. - -* If your rails measurement is *faster* than your baseline - measurement then you screwed up. Rails shouldn't be faster than a file - off your static server. Check your config. -* If your rails measurement is *horribly slow* compared to baseline - then you've got some config to do before you even start tuning the - number of process. Repeat this test until one mongrel is as fast as - possible. - -h2. Tweak - -Once you've got a Rails page going at a reasonable speed, then you'll want to -increase the --rate setting to make sure that it can handle the reported rate. - -Finally, alternate between adding a mongrel process and running the test with -the next highest rate you'd get. Stop when adding one more server doesn't -improve your rate. - -*Make sure you run one round of the test to get the server "warmed up", and -then run the real one.* Heck, run like 5 or 6 just to make sure you're not -getting a possibly bad reading. - -h2. Example - -# Run the test and find out that one mongrel can support a @--rate@ of 120 req/second. -# Add another mongrel and run the test again with @--rate@ 240. It handles this - just find so you add another and get @--rate@ 360. -# Try another one and it dies. Giving @--rate@ 480 gets you only a rate of 100. - Your server has hit it's max and broke. -# Try tuning the @--rate@ down at this and see if it's totally busted (like, 4 mongrels - only gets you @--rate@ 380) or if it's pretty close to 480. -# That should do it. A good practice is to also look at the CPUs on the - server with top and see what kind of thrashing you give the server. - - -h2. HTTPERF - -Here's the commands I use for each test, but read the man page for -httperf so that you learn to use it. It's an important tool and just -cut-pasting what I have here is not going to do it for you. - -* @httperf --server www.theserver.com --port 80 --uri /tested --num-conns <10 second count>@ - -* @httperf --server www.theserver.com --port 80 --uri /tested --num-conns <10 second count> --rate @ - -Where @<10 second count>@ is enough connections to make the test run for 10 -seconds. Start off with like 100 and keep raising it until it goes for 10 -seconds. - -Where @@ is whatever httperf said the estimated -requests/second were. What you're doing here is seeing if it really can handle -that much concurrency. Try raising it up and dropping it down to see the -impact of performance on higher loads. - -Have fun. diff --git a/site/src/docs/howto.page b/site/src/docs/howto.page deleted file mode 100644 index f59bcfa..0000000 --- a/site/src/docs/howto.page +++ /dev/null @@ -1,490 +0,0 @@ ---- -title: HOWTO -inMenu: true -directoryName: Documentation ---- - -h1. Mongrel HOWTO - -After you have "Mongrel running":started.html you can start -to configure Mongrel and tune it to your specific configuration. -The "documentation":/docs/index.html page has documentation -on the various web servers you can run, but this document -will give you tips and tricks on getting Mongrel running. - - -h2. Every Start Option Explained - -Mongrel is a self-documenting program by giving you an extensive help -listing for each command. Simply running *mongrel_rails start -h* -will print out each possible option and what it does. Most of -the options are similar to what you've been using already with -script/server. - -These options are also used in the -C config file option to -set them without using the command line. The name used in the -config file is slightly different since it's a YAML file. The -name to use is in parenthesis after the option name. The -option names are different from the command line option names -mostly for historical reasons. - - -
-
-e, --environment (:environment)
-
-Configures your Rails environment to what you need. -
  • Default: development
-
-
- -
-
-d, --daemonize (:daemon)
-
-If given (no options) then Mongrel will run in the background. -No Win32. -
  • Default: false
-
-
- -
-
-p, --port (:port)
-
-Port to bind to when listening for connections. -
  • Default: 3000
-
-
- -
-
-a, --address (:host)
-
-Address to bind to when listening for connections. -
  • Default: 0.0.0.0 (every interface)
-
-
- -
-
-l, --log (:log_file)
-
-Where to dump log messages in daemon mode. Use an *absolute* path. -No Win32. -
  • Default: $PWD/log/mongrel.log
-
-
- -
-
-P, --pid (:pid_file)
-
-Where to write the PID file so start and -stop commands know the Process ID. Use *absolute* paths. -No Win32. -
  • Default: $PWD/log/mongrel.pid
-
-
- -
-
-n, --num-procs (:num_processors)
-
-Maximum number of concurrent processing threads before -Mongrel starts denying connections and trying to kill -old threads. -
  • Default: 1024
-
-
- -
-
-t, --timeout (:timeout)
-
-Time to pause (in hundredths of a second) between accepting -clients. Used as a throttle mechanism. -
  • Default: 0
-
-
- -
-
-m, --mime, (:mime_map)
-
-A YAML file that maps from file extensions to MIME types -for static files. It's important that if you are using -page caching or you have a different language setting--like -UTF8--then you have to configure this. Read more below. -
  • Default: not set.
-
-
- -
-
-c, --chdir (:cwd)
-
-Directory to change to prior to starting Mongrel. "cwd" means -"change working directory". -
  • Default: . (current directory)
-
-
- -
-
-r, --root (:docroot)
-
-Document root where Mongrel should serve files from. -If you are putting Mongrel under a different base URI, and -you want it to serve files out of a different directory then -you need to set this. -
  • Default: public
-
-
- -
-
-B, --debug (:debug)
-
-Turns on a debugging mode which traces objects, threads, files -request parameters, and logs accesses writing them to log/mongrel_debug. -This option makes Mongrel very slow. -
  • Default: false
-
-
- -
-
-C, --config (NONE)
-
-Specifies a configuration YAML file that sets options you're -reading about right now. Read "Command Line Settings" below -for more information. Use *absolute* paths. -
  • Default: no default
-
-
- -
-
-S, --script (:config_script)
-
-A special Ruby file that is run after Rails is configured -to give you the ability to change the configuration with -Ruby. This would be where you can load customer Mongrel -handlers, extra libraries, or setup additional Ruby code. -This option is fairly advanced so use with caution. -
  • Default: not set
-
-
- - -
-
-G, --generate (NONE)
-
-Takes whatever options you've set for Mongrel, and the -current defaults, and then writes them to a YAML file -suitable for use with the -C option. -
  • Default: not set
-
-
- -
-
--prefix uri
-
-A URI to mount your Rails application at rather than the default -/. This URI is stripped off all requests by Rails (not Mongrel) -so it cannot end in /. -
  • Default: not set
-
-
- - -
-
--user USER
-
-Must have --group too. -The user to change to right after creating the listening socket. -Use this if you have to bind Mongrel to a low port like port 80, -but don't want Mongrel to run as root. Not useful in Windows. -
  • Default: not set
-
-
- - -
-
--group GROUP
-
-Must have --user too. -The group to change to right after creating the listening socket. -Not userful in Windows. -
  • Default: not set
-
-
- -h2. Configuration Files - -When Mongrel runs with just *mongrel_rails start* it has -reasonable defaults for most people's development work with Rails. -It tries to be as similar to the existing @script/server@ command as -possible. - -When you need to run Mongrel in production (or if you're doing -wicked fancy stuff) then you'll need to start using a few -configuration files. Problem is the configuration file is in -this weird YAML syntax that most people just hate. Rather than -describe the file's syntax and all possible options, Mongrel has -a -G (generate) feature that will take any command line options -you give it, generate the YAML file to replicate those options, and -then exit. For example, you could make a config file like this: - - @mongrel_rails start -G mongrel_8080.yml -e production -p 8080@ - -And it'll write all the options possible to mongrel_8080.yml, but -with your specific changed for environment (-e production) and -port (-p 8080). - -When you run a configuration file with -C, don't pass other options. -Rather than have complex rules about whether a configuration file or -command line option wins, mongrel_rails just uses configuration file -and defaults, or command line options and defaults. Basically don't mix, -it won't work. - - -h2. MIME Types - -Mongrel comes with a very small set of default MIME types. -The main theme with Mongrel is that it doesn't interfere with -the frameworks it hosts. Many frameworks do their own -MIME parsing and control, so Mongrel only has just enough to -serve up a few static files. - -The default types are defined in DirHandler as a constant -and are: - -

- MIME_TYPES = {
- ".css"        =>  "text/css",
- ".gif"        =>  "image/gif",
- ".htm"        =>  "text/html",
- ".html"       =>  "text/html",
- ".jpeg"       =>  "image/jpeg",
- ".jpg"        =>  "image/jpeg",
- ".js"         =>  "text/javascript",
- ".png"        =>  "image/png",
- ".swf"        =>  "application/x-shockwave-flash",
- ".txt"        =>  "text/plain"
- }
- 
- -Notice that it's just a hash mapping from extension (*with period*) -to the type that needs to be set. - -To change this you just need to write a YAML file that sets -up your new types or changes these: - -
- 
- ---
- .rss: text/xml
- 
- 
- -This would add .rss with the @text/xml@ MIME type. - -One problem that comes up quite frequently is that Mongrel's -DirHandler isn't quite smart enough to know that a page cached -/feed/rss.html should really be an RSS file with text/xml. -Mongrel really doesn't have much information to go on, but it -will happily serve this file up as @text/html@. The best -solution to this is to just not use Mongrel's DirHandler, but -instead use a real web server. Another option is to write a -special handler for that URI which knows about it. - -You might also need to edit this file if, for example, you use a different encoding such as UTF8. -You'll want to change all of these MIME types to have the -proper ending. For example,if you wanted @charset=EUC-JP@ for -all your returned static documents, then you'd do: - -
- 
- ---
- .js: text/javascript; charset=EUC-JP
- .htm: text/html; charset=EUC-JP
- .html: text/html; charset=EUC-JP
- .css: text/css; charset=EUC-JP
- .txt: text/plain; charset=EUC-JP
- 
- 
- -You'd also probably need to do this with your Rails pages. - -*NOTE:* I'm looking for a method to fix this with a setting or detection. - - -h2. Command Line Settings - -Sometimes it's a real pain to set all the command line options -you need to run Mongrel in production. Instead of setting the -options on the command line, you can have Mongrel generate a -configuration file for you with -G and then pass this (modified) -file to the -C option next time you start. - -For example, if you do this: - - mongrel_rails start -G config/mongrel_opts.conf - -Then the mongrel_options.conf will have: - -
- 
- ---
- :config_script:
- :environment: development
- :pid_file: log/mongrel.pid
- :num_processors: 1024
- :docroot: public
- :timeout: 0
- :host: 0.0.0.0
- :mime_map:
- :port: 3000
- :daemon: false
- :cwd: /home/zedshaw/projects/mongrel/testapp
- :includes:
- - mongrel
- :debug: false
- :log_file: log/mongrel.log
- 
- 
- -The @:blah:@ (two colons) syntax is just how YAML does things. -You can then either just edit this file and use it with: - - mongrel_rails start -C config/mongrel_opts.conf - -Or, you can run the start command again with -G and all the -options you need to set and it will properly generate the -config file again. - - -h2. Mongrel Configure Scripts - -Mongrel uses a small DSL (Domain Specific Language) to configure -it's internal workings. It also lets *you* use this DSL and -regular Ruby to alter it's internal workings. The options that -turn it on are -S or @:config_script:@ in the config file. - -Doing this is fairly advanced, but here's how I would create a -second DirHandler that sits in another directory. First, create -a config/mongrel.conf file with this in it: - - @uri "/newstuff", :handler => DirHandler.new("/var/www/newstuff")@ - -And then do this: - - mongrel_rails start -S config/mongrel.conf - -Now when people go to /newstuff they get the files listed there. - -This is actually a Ruby file, so you can run -most Ruby code you need, require libraries, etc. - -Main usage for this is to create handlers which run inside Mongrel -and do extra work. - -For more information, read the "RDoc":/rdoc/ for -"Mongrel::Configurator":/rdoc/classes/Mongrel/Configurator.html -on what functions are available. - - -h2. POSIX Signals Used - -When you run Mongrel on a POSIX compliant system (meaning *not* Win32) -you are able to control with signals similar WEBrick or FastCGI. - -The signals Mongrel running Rails understands are: - -* *TERM* -- Stops mongrel and deleted PID file. -* *USR2* -- Restarts mongrel (new process) and deletes PID file. -* *INT* -- Same as USR2, just convenient since CTRL-C is used in debug mode. -* *HUP* -- Internal reload that might not work so well. - -You can use the -S configure script to add your own handlers -with code like this: - -

- trap("USR1") { log "I'm doing stuff." }
- 
- - -h2. Super Debugging With Rails - -When you use the -B option Mongrel produces *tons* of -useful debugging output. The debugging output is actually -implemented as a small set of handlers in lib/mongrel/debug.rb -if you're interested in writing your own. - -The files that get generated are: - -* *rails.log* -- Logs all request parameters exactly as they come to Rails from Mongrel. -* *objects.log* -- Logs a top 20 count of object types before and after each request. -* *files.log* -- Logs open files before and after each request. -* *threads.log* -- Logs active threads before and after each request. - -You use these log files to track down weird Rails behavior in your -application. Classic example is if your Rails server stops answering -requests after a certain amount of time. #1, #2, and #3 cause of this is -that you are opening files and not closing them. Turning on -B and -look in the @files.log@ file will show you exactly what files are -being leaked. - -Another place this helps is if you see that your application is generating -a lot of RAM. Look in @objects.log@ and you'll see right away what is the worst -offending Object. - -Finally, the @threads.log@ will tell you if you're leaking threads. -This happens mostly with people who use IO.popen and don't properly -clean up the results. IO.popen in Ruby threads is very tricky, -and you're better off putting this work into a DRb server anyway. - - -h2. Installing GemPlugins: mongrel_cluster - -Mongrel is extensible via a system called GemPlugins. They -are basically autoloaded RubyGems which you install and are -configured based on how they depend on Mongrel. - -A good example is the @mongrel_cluster@ GemPlugin written -by Bradley Taylor from RailsMachine. It gives you a nice -management system for a cluster of Mongrel servers. This -is very handy when you are running a large scale deployment -and I recommend everyone uses it. - -You install it simply with: - - $ gem install mongrel_cluster - -Once it's installed you can do @mongrel_rails -h@ and it'll -show you the new commands: - -* cluster::configure -- Configures your cluster. -* cluster::restart -- Restarts it. -* cluster::start -- Yep, starts it. -* cluster::stop -- And, yes, stops it. - -You can then pass --help to each one to find out the options -it gets. You then use it like so: - - - $ mongrel_rails cluster::configure -p 8080 -e production -a 127.0.0.1 - $ mongrel_rails cluster::start - $ mongrel_rails cluster::stop - -If you don't like mongrel_cluster (shame on you!) then you can -easily remove it with: - - $ gem uninstall mongrel_cluster - -And all the commands go away. - - -h1. More Documentation - -This should get you started with intermediate Mongrel usage. -There quite a few more documents in the "Documentation":/docs/index.html -section in various states of completion. - -If you'd like to write one of these documents, then join the -"mailing list":http://rubyforge.org/mailman/listinfo/mongrel-users -and volunteer. - - -h1. Credits - -Thanks to "Jamie van Dyke":http://www.fearoffish.com/ and mly on #caboose for correcting some -grammar mistakes. diff --git a/site/src/docs/index.page b/site/src/docs/index.page deleted file mode 100644 index 4638f18..0000000 --- a/site/src/docs/index.page +++ /dev/null @@ -1,104 +0,0 @@ ---- -title: Documentation -inMenu: true -directoryName: Documentation ---- - -h1. Available Documentation - -We've got a small set of documentation to get people going. Most of it is -geared toward Ruby on Rails but other projects using Mongrel should have their -own docs that you can refer to based on these. - -h2. Contributing Documentation - -As you can see many of the pages here are empty. If you'd like to contribute some -documentation then read the "instructions on how to do it":contrib.html and -contact the "mailing list":http://rubyforge.org/mailman/listinfo/mongrel-users -to announce that you'd like to work on something. - -h2. Getting Started - -Start here to get a good grounding in getting Mongrel up and running. These -documents are targeted at developers who will be starting off using Mongrel and -might want to throw in a few little tricks. Serious deployments should check -out *Deployment Best Practices*. - -* "Getting Started":started.html -- Installing and Other things -* "Win32 HOWTO":win32.html -- Specific instructions for running on windows. -* "HOWTO":howto.html -- Doing advanced stuff with Mongrel. -* "Using mongrel_cluster":mongrel_cluster.html -- Nifty plugin for managing your clusters. -* "Choosing A Deployment":choosing_deployment.html -- How to pick a best practice. -* "Security":security.html -- Security issues to look at (for any web application). -* "Frameworks":frameworks.html -- Specific problems and things to know when you run different frameworks. - -h2. Deployment Best Practices - -These documents are continually changing as deploying Mongrel becomes more -solid and certain options and configurations start to work the best. Each one -is a *best practice* which means that if you do something different then you'll -have to do your own research. Best way to work it is to do the *best practice* -exactly as described, then try to do something weird from there. - -* "Apache":apache.html -- The current preferred way to host Mongrel. -* "Litespeed":litespeed.html -- Another good option, but not open source. -* "Lighttpd":lighttpd.html -- Using mod_proxy to do a cluster. -* "Pound":pound.html -- Small scale and dead simple with SSL. -* "Pen or Balance":pen_balance.html -- Smaller scale without SSL. - - -h2. Advanced - -You are a grand master and have answered a few questions on the Mongrel mailing -list so now it's time to get fancy. - -* "Writing Mongrel Plugins":gem_plugin.html -- Writing a GemPlugin for Mongrel. -* "Distributed Worker":distributed_worker.html -- A common pattern for actions that take forever and block Rails. -* "Upload Progress Without Rails":upload_progress.html -- Uploading without blocking Rails and giving the user progress. - - -h2. Ruby API Documentation - -People writing plugins will want these. - -* "Mongrel RDoc":/rdoc/index.html -* "GemPlugin RDoc":/gem_plugin_rdoc/index.html - - -If there's documentation you'd like then feel free to E-mail the list or post -to the tracker. - -h1. Other People's Documentation - -Many other folks have written documentation that they post to their blogs for -people to use. We've based a lot of the documentation here on their writings, -so you should go check out their blogs and shoot them a thanks when you -can. - -* "What About Apache to Mongrel for Rails Applications":http://weblog.textdrive.com/article/219/what-about-apache-to-mongrel-for-rails-applications -* "Apache 2.2 worker on solaris to a remote mongrel":http://weblog.textdrive.com/article/223/apache-22-worker-on-solaris-to-a-remote-mongrel -* "Apache 2.2, mod_proxy_balancer and Mongrel":http://weblog.textdrive.com/article/224/apache-22-mod_proxy_balancer-and-mongrel -* "Scaling Rails with Apache 2.2, mod_proxy_balancer and Mongrel":http://blog.innerewut.de/articles/2006/04/21/scaling-rails-with-apache-2-2-mod_proxy_balancer-and-mongrel -* "Dead Simple Deployment":http://brainspl.at/articles/2006/04/26/dead-simple-deployment -* "Deployment Strategies for Rails on Windows servers":http://www.napcs.com/howto/rails/deploy/ -* "mongrel_cluster-0.1.1: the bird dog (capistrano support!)":http://fluxura.com/articles/2006/04/24/easy-mongrel-clustering-with-mongrel_cluster -* "Easy Mongrel Clustering with mongrel_cluster":http://fluxura.com/articles/2006/05/01/mongrel_cluster-0-1-1-the-bird-dog-capistrano-support - - -h1. Frequently Asked Questions - -When people ask questions really frequently the results end up in the -"FAQ":../faq.html. - -h1. Mailing Lists - -There's a "mailing list":http://rubyforge.org/mailman/listinfo/mongrel-users -that you should subscribe to if you're looking for help or are interested in -tracking Mongrel. We post announcements of pre-release gems you can play with -to this mailing list and also discuss development of Mongrel there. - -Before you start asking for features you should read about -"bikeshedding":http://www.catb.org/jargon/html/B/bikeshedding.html and -understand that we're really nice, but sometimes code speaks better than -rhetoric. - diff --git a/site/src/docs/lighttpd.page b/site/src/docs/lighttpd.page deleted file mode 100644 index 973fd2c..0000000 --- a/site/src/docs/lighttpd.page +++ /dev/null @@ -1,278 +0,0 @@ ---- -title: Lighttpd -inMenu: true -directoryName: Documentation ---- - -*I'm sad to say that I have to recommend people not use lighttpd anymore.* -The author hasn't updated the mod_proxy plugin and isn't providing too much -support for the bugs it has. If you're running lighttpd and you constantly -see 500 errors that are never recovered, then you should switch to Apache -or another web server that can handle properly balancing backends. - - -h1. Using Lighttpd With Mongrel - -It is possible to host an application with just Mongrel since it is -able to serve files like a normal web server. Still, no matter -how fast Mongrel gets it probably can't compete with something -like lighttpd for serving static files. Because of this I've -devised a simple way to setup a lighttpd+Mongrel setup that -demonstrates clustering four Mongrel servers running the same -application as backends. - -This is very similar to a FastCGI or SCGI setup except that -you're just using regular HTTP. Read through the "HOWTO":howto.html -for information on other possible deployment scenarios. - - -h2. The Goal - -What we want to do is put a lighttpd on the internet and then -have it proxy back to one of four Mongrel servers. - -!SimpleLighttpdMongrelSetup.jpg! - -This is actually really trivial and probably doesn't need a diagram -but I got bored just writing it up. - -How it all works is pretty simple: - -# Requests come to the lighttpd server. -# Lighttpd takes each request, and sends it to a backend depending - on how you configure it: - * hash -- Hashes the request URI and makes sure that it goes to the same backend. - * round-robin -- Just chooses another host for each request. - * fair -- "Load based, passive balancing." No idea what that means, but if it's like - the rest of lighttpd it probably means it will overload the first one and if that one's - busy then it starts using the next ones. -# Each backend doesn't really care about any of this since it's just a web server. - - -h2. Lighttpd Configuration - -For lighttpd you need to have *mod_proxy* in your server.modules setting: - - server.modules = ( "mod_rewrite", "mod_redirect", - "mod_access", "mod_accesslog", "mod_compress", - "mod_proxy") - -Then you need to tell lighttpd where the other backends are located: - - proxy.balance = "fair" - proxy.server = ( "/" => - ( ( "host" => "127.0.0.1", "port" => 8001 ), - ( "host" => "127.0.0.1", "port" => 8002 ), - ( "host" => "127.0.0.1", "port" => 8003 ), - ( "host" => "127.0.0.1", "port" => 8004 ) ) ) - -When I used lighttpd 1.4.9 and set proxy.balance="round-robin" I had an excessive number of -500 errors for no real reason. The "fair" setting seems to be the best, but if you -have a large number of fairly random URIs you should try "hash" too. - -*For the rest of this tutorial we'll assume you're running lighttpd on port 80.* - - -h2. Mongrel Configuration - -Mongrel is pretty easy to setup with this configuration on either Win32 or Unix, but -since lighttpd doesn't compile so easily on Win32 I'll just show the Unix method -for starting it: - - $ mongrel_rails start -d -p 8001 \ - -e production -P log/mongrel-1.pid - $ mongrel_rails start -d -p 8002 \ - -e production -P log/mongrel-2.pid - $ mongrel_rails start -d -p 8003 \ - -e production -P log/mongrel-3.pid - $ mongrel_rails start -d -p 8004 \ - -e production -P log/mongrel-4.pid - -Now you should be able to hit your web server at port 80 and it'll run against -one of your four Mongrels. - - -h2. Testing Stability and Performance - -As I mentioned before proxy.balance="round-robin" had many stability issues -in lighttpd 1.4.9 but how did I figure this out? Here's how you can do it. - -You use "httperf":http://www.hpl.hp.com/research/linux/httperf/ to first hit each -Mongrel backend with a large request set. - - $ httperf --port 8001 --server 127.0.0.1 \ - --num-conns 300 --uri /test - $ httperf --port 8002 --server 127.0.0.1 \ - --num-conns 300 --uri /test - $ httperf --port 8003 --server 127.0.0.1 \ - --num-conns 300 --uri /test - $ httperf --port 8004 --server 127.0.0.1 \ - --num-conns 300 --uri /test - -After each of these you're looking for the *Connection rate*, *Request rate*, -*Reply rate*, and *Reply status*. You first look at the *Reply status* to make -sure that you got all 2xx messages. Then look at the other three and make -sure they are about the same. - -Then you hit lighttpd with a similar request set to confirm that it handles the base case. - - $ httperf --port 80 --server 127.0.0.1 \ - --num-conns 300 --uri /test - -You should get no 5xx errors. In the case of round-robin there were about 60% -5xx errors even though the Mongrels were functioning just fine. The "hash" method -didn't improve this test's performance since there's only on URI in the test. It -seems the "fair" method is the best you can do right now. - -Finally you hit lighttpd with a 4x rate to see if it could handle the theoretical limit. - - $ httperf --port 80 --server 127.0.0.1 \ - --num-conns 10000 --uri /test --rate 600 - -It will most likely fail miserably and you'll probably see a few 5xx counts in the -*Reply status* line but that's normal. What you're looking to do is keep moving ---rate and --num-conns up/down until you get where the server is just barely -able to accept the requests without slowing down (i.e. your *Request rate* matches -your --rate setting). There will be a point where adding literally one more -to your --rate setting causes the Request rate to tank. That's your setup's breaking -point and is the actual requests/second you can handle. - - -h1. Insane Caching Power Magnet - -Mongrel (as of 0.3.7) by default supports Rails style page caching -in the RailsHandler it uses to serve your applications. What this -means is that if you do a page cached action (which writes a -.html file as well as respond) then Mongrel will just serve up -the cached page instead of bug Rails. - -This does give you a large boost in performance, but still not nearly -as much as if you had lighttpd doing the caching for you. The optimal -configuration would be where lighttpd checks for cached pages and then -served it directly as it already does with FastCGI. - -There are some technical problems with this and the lighttpd mod_proxy, -but thankfully I don't have to go into them because lighttpd now supports -the "power magnet" and Cache Meta Language (CML). CML is a small bit -of the Lua programming language that lets you script lighttpd and tell -it when to cache or not. The power magnet feature of CML lets you put -all requests through one CML script so that you can determine whether -to cache or not. - -h2. Configuration - -In order to get everything to work right you'll need a few pieces -of equipment and make sure they are enabled in your lighttpd build. -The sample build was done on Debian so that everything would work -including mod_rewrite, mod_memcache, mod_cml, and mod_redirect. - -* lua50, liblua50-dev -* libpcre3-dev -* memcached -* Finally make sure you configure with ./configure --with-lua --with-memcache - -Debian people will need to follow these instructions from -"www.debian-administration.org":http://www.debian-administration.org/articles/20 -for installing from source, and will also need to add these lines to your -/etc/apt/sources.list: - - deb-src http://http.us.debian.org/debian stable main contrib non-free - deb-src http://http.us.debian.org/debian unstable main contrib non-free - deb-src http://non-us.debian.org/debian-non-US stable/non-US main contrib non-free - -And then do the following: - -# Make sure you don't have the source extracted in your current directory. -# apt-get install devscripts debhelper build-essential fakeroot -# apt-get update -# apt-get source lighttpd -# nano -w lighttpd-1.4.10/debian/rules -## DEB_CONFIGURE_EXTRA_FLAGS need have at the end: --with-lua --with-memcache -# nano -w lighttpd-1.4.10/debian/lighttpd.install -## debian/tmp/usr/lib/lighttpd/mod_cml.so needs to be added here. - -Then you're supposed to be able to follow the debian-administration -docs but I haven't got it all working yet. Please clue me in -if you get this compiled on Debian. - -h3. lighttpd.conf - -If it all builds right then you'll be able to use this nifty -CML script that Bradley K. Taylor (from railsmachine.net) came -up with. First you need to tweak your lighttpd.conf at the -place where you have the mod_proxy setup from previous: - - $HTTP["host"] == "www.myhost.come" { - server.document-root = "/my/path/to/app/public" - cml.power-magnet = "/my/path/to/app/config/power-magnet.cml" - proxy.balance = "fair" - proxy.server = ( "/" => ( ( "host" => "127.0.0.1", "port" => 8001 ), - ( "host" => "127.0.0.1", "port" => 8002 ) ) ) - } - -This one just has two for simplicity. The big thing is the -document root setting and the power-magnet.cml setting. I wouldn't -put the power-magnet.cml in your public directory. - -h3. power-magnet.cml - -Now for the magic bit of Lua code that tells lighttpd what to do: - - dr = request["DOCUMENT_ROOT"] - - if file_isreg(dr .. "maintainance.html") then - output_include = { dr .. "maintainance.html" } - return CACHE_HIT - end - - f = request["REQUEST_URI"] - - if f == "/" or f == "" then - file = dr .. "index.html" - elseif not string.find(f, "%.") then -- rewrite for cached pages - file = dr .. f .. ".html" - else - file = dr .. f - end - - if file_isreg(file) then - output_include = { file } - return CACHE_HIT - end - - return 1 -- should be CACHE_MISS, but there's a bug in 1.4.10 - -Place this in the /my/path/to/app/config/power-magnet.cml like you -configured above. - -Now if you restart lighttpd and everything worked right you should -be able to see the headers and tell if Mongrel or lighttpd is serving -them. Use curl like this: - - curl -I http://zedapp.railsmachine.net/ - curl -I http://zedapp.railsmachine.net/admin - -The second one should redirect and show a Mongrel header while the -first one should show a lighttpd header. - - -h2. Memcached - -The next installment of this document will tell you how to setup a -memcached so that you can run the lighttpd on a different server -from the Mongrel cluster. Right now they all have to reside -on one machine. - -h2. CML Tricks - -Since Lua is a full blown and fast little language -you can get pretty creative with it. For example you could -have it check dates and times of files, look for processes -that should be running, run commands, check the contents of -a file, etc. - -Take a look at the "Lua Reference Manual":http://www.lua.org/manual/5.0/ -to see what it can do. Ruby people will probably like Lua. - - - diff --git a/site/src/docs/litespeed.page b/site/src/docs/litespeed.page deleted file mode 100644 index bf8c3e2..0000000 --- a/site/src/docs/litespeed.page +++ /dev/null @@ -1,84 +0,0 @@ ---- -title: LiteSpeed -inMenu: true -directoryName: LiteSpeed ---- - -h1. LiteSpeed Best Practice Deployment - -h3. by "Alison Rowland":http://blog.alisonrowland.com - -LiteSpeed makes setting up a reverse proxy to Mongrel a snap with its excellent, web-based control panel. LiteSpeed has a built-in load balancer, so it also works well in conjunction with the "Mongrel_Cluster":mongrel_cluster.html plugin. - -h2. Requirements - -These instructions assume you have already completed the following steps: - -* installed the LiteSpeed Webserver, version 2.1.16 or greater[1] (note: not available for Windows), -* set up your application as a virtual host[2], -* installed and configured Mongrel, -* and confirmed that you can start Mongrel and access your app by appending Mongrel's port number to your domain (e.g. mysite.com:8000). - -If you've done all that, then continue reading! - -h2. Configuring Mongrel as an External App - -# Enter your LiteSpeed Administration Panel (usually yourdomain:7080). -# Go to *Server Configuration*. -# Select your app under *Virtual Hosts* in the sidebar at left. -# Go to the *External Apps* tab and click *Add*. -# Choose *Web Server* for the *Type* and click *Next*. - -Fill in the following fields: - -* *Name*: Give this instance of Mongrel a name, such as @myapp-1@. -* *Address*: This should be @127.0.0.1:XXXX@, where @XXXX@ is the port number your mongrel instance is running on. - -The other fields are up to you. Here are some values to start you off with a workable setup: - -* *Max Connections*: 20 -* *Connection Keepalive Timeout*: 1000 -* *Environment*: __leave blank__ -* *Initial Request Timeout (secs)*: 1 -* *Retry Timeout (secs)*: 0 -* *Response Buffering*: No - -Finally, click *Save*. If you're only running a single instance of Mongrel, skip down to the instructions on *Configuring a Context.* Otherwise, read on. - -h2. Load Balancing across Multiple Mongrel Instances - -If you're running more than one instance of Mongrel, or are using Mongrel_Cluster, you'll need to repeat the above directions for every instance of Mongrel, changing the name and port number as appropriate for each. Next, you need to set up a load balancer. - -# Back on the *External Apps* tab, click *Add*. -# Choose *Load Balancer* for *Type* and click *Next*. -# Give it a *Name*, such as @MyApp@ -# In the *Workers* field, enter all of the mongrel instances you set up, using the names you gave them, like so:
-@proxy::myapp-1, proxy::myapp-2, proxy::myapp-3@ -# *Save*. - -h2. Configuring a Context - -Configuring a context prevents LiteSpeed from displaying Mongrel's port number in the URL. - -# Go to your virtual host's *Context* tab, and click *Add*. -# If you're set up to run on just a single Mongrel instance, select *Proxy*. Otherwise, select *Load Balancer*. -# Enter @/@ in *URI*. -# Make sure your *Web Server* or *Load Balancer* is selected in the next field's drop-down menu. -# The other settings are up to you. Most can be left blank. -# *Save*. - -h2. Finishing Up - -The only thing left is to make sure Mongrel is fired up, and, in your LiteSpeed admin panel, click *Apply Changes*, then *Graceful Restart*. You should be good to go! - - -h2. References - -Thanks go to Bob Silva[2] and Rick Olson[3], for their trailblazing articles on LiteSpeed deployment for Rails. - -fn1. "LiteSpeed Technologies":http://litespeedtech.com - -fn2. "Launching Rails at the Speed of Lite with LiteSpeed Webserver":http://www.railtie.net/articles/2006/01/21/up-and-running-in-the-speed-of-light - -fn3. "Setting up LiteSpeed with Mongrel":http://weblog.techno-weenie.net/2006/4/11/setting-up-litespeed-with-mongrel - diff --git a/site/src/docs/mongrel_cluster.page b/site/src/docs/mongrel_cluster.page deleted file mode 100644 index 4893206..0000000 --- a/site/src/docs/mongrel_cluster.page +++ /dev/null @@ -1,138 +0,0 @@ ---- -title: mongrel_cluster -inMenu: true -directoryName: mongrel_cluster ---- - -h1. Using Mongrel Cluster
-by Austin Godber - -"Mongrel_cluster":http://rubyforge.org/projects/railsmachine/ is a -"GemPlugin":http://mongrel.rubyforge.org/gem_plugin_rdoc that wrappers -the mongrel HTTP server and simplifies the deployment of webapps -using a cluster of mongrel servers. Mongrel_cluster will conveniently configure -and control several mongrel servers, or groups of mongrel servers, which are -then load balanced using a reverse proxy solution. Typical load balancing -reverse proxies include: -* "Apache":apache.html - flexible and complex -* "Lighttpd":lighttpd.html - development has stalled -* "Pound":pound.html - Simple and SSL capable -* "Pen/Balance":pen_balance.html - Simple - -h2. Requirements - -Throughout these instructions we will assume the following: -* All mongrel instances are running on the same machine -* Mongrel *0.3.13* or greater -* "Mongrel_cluster":http://rubyforge.org/projects/railsmachine/ *0.2.0* or greater -* Linux platform (Centos 4.3 in this case, so you will see RedHat like commands). -* You have *sudo* or *root* access - -h2. Preliminary steps - -In general, when deploying a mongrel cluster, none of the mongrel servers will -be listening on a privileged port. This is nice, we don't have to run mongrel as -root, therefore we should create a user for mongrel to run as: -

-  $ sudo /usr/sbin/adduser -r mongrel
-
-For the purpose of this example we will just use a freshly minted rails app. -You can adjust these instructions to work with your app, wherever you may have -placed it but lets pretend we are working in */var/www/apps*. So lets go set -up our app and test that mongrel will serve it: -

-  $ cd /var/www/apps
-  $ rails testapp
-  $ cd testapp
-  $ mongrel_rails start
-
-You should now be able to see your application at @http://host:3000/@. If you -can, you are good to go. Hit @CTRL+C@ to stop the mongrel server. At a minimum -the log directory of your app has to be writable by the *mongrel* user: -

-  $ sudo chown -R mongrel:mongrel /var/www/apps/testapp
-
- -h2. Mongrel Cluster Setup - -With mongrel working and our webapp directory prepared we can proceed with the -mongrel_cluster configuration step: -

-  $ sudo mongrel_rails cluster::configure -e production \
-    -p 8000 -N 3 -c /var/www/apps/testapp -a 127.0.0.1 \
-    --user mongrel --group mongrel 
-
-This will write a configuration file in *config/mongrel_cluster.yml*. We have -setup to run our cluster in production mode as the user *mongrel* and will start -3 mongrel servers listening on ports 8000, 8001, and 8002. Now, lets do a quick -test of what we have setup so far: -

-   $ sudo mongrel_rails cluster::start
-
-Checking our host on ports 8000, 8001, and 8002 we should now be able to see our -test application. We can stop all of those mongrels with -@sudo mongrel_rails cluster::stop@. - -h2. On Boot Initialization Setup - -At this point, mongrel and mongrel_cluster are setup and working with our sample -webapp. Ultimately, we want this cluster to start on boot. Fortunately, -mongrel_cluster comes with an init script that we can just drop into place. All -we need to do is put the configuration files in */etc/mongrel_cluster* and take care of -a few system tasks: -

-  $ sudo mkdir /etc/mongrel_cluster
-  $ sudo ln -s /var/www/apps/testapp/config/mongrel_cluster.yml \
-    /etc/mongrel_cluster/testapp.yml
-  $ sudo cp \
-    /path/to/mongrel_cluster_gem/resources/mongrel_cluster \
-    /etc/init.d/
-  $ sudo chmod +x /etc/init.d/mongrel_cluster 
-
-Now we have a typical System V init script that will launch our mongrel cluster. -Actually, this script will launch any cluster that has a configuration file in -*/etc/mongrel_cluster/*. So when we run */etc/init.d/mongrel_cluster start* it -will start all clusters. Likewise for stop and restart. If we are using a -RedHat like system we can configure mongrel_cluster for startup: -

-  $ sudo /sbin/chkconfig --level 345 mongrel_cluster on
-
-For users of Debian, you can use this command to install the script: -

-  $ sudo /usr/sbin/update-rc.d -f mongrel_cluster defaults
-
-*NOTE* At this point there are a few issues with this init script that only apply -under certain circumstances. Those issues include: - -* *Shebang line* - The init script uses *#!/usr/bin/env ruby* to find the -appropriate interpreter. Some distribution installs of ruby only give you a -/usr/bin/ruby1.8. You may change the shebang line or simply create a symbolic -link from /usr/bin/ruby1.8 to /usr/bin/ruby[3]. -* *mongrel_cluster_ctl location* - If you have installed your gems in -/usr/local/ you may find that the init script can not find mongrel_cluster_ctl. -To resolve this, you can symbolically link /usr/local/bin/mongrel_cluster_ctl into -/usr/bin/ - -h2. Conclusion - -We have configured mongrel and mongrel_cluster with our webapp and setup -mongrel_cluster to run our cluster at startup. What's missing? Well, unless -your application users expect to have to connect to ports 8000-8002 you had best -check out the reverse proxy options listed above. - -The process of setting up mongrel_cluster will be the same for all of the -reverse proxy deployment options. So this document will likely serve as a reference -for several of the other deployment guides. - -
- -fn1. Thanks to "Bradley Taylor":http://fluxura.com/ for writing -mongrel_cluster and recent improvements in its startup capabilities. The -following people have provided valuable feedback on this document: Alison Rowland. - -fn2. @adduser -r@ is a RedHat-centric way of creating a system account. For -Debian-ish distributions replace that with @adduser --system mongrel@. - -fn3. If you have this problem, you will probably discover other ruby related -executables are also missing. You may want to link irb1.8 and ri1.8 as well, -though only /usr/bin/ruby is necessary for this init script. diff --git a/site/src/docs/osx.page b/site/src/docs/osx.page deleted file mode 100644 index 4a4feba..0000000 --- a/site/src/docs/osx.page +++ /dev/null @@ -1,124 +0,0 @@ ---- -title: OSX -inMenu: true -directoryName: OSX ---- -h1. OS X + Ruby on Rails + Mongrel + MySQL in 15 minutes - -*by "Elliott Hird":http://elliotthird.org/* - -Most tutorials about this seem to involve either manually compiling everything or they take some totally unneccesary long-winded detour. But it's really easy. - -Anyway, let's get started. - -h2. Installing MacPorts - -_(If you already have MacPorts installed, you can skip this step.)_ - -You'll be able to follow "this tutorial":http://trac.macosforge.org/projects/macports/wiki/InstallingMacPorts for the most part, but skip installing X11. - -_Disclaimer: The time spent installing MacPorts does not add up to the time spent following this tutorial. Yes, I cheated._ - -h2. Installing Ruby - -Well, technically, you already have ruby. Look: -
-$ ruby -v
-ruby 1.8.2 [stuff follows]
-
- -_(The version number may be different for you.)_ - -But depending on what OS X version you're on, it's either broken or outdated. Let's get a working copy of 1.8.5. Fire up your "terminal of choice":http://iterm.sourceforge.net/ and install ruby: -
-$ sudo port install ruby
-[lots of text showing macports compiling things]
-
-That was easy, wasn't it? - -h2. Installing RubyGems (these titles have very little variation) - -Grab the latest RubyGems version from "here":http://rubyforge.org/frs/?group_id=126 (grab either the .tgz or .zip version, either is fine but the .tgz is smaller) and extract it to wherever you want (in Tiger, just double click on it). - -Open your terminal of choice and install it: -
-$ cd ~/Desktop/rubygems-0.9.0
-$ sudo ruby install.rb
-[things]
-
-Hopefully that worked. If it didn't, well then, I can't help you. Ask somebody else. - -h2. Did that work? - -Now simply type: -
-$ gem
-[boring usage instructions]
-
-Yay! RubyGems works (again, if it doesn't, I have no idea what's wrong). - -h2. Installing Rails - -Now: -
-$ sudo gem install rails --include-dependencies
-
-After a few minutes, it should dump you back to the prompt without errors. Make sure it works: -
-$ rails
-
-If you want to update rails to the latest (at the time of writing) release candidate of 1.2, see the last section. For now, just wait. - -h2. MySQL! - -You might think MySQL, being a big bloated thing, would take all day to compile. Not so - it only took about 2 minutes for me. Your mileage may vary. -
-$ sudo port install mysql +server
-
-Note the server variant is selected by using +server. This is required, so just leave it, mmkay? - -After compiling and installing all that, it should give you a notice about how to start MySQL at startup. I highly reccomend doing this, it doesn't make startup any slower. - -If you've told MySQL to start at bootup, reboot now. I'll wait for you. - -h2. Add some Mongrel to the mix - -This one is simple. -
-$ sudo gem install mongrel --include-dependencies
-
-Choose the first one and wait for it to install. - -h2. Testing it out - -Alright then. -
-$ cd ~/Code
-$ rails test
-$ cd test
-$ mongrel_rails start
-
-If all goes well Mongrel should start up. To test it, "load this":http://localhost:3000. If you see the Rails welcome screen - you're done! - -h2. That's All, Folks! - -No, really. - -Actually, that was a bit more than 15 minutes, wasn't it? Oh well. - -h2. Additional things - -These aren't neccesary, but some people like to do them. - -h3. Updating Rails to 1.2rc1 - -This one is easy. -
-$ gem update rails --source http://gems.rubyonrails.org/
---include-depdendencies
-
- -h3. Securing MySQL - -By default, nobody except localhost can access MySQL, but it allows any user to login (although they can't do anything) and root has no password. I don't see this as a problem since nobody that isn't at your computer can take advantage of this and it's development anyway, but if you want to secure it you're on your own. - diff --git a/site/src/docs/pen_balance.page b/site/src/docs/pen_balance.page deleted file mode 100644 index 1799c0f..0000000 --- a/site/src/docs/pen_balance.page +++ /dev/null @@ -1,57 +0,0 @@ ---- -title: Pen/Balance -inMenu: true -directoryName: Pen/Balance ---- - -h1. Pen/Balance Best Practice Deployment - -Using "Pen":http://siag.nu/pen/ or "Balance":http://www.inlab.de/balance.html to serve -a cluster of Mongrel servers is a simple way to get good concurrency without -going wild on your deployment complexity. What these two programs do is listen on one -port and then proxy the requests to one of the Mongrel servers in your cluster. - -h2. Requirements - -First up, you should learn to use "mongrel_cluster":/docs/mongrel_cluster.html to manage -a cluster of Mongrel servers. It's a simple GemPlugin that simplifies things and also -works better with Capistrano. - -Second, you need to install wither Pen or Balance. Either use your package management -system or install from source. - -Finally, you probably can't do this on win32 unless you use Cygwin. - -h2. Pen - -Once you get Pen installed you just use it like this: - -# Make sure that you can run your application like normal and then -setup "mongrel_cluster":/docs/mongrel_cluster.html so that all of the running Mongrels work. -# Run this command: pen -H 4000 localhost:3000 localhost:3001 -# Check port 4000 to make sure that Pen is proxying correctly. - -As with the Balance instructions below you'll want to create a start-up script so that -Pen gets started on machine reboots. The -H adds a "X-Forwarded-For" header to the -request, which helps if you need to track the client's IP address. There's plenty -of other options for pen as well. - -NOTE: Pen has experimental support for SSL. Try it out if you need SSL. - -h2. Balance - -Balance is pretty simple: - -# Make sure that you can run your application like normal and then -setup "mongrel_cluster":/docs/mongrel_cluster.html so that all of the running Mongrels work. -# Run this command: balance 4000 localhost:3001 localhost:3002 ... -# Hit port 4000 with a browser to see if it's working. - -That's all there is to it. You might want to write a little start-up script that -starts balance on machine reboots. Balance has many other options available if -you need to do more complex stuff, but this is usually all people need. - -h2. Limitations - -We found that Balance has an upper limit of 15 backend servers. I haven't heard much -about Pen, but it's experimental SSL support is interesting. diff --git a/site/src/docs/pound.page b/site/src/docs/pound.page deleted file mode 100644 index a4e166b..0000000 --- a/site/src/docs/pound.page +++ /dev/null @@ -1,148 +0,0 @@ ---- -title: Pound -inMenu: true -directoryName: Pound ---- - -h1. Pound Best Practice Deployment
-By Austin Godber - -"Pound":http://www.apsis.ch/pound/ is a load-balancing reverse HTTP proxy. It -can also handle SSL connections. Pound, itself, does not serve content but -just acts as a front end to servers that do. In this case pound will sit in -front of a cluster of mongrel servers. This arrangement is similar to that -illustrated on the "Using Lighttpd with Mongrel":lighttpd.html page, except -pound replaces lighttpd. - -h2. Requirements - -We assume that the following: - -* Pound and the mongrel cluster are running on the same machine[1]. -* *Pound 2.0.4* is built and installed, including SSL support if desired. -* The *mongrel* gem is installed. -* The *mongrel_cluster* gem is installed. - -These instructions were performed on CentOS 4.3 using Ruby 1.8.4 from the -CentOS 4 test repository. They should apply on other Linux distributions. -They may work for other OSes, but please see the "pound -website":http://www.apsis.ch/pound/ for additional information. - -h2. Mongrel Cluster Setup - -First we need to prepare our rails application to run in a mongrel cluster. In -this example we will use mongrel_cluster to run three mongrel instances on -ports 8000, 8001, and 8002. We then launch the mongrel cluster: - - $ cd railsapp/ - $ mongrel_rails cluster::configure -p 8000 -N 3 - $ mongrel_rails cluster::start - -We should now have three instances of our rails app running on ports 8000, -8001, and 8002. - -h2. Configuring Pound - -Now we configure pound to proxy requests to the rails cluster we just created. -We will configure pound to accept both HTTP and HTTPS traffic on ports 80 and -443 respectively. Pound will then proxy requests to the *Service*s listed in -the configuration file. Our configuration file (/usr/local/etc/pound.cfg) -looks like this: - -
-
-ListenHTTP
-  Address 0.0.0.0
-  Port    80
-  Service
-    BackEnd
-      Address 127.0.0.1
-      Port    8000
-    End
-    BackEnd
-      Address 127.0.0.1
-      Port    8001
-    End
-    BackEnd
-      Address 127.0.0.1
-      Port    8002
-    End
-  End
-End
-
-ListenHTTPS
-  Address 0.0.0.0
-  Port    443
-  Cert    "/usr/local/etc/test.pem"
-  # pass along https hint
-  AddHeader "X-Forwarded-Proto: https"
-  HeadRemove "X-Forwarded-Proto"
-  Service
-    BackEnd
-      Address 127.0.0.1
-      Port    8000
-    End
-    BackEnd
-      Address 127.0.0.1
-      Port    8001
-    End
-    BackEnd
-      Address 127.0.0.1
-      Port    8002
-    End
-  End
-End
-
-
- -Before starting pound, we need to make sure our SSL certificate is present. If -not we can quickly generate a test certificate: - - $ openssl req -x509 -newkey rsa:1024 -keyout test.pem \ - -out test.pem -days -nodes - -It should now be safe to start pound: - - $ sudo pound -f /usr/local/etc/pound.cfg - -Our Rails application should now be available at http://127.0.0.1/ and https://127.0.0.1/ . - -h2. Testing SSL in Rails - -The line @AddHeader "X-Forwarded-Proto: https"@ in the ListenHTTPS section -tells pound to add a header to the request as it is passed back to the mongrel -servers[2]. This will tell the rails application that the request was -originally an SSL request. We can test this with the following simple Rails -controller, app/controller/test_controller.rb: - -
-
-class TestController < ApplicationController
-  def index
-    @sslyn = request.ssl?
-  end
-end
-
-
- -And the accompanying view, app/views/test/index.rhtml: - -
-

test

-SSL: < %= @sslyn %> -
- -Visiting @http://127.0.0.1/Test/@ should show @SSL: false@ while visiting -@https://127.0.0.1/Test/@ should return @SSL: true@. - -h2. Building Pound on OSX - -OSX has specific problems when building pound, but you can follow "Trotter Cashion's":http://lifecoding.com/blog/?p=29 -to get everything working. - -
- -fn1. It is not required that pound run on the same machine as the mongrel -servers. It was just chosen for this example. - -fn2. Thanks to Joshua Harvey's post on the Mongrel mailing list for this fix. diff --git a/site/src/docs/security.page b/site/src/docs/security.page deleted file mode 100644 index 2781b12..0000000 --- a/site/src/docs/security.page +++ /dev/null @@ -1,94 +0,0 @@ ---- -title: Security -inMenu: true -directoryName: Security ---- - -h1. Web Application Security Issues - -Mongrel takes a different approach to security than most web servers. Rather than -relying on massive human efforts to audit all possible code, Mongrel is implemented -using algorithms and methods that are difficult to subvert. There is still auditing -and checks, but Mongrel simply tries to avoid errors by not doing things that cause them. - -Read the "Iron Mongrel Security page":/security.html for information on how security -is done in Mongrel. The main points to remember with Mongrel's security are: - -* Mongrel uses a "Ragel":http://www.cs.queensu.ca/home/thurston/ragel/ generated parser -instead of a hand coded HTTP handler. The grammar is very close to the ABNF specification, so -if you see "BAD CLIENT" errors in your logs, that probably is a bad client. -* Security tests have found that Mongrel stops most security attacks at the protocol level due to -it's correctly written parser *and* it's explicit limits on the sizes of everything. -* The Mongrel reaction to a protocol violation is to close the socket immediately. It doesn't waste -time and resources on bad clients since this is *always* a hack attempt. If it isn't then it's a -poorly written client and the author should learn to write a correct one. -* Mongrel works with all the main clients out there, and ones it doesn't work with are crap living -in a tiny tiny niche of the internet designed by horrible programmers. -* While Mongrel is more strict than other servers, it isn't draconian. The clients that can't get -through are typically skating on the edge of the HTTP grammar where they do not belong. - -Mongrel isn't infallible, but if Mongrel complains about something then you should investigate it. -If you think Mongrel is wrong then shoot a message to the mailing list detailing what it should do -and we'll consider adjusting the grammar. If you think Mongrel should violate the grammar so that -your little WebDAV++ Social Network Bookmark Chat Web 2.0 monstrosity can see the light of day, then -you "should write your own web server":/not_mongrel.html instead. - -h2. Learning About Web Application Security - -You should read the "OWASP":http://www.owasp.org/index.php/Main_Page document -"Top Ten Project":http://www.owasp.org/index.php/OWASP_Top_Ten_Project for information on -the big security risks and how to avoid them. The summary of these is: - -* Unvalidated Input -* Broken Access Control -* Broken Authentication And Session Management -* Cross Site Scripting -* Buffer Overflow -* Injection Flaws -* Improper Error Handling -* Insecure Storage -* Application Denial Of Service -* Insecure Configuration Management - -Many of these errors depend on how you write your application and have little to do with Mongrel. -The two that relate the most to Mongrel are *Buffer Overflows* and *Application Denial of Service*. - - -h2. Buffer Overflows - -Mongrel is doing some heavy C buffer thrashing internally, but several controls are in place to make -sure that things stay safe: - -* Pointers are checked with asserts and if statements to test if there's been a buffer overflow. -* Ragel generates a safe state machine that is accurate to the byte level. -* There are none of the "unsafe" string handling functions except for where absolutely necessary, and -that one spot is checked heavily. -* Input is limited to maximum sizes--which also helps prevent denial of service. - - -h2. Application Denial of Service - -Normally this is things like using algorithms in your application that make it easy for -someone to take down your application with simple queries. A good example is a SQL database -query that when given the right inputs takes forever. It only takes a few of these to -destroy your application's response time. - -Mongrel helps with Denial of Service by doing the following things: - -* Mongrel strict parser boots clients immediately to save on resources and time. -* Mongrel boots clients that go over the (generous) size limits for input. -* When Mongrel gets overloaded it starts denying clients and then finds existing -requests that are taking to long and kills them. It is pretty conservative about this, but -you can use options to tune it more or less severe. -* Mongrel is already using pure HTTP so there's plenty of tools available to help you. -* It's designed to be as efficient as possible, but this has limits because of Ruby. - -Don't count on Mongrel to suddenly make your Rails application withstand a Russian -DOS blackmail operation though. It works hard to prevent DOS potential, but there's only -so much it can do. - -If you're very serious about security then you should check out "mod_security":http://www.modsecurity.org/ -which is an Apache module that has lots of active prevention of such things. It can stop many web -scanner attacks, DOS attempts, and other security attempts. It does slow your server down, but it's -probably worth it if you have something valuable. - diff --git a/site/src/docs/started.page b/site/src/docs/started.page deleted file mode 100644 index 5c6f23c..0000000 --- a/site/src/docs/started.page +++ /dev/null @@ -1,83 +0,0 @@ ---- -title: Getting Started -inMenu: true -directoryName: Documentation ---- - -h1. Getting Started - -The easiest way to get started with Mongrel is to install it via RubyGems -and then run a Ruby on Rails application. You can do this easily: - - $ sudo gem install mongrel - $ cd myrailsapp - $ mongrel_rails start -d - -Which runs Mongrel in the background. You can stop it with: - - $ mongrel_rails stop - -And you're all set. There's quite a few options you can set for the -start command. Use the *mongrel_rails start -h* to see them all. - - -h2. Win32 Install - -Windows has a slight difference since it seems that the win32-service doesn't -get picked up for some people as a dependency. You'll need to do this instead: - - $ gem install win32-service (pick the most recent one) - $ gem install mongrel (pick the win32 pre-built) - $ gem install mongrel_service - -Now you're installed. "Read the Win32 HOWTO for more instructions.":win32.html - - -h2. Updating - -You should be able to do an *gem update* and get the latest version of Mongrel -on any platform you've already installed it on. The caveat to this is if -you've been grabbing test releases from any of the authors directly then -you'll need to *gem uninstall* first to make sure you don't have any buggy -stuff lying around. - - -h1. Help For Commands - -Mongrel uses a fairly comprehensive command/plugin system (documented in the near -future) that has built-in help thanks to optparse. Just pass a -h to any -command and it will dump the help for you: - - $ mongrel_rails start -h - -Also every option has reasonable default options, and will complain if you give -anything invalid. - -See the "HOWTO":howto.html for information on each option and what -it does. - -h1. Running In Development - -Mongrel turns out to be really nice for development since it serves files -much faster than WEBrick. I'm using it for almost all my development Ruby -on Rails work these days. What I do is the following: - - $ mongrel_rails start - -And then do my work like normal with WEBrick. You don't get all the logging -and stuff you get with WEBrick (planned for a future release) but otherwise -it's nice and snappy. - - -h1. More Information - -There's a "mailing list":http://rubyforge.org/mailman/listinfo/mongrel-users that -you should subscribe to if you're looking for help or are interested in tracking -Mongrel. We post announcements of pre-release gems you can play with to this -mailing list and also discuss development of Mongrel there. - -Before you start asking for features you should read about -"bikeshedding":http://www.catb.org/jargon/html/B/bikeshedding.html and -understand that we're really nice, but sometimes code speaks better than rhetoric. - -Finally there's lots of other "documentation.":index.html diff --git a/site/src/docs/upload_progress.page b/site/src/docs/upload_progress.page deleted file mode 100644 index b40eaef..0000000 --- a/site/src/docs/upload_progress.page +++ /dev/null @@ -1,136 +0,0 @@ ---- -title: Upload Progress -inMenu: true -directoryName: Upload Progress ---- - -h1. Mongrel Upload Progress Plugin - -One of the really nice things about Mongrel is its simplicity. It's very easy -for someone to take and extend for their own needs. The Mongrel Upload -Progress plugin is an example of how I'm able to extend the Mongrel HTTP -Request object and provide near-realtime progress updates. - -The reason why this is a challenge, is because web servers usually gather the -HTTP request, send it on to the web framework, and wait on a response. This is -fine for most requests, because they're too small to cause an issue. For large -file uploads this is a usability nightmare. The user is left wondering what -whether their upload is going through or not. - -To do this, I've written a Mongrel handler that hooks into some basic Request -callbacks. To use it, you need to install the gem, and create a small config -file for it: - -
gem install mongrel_upload_progress
-
-# config/mongrel_upload_progress.conf
-uri "/", 
-  :handler => plugin("/handlers/upload", :path_info => '/files/upload'), 
-  :in_front => true
-
-# start mongrel
-mongrel_rails start -d -p 3000 -S config/mongrel_upload_progress.conf
-
- -That config file tells mongrel to load the Upload handler in front of all other -handlers. :path_info is passed to it, telling upload_progress to -only watch the /files/upload action. There are two more parameters that I'll -get into later: :frequency and :drb. I'm using Rails -as an example, but this should work with any Ruby framework, such as Camping or -Nitro. - -Now that Mongrel is set up, let's create a "basic upload -form":/docs/upload_progress_form.rhtml. If you -look closely you'll notice a few things: - -* A unique :upload_id parameter must be sent to the upload_progress handler. This is so requests don't get mixed up, and the client page has an ID to query with. -* The <form> tag is targetted to an iFrame to do the uploading. Certain browsers (like Safari) won't execute javascript while a request is taken place, so this step is necessary. -* There is a little "javascript library":/docs/upload_progress_javascript.js being used. This handles the polling and status bar updates. -* Notice the form's action is file/upload, just like the upload_progress handler. - -The "Rails controller -actions":/docs/upload_progress_rails.rb for this are very -simple. The upload form itself needs no custom code. The upload action only -renders javascript to be executed in the iFrame, to modify the contents of the -parent page. The progress action is a basic RJS action that updates the -current status. Most of the guts of this are implemented in the javascript -library. - -Here's what happens when you submit the form: - -* The UploadProgress class creates a PeriodicalExecuter and gets ready to poll. -* The browser initiates the upload. -* Every 3 seconds, the PeriodicalExecuter calls the RJS #progress action and gets back the current status of the file. -* Once finished, the iFrame calls window.parent.UploadProgress.finish(), which removes the status bar and performs any other finishing actions. - -How's this work with a single Mongrel process if "Mongrel synchronizes Rails -requests":http://david.planetargon.us/articles/2006/08/08/why-you-need-multiple-mongrel-instances-with-rails? -It's actually very careful about locking, synchronizing only the bare minimum. -The whole time that Mongrel is receiving the request and updating the progress -is spent _in_ Mongrel, so it can happily serve other requests. This is how the -RJS action is able poll while it's uploading. - -This is fine and dandy, but not too many sites run on a single Mongrel. You'll -quickly run into problems with multiple mongrels since only one Mongrel process -knows about the upload. You'll either have to specify a specific mongrel port -to communicate with, or set up a dedicated mongrel upload process. The third -option, is use DRb. - -
# config/mongrel_upload_progress.conf
-uri "/", 
-  :handler => plugin("/handlers/upload", 
-    :path_info => '/files/upload', 
-    :drb => 'druby://0.0.0.0:2999'), 
-  :in_front => true
-
-# lib/upload.rb, the upload drb server
-require 'rubygems'
-require 'drb'
-require 'gem_plugin'
-GemPlugin::Manager.instance.load 'mongrel' => GemPlugin::INCLUDE
-DRb.start_service 'druby://0.0.0.0:2999', Mongrel::UploadProgress.new
-DRb.thread.join
- -Now in addition to starting mongrel, you'll need to start the DRb service too: - -
ruby lib/upload.rb
- -The Rails app should work the same as before, but now it is using a shared DRb -instance to store the updates. This gives us one other advantage: a console -interface to the current uploads. - -
# lib/upload_client.rb, a simple upload drb client
-require 'drb'
-DRb.start_service
-
-def get_status
-  DRbObject.new nil, 'druby://0.0.0.0:2999'
-end
-
-# typical console session
-$ irb -r lib/upload_client.rb
->> uploads = get_status
->> uploads.list
-=> []
-# start uploading in the browser
->> uploads.list
-=> ["1157399821"]
->> uploads.check "1157399821"
-=> {:size=>863467686, :received=>0}
- -Using DRb gives you a simple way to monitor the status of current uploads in -progress. You could also write a simple web frontend for this too, accessing -the DRb client with Mongrel::Uploads. - -One final note is the use of the :frequency option. By default, - the upload progress is marked every three seconds. This can be modified - through the mongrel config file: - -
uri "/", 
-  :handler => plugin("/handlers/upload", 
-    :path_info => '/files/upload', 
-    :frequency => 1,
-    :drb => 'druby://0.0.0.0:2999'), 
-  :in_front => true
- - diff --git a/site/src/docs/upload_progress_form.rhtml b/site/src/docs/upload_progress_form.rhtml deleted file mode 100644 index 8a9b675..0000000 --- a/site/src/docs/upload_progress_form.rhtml +++ /dev/null @@ -1,53 +0,0 @@ - - - - mongrel test - <%= javascript_include_tag :defaults %> - - - - -

<%= link_to (@upid = Time.now.to_i.to_s), :action => 'status', :upload_id => @upid %>

-<%= start_form_tag({:action => 'upload', :upload_id => @upid}, {:multipart => true, :target => 'upload', - :onsubmit => "UploadProgress.monitor('#{escape_javascript @upid}')"}) %> -
-

<%= file_field_tag :data %>

-
-

<%= link_to_function 'Add File Field', 'UploadProgress.FileField.add()' %> -

-

<%= submit_tag :Upload %>

- - -
-
- - - - - diff --git a/site/src/docs/upload_progress_javascript.js b/site/src/docs/upload_progress_javascript.js deleted file mode 100644 index 6fbc51f..0000000 --- a/site/src/docs/upload_progress_javascript.js +++ /dev/null @@ -1,113 +0,0 @@ -var UploadProgress = { - uploading: null, - monitor: function(upid) { - if(!this.periodicExecuter) { - this.periodicExecuter = new PeriodicalExecuter(function() { - if(!UploadProgress.uploading) return; - new Ajax.Request('/files/progress?upload_id=' + upid); - }, 3); - } - - this.uploading = true; - this.StatusBar.create(); - }, - - update: function(total, current) { - if(!this.uploading) return; - var status = current / total; - var statusHTML = status.toPercentage(); - $('results').innerHTML = statusHTML + "
" + current.toHumanSize() + ' of ' + total.toHumanSize() + " uploaded."; - this.StatusBar.update(status, statusHTML); - }, - - finish: function() { - this.uploading = false; - this.StatusBar.finish(); - $('results').innerHTML = 'finished!'; - }, - - cancel: function(msg) { - if(!this.uploading) return; - this.uploading = false; - if(this.StatusBar.statusText) this.StatusBar.statusText.innerHTML = msg || 'canceled'; - }, - - StatusBar: { - statusBar: null, - statusText: null, - statusBarWidth: 500, - - create: function() { - this.statusBar = this._createStatus('status-bar'); - this.statusText = this._createStatus('status-text'); - this.statusText.innerHTML = '0%'; - this.statusBar.style.width = '0'; - }, - - update: function(status, statusHTML) { - this.statusText.innerHTML = statusHTML; - this.statusBar.style.width = Math.floor(this.statusBarWidth * status); - }, - - finish: function() { - this.statusText.innerHTML = '100%'; - this.statusBar.style.width = '100%'; - }, - - _createStatus: function(id) { - el = $(id); - if(!el) { - el = document.createElement('span'); - el.setAttribute('id', id); - $('progress-bar').appendChild(el); - } - return el; - } - }, - - FileField: { - add: function() { - new Insertion.Bottom('file-fields', '

x

') - $$('#file-fields p').last().visualEffect('blind_down', {duration:0.3}); - }, - - remove: function(anchor) { - anchor.parentNode.visualEffect('drop_out', {duration:0.25}); - } - } -} - -Number.prototype.bytes = function() { return this; }; -Number.prototype.kilobytes = function() { return this * 1024; }; -Number.prototype.megabytes = function() { return this * (1024).kilobytes(); }; -Number.prototype.gigabytes = function() { return this * (1024).megabytes(); }; -Number.prototype.terabytes = function() { return this * (1024).gigabytes(); }; -Number.prototype.petabytes = function() { return this * (1024).terabytes(); }; -Number.prototype.exabytes = function() { return this * (1024).petabytes(); }; -['byte', 'kilobyte', 'megabyte', 'gigabyte', 'terabyte', 'petabyte', 'exabyte'].each(function(meth) { - Number.prototype[meth] = Number.prototype[meth+'s']; -}); - -Number.prototype.toPrecision = function() { - var precision = arguments[0] || 2; - var s = Math.round(this * Math.pow(10, precision)).toString(); - var pos = s.length - precision; - var last = s.substr(pos, precision); - return s.substr(0, pos) + (last.match("^0{" + precision + "}$") ? '' : '.' + last); -} - -// (1/10).toPercentage() -// # => '10%' -Number.prototype.toPercentage = function() { - return (this * 100).toPrecision() + '%'; -} - -Number.prototype.toHumanSize = function() { - if(this < (1).kilobyte()) return this + " Bytes"; - if(this < (1).megabyte()) return (this / (1).kilobyte()).toPrecision() + ' KB'; - if(this < (1).gigabytes()) return (this / (1).megabyte()).toPrecision() + ' MB'; - if(this < (1).terabytes()) return (this / (1).gigabytes()).toPrecision() + ' GB'; - if(this < (1).petabytes()) return (this / (1).terabytes()).toPrecision() + ' TB'; - if(this < (1).exabytes()) return (this / (1).petabytes()).toPrecision() + ' PB'; - return (this / (1).exabytes()).toPrecision() + ' EB'; -} diff --git a/site/src/docs/upload_progress_rails.rb b/site/src/docs/upload_progress_rails.rb deleted file mode 100644 index d04d658..0000000 --- a/site/src/docs/upload_progress_rails.rb +++ /dev/null @@ -1,14 +0,0 @@ -class FilesController < ApplicationController - session :off, :only => :progress - - def progress - render :update do |page| - @status = Mongrel::Uploads.check(params[:upload_id]) - page.upload_progress.update(@status[:size], @status[:received]) if @status - end - end - - def upload - render :text => %(UPLOADED: #{params.inspect}.) - end -end diff --git a/site/src/docs/win32.page b/site/src/docs/win32.page deleted file mode 100644 index c3e386f..0000000 --- a/site/src/docs/win32.page +++ /dev/null @@ -1,131 +0,0 @@ ---- -title: Win32 HOWTO -inMenu: true -directoryName: Documentation ---- - -h1. Mongrel Win32 HOWTO - -Mongrel now supports Win32 much better than previous releases thanks to -some "great people":../attributions.html and their hard work. You can -now run Mongrel with Ruby on Rails as a windows service, ang there are -pre-compiled gems available for people to use. - -*Before reading this document you need to read "Getting Started.":started.html and make sure it works.* - -h2. Installing Service Support - -Mongrel used to have a separate mongrel_rails_service script but this -caused problems and has since been unified into just mongrel_rails -and a special GemPlugin that gives you a set of service:: commands. - -To install the mongrel_service GemPlugin you simply install mongrel and -then do: - - > gem install mongrel_service - -This will give you a set of service commands that you can find out about -by just running mongrel_rails and then passing each one the -h option to -get help. - - -h2. Running The Service - -After you do the gem install, find a Rails application you want to run -and do: - - $ mongrel_rails service::install -N myapp \ - -c c:\my\path\to\myapp -p 4000 -e production - $ mongrel_rails service::start -N myapp - -Now hit the port and poof, works (or should). - -The application will stop if you use: - - $ mongrel_rails service::stop -N myapp - -@NOTE: Stop reports an exception but does stop the service.@ - -Now the really great thing is that you can just do all this from -the Services control panel like your Rails application is a regular -Windows service. - -Even works in development mode, which is pretty nice. I use win32 -at work now and what I have setup is three services: myapp_dev, -myapp_stage, myapp_prod. I point dev and stage at the same -directory but run dev in *development* mode and stage in *production* -mode. Then I have myapp_prod in a separate directory and when I'm -about to claim I've got something to release I'll go simulate a -subversion check-out and run my tests again. - - -h2. Other Service Commands - -There is a full set of service control commands in the mongrel_service plugin. -This lets you use either the Services control panel or a command line script to -manage your Rails applications. What's also nice is that you can register as many -applications as you want, and even the same one with different names. - - -h3. service::install - -If you want to run the same app in different modes then use the *-N* option to the *install* -command: - - $ mongrel_rails service::install -N myapp_dev \ - -c c:\my\path\to\myapp -p 4000 -e development - $ mongrel_rails service::start -N myapp - -You can also use the *-D* option to give the service a different display name in the -Services console. - -h3. service::start - -Pretty much just takes a service name to start up. It will run and print a message -until the service finally starts, which sometimes can take 10-60 seconds. - -h3. service::stop - -Sort of works right now and also only takes a -N parameter. It has a few errors -when it tries to stop a service so we're working on making it cleaner. - -*NOTE:* since mongrel_service 0.3.1, start and stop commands were removed. -Use net start / net stop instead. - -h3. service::remove - -Takes the name (-N) of the service to remove and then removes it from the list. -*This would be how you'd remove a service so you can change it's start-up options.* - - -h2. CPU Affinity - -Mongrel's win32 support actually is able to set the CPU affinity of a running -Mongrel service. This is pretty neat since it means if you're running a -fancy SMP machine or a dual core that pretends to be SMP, then you can -force Mongrel onto one of them and get a nice little boost. - -It's pretty easy to use, just pass the *-u or --cpu* option to the *install* -command and give a CPU of 1-X. That means if you have 4 CPUs and you want -Mongrel on #4 then do: - - $ mongrel_rails service::install -N myapp \ - -c c:\my\path\to\myapp -p 4000 -e production -u 4 - -Pretty much the same command, just one more option and you're done. - - -h2. Making you Service autostart with Windows - -By default, the new Mongrel service get installed to be run _manually_, using -Mongrel's commands or the Service Manager. You could tweak it to start automatically -when Windows start, just use the Service Control commandline tool: - - $ sc config myapp start= auto - -Also, you can configure the services that are neede to make it work, like database -support: - - $ sc config myapp start= auto dependency= MySql - -The space after the equal sign is needed for the command to complete successfully. diff --git a/site/src/dogs.page b/site/src/dogs.page deleted file mode 100644 index 1bde647..0000000 --- a/site/src/dogs.page +++ /dev/null @@ -1,40 +0,0 @@ ---- -title: Mongrels -inMenu: true -directoryName: Mongrels ---- - -h1. Dogs Who Love Their People - -We asked people to send links to their favorite pictures of their dogs. If you -want your dog listed here as another Mongrel Supporter then just shoot someone -on the team an email. - -h2. Kelly Felkins' tur-bone - -Kelly actually has an entire site devoted to his dog tur-bone. Now that's love. - -* "tur-bone running":http://thedailybone.us/index.php?showimage=11 -* "tur-bone's main site":http://thedailybone.us/ - -"My dog is lighting fast and 30 lbs small. Lean yet powerful. (And he's a great guy too.) -His name is T-Bone and you can see pictures of him at, where else, 'the daily bone'." - -h2. Paul Vudmaska's lucky - -Paul said his dog Lucky "is mean as hell :-)". - -* "Lucky likes you":http://flickr.com/photos/i-i/40837043/ - -h2. Ed C.'s Honey - -Ready for the work day. - -* "Honey wearing a tie":http://static.flickr.com/16/21296961_6512bbdc3c_o.jpg - -h2. Ezra Zygmuntowicz's Louie - -We hear he likes hands too. - -* "Louie during x-mas":http://brainspl.at/xmas/xmas-Images/21.jpg - diff --git a/site/src/faq.page b/site/src/faq.page deleted file mode 100644 index e6c3206..0000000 --- a/site/src/faq.page +++ /dev/null @@ -1,411 +0,0 @@ ---- -title: FAQ -inMenu: true -directoryName: FAQ -ordering: 5 ---- - -h1. FAQ - -h2. Design - -h3. Q: How is Mongrel designed? - -The design of Mongrel most closely matches "Simple":http://simpleweb.sourceforge.net/ -which is a very nicely designed web server framework for Java. Despite being written -in Java, Simple is very clean and simple, thus the name (clever eh?). The main difference -between Mongrel and Simple is that Simple monitors returned output from handlers so that -it can modify the results. Mongrel instead uses Ruby's blocks to get the same effect. - -As for the internals of Mongrel there are a few key technologies being used: - -* A custom HTTP 1.1 parser written based on the "RFC":http://www.w3.org/Protocols/rfc2616/rfc2616.html - standard and using "an ABNF dump":http://www.cs.columbia.edu/sip/syntax/rfc2068.html thankfully - put online by someone. The parser is written using "Ragel":http://www.elude.ca/ragel/ and - is written C as a Ruby extension. -* A simple server that uses the parser and URIClassifier to process requests, find the - right handlers, and then pass the results on to the handler for processing. -* Handlers are responsible for using HttpRequest and HttpResponse objects to do their - thing and then return results. - -Other than this there's not much more to it. - -h3. Q: Is it multi-threaded or can it handle concurrent requests? - -Mongrel uses one thread per request, but it will start closing connections -when it gets "overloaded". While Mongrel is processing HTTP requests and -sending responses it uses Ruby's threading system (which is more like -Java's original green threads and uses select). - -Camping and Og+Nitro are supposed to be thread safe and work with Mongrel directly. -This hasn't been heavily tested so people should let me know if they get weird -explosions under heavy load. - -Ruby on Rails is not thread safe so there is a synchronized block around the calls -to Dispatcher.dispatch. This means that everything is threaded right before and -right after Rails runs. While Rails is running there is only one controller -in operation at a time. This is why people typically have to run a small -set of Mongrel processes (a "Pack of Mongrels") to get good concurrency. - -If you have long running actions then you'll most likely have performance -problems. You should look at "BackgrounDRB":http://backgroundrb.rubyforge.org/ -as a very nice way to offload work to another process so that your Rails -app can keep working. - -h3. Q: But no, I mean how is it *exactly* locked? Because it's really really important that I know everything. - -First off, you should drink less coffee. Knowing exactly how Rails is locked -will not help you plan your deployment for the best performance, only testing -your deployment's speed will help. You should read "Tuning":/docs/how_many_mongrels.html -to get a good quick idea on how to figure out what your optimal Mongrel number -is, and then you should check out "BackgrounDRb":http://backgroundrb.rubyforge.org/ -for a good way to move long running tasks outside of Rails for better response. - -h3. Q: But, but, but, I really really need to know! It's killing me I *have* to know! - -Fine! It goes like this: - -# A request hits mongrel. -# Mongrel makes a thread and parses the HTTP request headers. -# If the body is small, then it puts the body into a StringIO. -# If the body is large then it streams the body to a temp file. -# When the request is "cooked" it call the RailsHandler. -# The RailsHandler sees if the file is possibly page cached, if so then it sends the cached page. -# Now you're *finally* ready to process the Rails request. *LOCK!* -# Still *locked*, Mongrel calls the Rails Dispatcher to handle the request, passing in the headers, and StringIO or Tempfile for body. -# When Rails is done, *UNLOCK!*. Rails has (hopefully) put all of its output into a StringIO. -# Mongrel then takes this StringIO output, any output headers, and streams them back to the client super fast. - -There's also a bit of processing with chains of Handlers, but that's a minor point. -For the most part, your goal as a Rails programmer is to make all of your Rails -actions as fast as possible, and to not do anything that takes a long time. - - -h3. Q: Can I run Mongrel without Rails? - -Yes, Mongrel is designed to host any framework, and already hosts Camping or Nitro -as well. If you're feeling adventurous, check out the "RDoc":/rdoc/index.html -for the latest API documentation. - -h2. Security - -h3. Q: Is Mongrel secure? - -Anyone who claims their server is "SECURE" is full of crap. You can't be -absolutely certain that any system is secure, but what you can do is put -policies and practices in place to try and make them more secure. - -As you can read in the "Iron Mongrel":/security.html documentation, I -have a policy of: - -* Extensive testing with multiple techniques, and even wrote my own HTTP fuzzing tool "RFuzz":http://rfuzz.rubyforge.org/ -* Full disclosure on any security issues found. -* Security auditing of all code before it's released. -* Design decisions such as using a parser generator and fixed limits on all HTTP. -* Simply trying to remove all defects and being proactive about it. - -Understand that I'm just one person with a few other people's help, so there's -bound to be mistakes. You use this technology (and *any* technology) at your -own risk. - -Then again, if someone is telling you their system is secure, but can't tell -you why it's secure, then maybe you should take a look at what I do to keep -Mongrel's defects low and ask if they do any of this. You might be surprised -at their response. - -h3. Q: What's this about .svn directories? - -Yeah, Capistrano doesn't use svn export to create the deployment directory so -there's a bunch of extra information in the .svn files. Without special config -changes to your web server you'll be letting people access these. Best solution -is to use svn export rather than checkout to get your code. If you're already -screwed then just do: - - find . -name ".svn" -exec rm -rf {} \; - -And that'll delete them all in a very final way. - -You should also read "the official page on that":http://subversion.tigris.org/faq.html#website-auto-update -to make sure there's nothing more you need to do. - -Finally, you can configure capistrano to do export instead of checkout -following "their instructions":http://manuals.rubyonrails.com/read/chapter/102 -instead of the ruthless delete I have above. - -h3. Q: Does Mongrel have SSL? - -No, having a Ruby web server do complex SSL cryptography is stupid when you can -get any of the major web servers to do it faster. - -h3. Q: Why are Apache & SSL - Redirects going to http:// not https://? - -Basically, you need to pass in a header so Rails knows what to do. Read -the bottom of the "Apache Documentation":/docs/apache.html for instructions -on how to do this. - - -h2. Installation - -h3. Q: I can't get Mongrel installed on Debian. - -You should read the "Debian":/docs/debian-sarge.html documentation. - -h3. Q: I can't get Mongrel installed on Fedora. - -Not sure when Fedora decided to start chopping up its packages like Debian, -but you should basically just install Ruby from source, then install Mongrel. - - -h2. Deployment - -h3. Q: What can cause Mongrel to lock up on a regular basis? - -There are several reasons Mongrel can stop functioning properly, but -most of them are related to using resources that aren't shared properly -between multiple processes. The following is just a short list of the -possible things you could be doing to cause Mongrel processes to lock: - -# Configuring Logger to rotate log files. Logger doesn't do this reliably -between processes, so use an external log rotation like logrotate. -# Using PStore to store your sessions. This isn't faster than the database -and has frequent locking and coordination issues. -# Sharing a file or similar service without proper locking. SQLite and BerkleyDB are -both culprits here. -# Not setting the MySQL timeout properly (see later in the FAQ). -# Using up too much CPU or memory on Linux will cause the oomkiller to -kill your Mongrel process. - -If you have frequent stopping and stability issues, then install "monit":http://www.tildeslash.com/monit/ -and have it restart your Mongrels when the go down or don't respond promptly. - -h3. Q: How do I deploy Mongrel in production? - -Take a look at the "documentation pages":/docs/index.html for -information on deploying and enhancing Mongrel. Feel free to -suggest documentation that you think is needed. - -h3. Q: Is there some kind of caching of session data in mongrel? - -Nope, Mongrel doesn't do anything with sessions and leaves that to the -framework. - -h3. Q: What is the best way to get mongrel servers within a cluster to always keep their sessions synced? - -For Rails the best way is either memcached or database session storage. -*Do not use PStore!* It is broken, will crash or lock your Mongrel processes, -and really isn't all that fast. - -h3. Q: What does num-procs do? - -There's two options that impact how your deployment performs -and what kind of resources it eats. - -* num-procs -- Determines how many active requests are allowed -before clients are denied and old requests are killed off. -* timeout -- Determines a short sleep time between each client -that is accepted. This acts as a kind of throttle. - -With num-procs you should think of it as the option that protects -your server from overload. Let's say you set it to 100 and you -get 100 requests coming in that are all being worked on. If -request 101 comes in then that request gets closed immediately, -and Mongrel goes through the original 100 looking for requests to -kill off. Right now it uses the timeout to come up with a reasonable -way to determine how long something is taking and will kill old -processors with an exception. - -The timeout option is what you use if you want to make sure that -a Mongrel server can't take on too much work (i.e. you need to -throttle it). What it does is sleep for N 100th/second after -each accept. This means that it will slow down the number of -incoming clients. Very handy if you have a shared hosting system -and don't want people to eat your servers. - - -h3. Q: Mongrel stops working if it's left alone for a long time. - -If you find that Mongrel stops working after a long idle time -and you're using MySQL then you're hitting a bug in the MySQL -driver that doesn't properly timeout connections. What happens -is the MySQL *server* side of the connection times out and closes, -but the MySQL *client* doesn't detect this and just sits there. - -What you have to do is set: - - ActiveRecord::Base.verification_timeout = 14400 - -Or to any value that is lower than the MySQL server's *interactive_timeout* -setting. This will make sure that ActiveRecord checks the connection -often enough to reset the connection. - - -h3. Q: Why is the first request to Mongrel really slow? - -The first request to *any* system will be slower than -the others, you are just noticing it with Mongrel because -the difference is so much larger. - -The cause of this depends on many factors, but typically it -is either Rails start-up, slow machine, no memory, or eager loading -the world. If you are on a slow box, or if you are trying to -load a huge amount of data when Rails starts, then the -first request will be nasty slow. - -This shouldn't really bug you though unless it happens periodically -rather than from a cold start. If it happens from a cold start or -after a long idle period then point your service monitor at your -application to keep it fresh. - -If you run a long performance test and you see periodic pauses -then you may have a memory leak or not enough ram. Re-run your -test while you monitor your ram with something like *top*. If -you see the ram of Mongrel increase and then drop, or just increase, -or you see the swap grow and shrink, then you've got a memory leak -or just simply need more ram. - -Debugging a leak is possible with the mongrel_rails start -B option. -It will log objects that get created to log/mongrel_debug and you can -look in there to find out what object is causing the problems. - - -h3. Why doesn't Mongrel write the .pid file like I tell it to? - -There was a change to the 0.3.13.4 release and on that makes it so Mongrel -doesn't try to "fix" invalid paths. You should change your configurations -so that they give explicit full paths to both the log and pid files. - - -h3. How do I put my Rails site at /someprefix? - -Most people use a virtual host configuration, but Mongrel now has an option -that lets you put your site at an arbitrary URI. Just start mongrel with: - - mongrel_rails start -e production --prefix=/someprefix - -Then your site will be at the same host but everything will be relative to -/someprefix. The only thing is you have to *religiously* use Rails link_to -and friends. If you don't then the links in your pages won't be written right. - - -h3. How many Mongrel processes should I run? - -First off, the type of machine you have doesn't matter, what matters is -that you measure your *deployment's* speed and tune that for optimal -performance. Then you *must* re-test after every change to your deployment -configuration to make sure that things didn't get worse or improve. - -There's a simple "document on tuning":/docs/how_many_mongrels.html that -should get you started. - -h3. What does BAD CLIENT mean? - -It means that a request came in which Mongrel rejects because it doesn't follow -the RFC grammar. Mongrel is pretty relaxed about most requests, but in order to -block the majority of security attacks for web servers it is strict about characters -used, header formats, status line formats, etc. This is also based on matching -the RFC's grammar specification to a Ragel grammar specification, so it's easy -to compare. - -If you need to know why the client is triggering this, then simply hit your -Mongrel processes with USR1 signals and they'll log the full request data -and parameters that were collected. Then, if you think the request is valid -send me this data and I'll look. If it's not valid than fix the client. - -Mongrel takes the stance that all clients are written by software developers and -that they should follow the standard. By doing this it reduces the bugs and -potential security holes found in many other web servers. It also means that -if you absolutely have to allow a bad client, then you'll need to not use Mongrel. - - -h3. Why do I get MySQL "lost connection to database" errors? - -The most common cause is that you're using mysql.rb that comes with Rails -rather than the MySQL compiled ruby driver from gems. Do this: - - sudo gem install mysql - -And pick the one for your system (don't type sudo if you're win32). - - -h3. Why does Mongrel keep dying on me? - -There are three known causes to this, and all of them are your fault. -First, there's a few symptoms to check to see if you fit in these -categories. - -* CLOSE_WAIT: Run @lsof -i -P | grep CLOSE_WAIT@ and if you see a bunch of mongrels then you've got a problem. -* 99% CPU: Check the mongrel processes and see if one or more are at 99%. -* MEMORY LEAK: We've supposedly fixed it, but you might be causing it yourself. - -In the case of CLOSE_WAIT and 99% CPU the problem is most likely you're using the -PStore for your session storage. Don't do this. Use memcached or database for your -session storage. PStore is slow anyway, but with multiple processes it's deadly. - -Another cause of CLOSE_WAIT and 99% CPU is one of your Rails actions is doing something -that "jams" Mongrel requests. Temporarily turn on USR1 debugging: - - killall -USR1 mongrel_rails - -And then watch what Mongrel says about the number of threads waiting for the various -Rails actions you have. You'll see right away which one is causing it. Usually -it's because you're using an external 3rd party library that isn't designed for -multiple process action. - -For memory leaks the most common cause is using Mutex. We found that on most systems -Mutex caused memory leaks when the Mutex was managing many Threads. Switch to using -Sync and see if the memory leak goes away. - -Other things that can cause big pauses are: - -* Using a broken or slow DNS server to resolve hosts. Ruby blocks the whole process while it resolves. -* Loading tons and tons of data over and over again. The GC will kill you if Linux doesn't. -* Locking files wrong. Multiple processes locking files is a delicate thing to do. -* Doing stuff over the network that takes a long time. Move that process to a DRb server run locally. - -If you have to do extensive DNS resolving then consider using dnsmasq run locally to cache the DNS -queries and make them faster. - -h3. How can I run some code before Rails starts? - -Simplest way is to put it in your production.rb and configure it there, but if -you need it done long before Rails starts, then you can throw it into a -mongrel.conf and run that file with the -S option (see mongrel_rails --help). -The mongrel.conf is a Ruby script that lets you configure Mongrel with special -Ruby code, but you can also put other Ruby code in it. - -h3. Why do I see my headers when Mongrel is behind Apache? - -If you see something weird like this in your browser when you're behind Apache: - - HTTP/1.1 0 Content-Length: 7636 - Connection: close - Date: Sat, 02 Sep 2006 14:10:38 GMT - Set-Cookie: device_id=; path=/; expires=Sun, 02 Sep 2007 14:10:38 GMT - Set-Cookie: _session_id=85d7a3c296268e0222cb796127da9c43; path=/ - *Status: status500* - Cache-Control: no-cache - Server: Mongrel 0.3.13.3 - Content-Type: text/html - -Then what you've done is you've mangled the *status* code inside rails with something -that is setting "status => 500". Rails is then injecting this right in, as you can -see in the above Status line. Since this is an invalid status, Apache "helpfully" -shows you the error so you can correct it. - - -h2. Mongrel Web Site - -h3. Q: How did you make this site? - -Zed made most of this site: - - The site was actually incredibly easy to create. I simply went to "OSWD":http://openwebdesign.org/ - and found a design that fit what I wanted for the site. I then went to "Flickr":http://flickr.com/ - and found pictures of various animals that were licensed under the - "Creative Commons":http://creativecommons.org/ license. Once I chopped the images up, worked them - into the design structure, and wrote an initial set of content I was done. - - The tool I use to generate the site is called "webgen":http://webgen.rubyforge.org/ which - is a static site generator written in Ruby. I write all of the content using redcloth - mark-up and leave the generation to webgen. Finally I hooked into the Mongrel Rakefile - so that it's auto-generated and deployed to the site for me. diff --git a/site/src/images/250878012_55b96c985c_o.jpg b/site/src/images/250878012_55b96c985c_o.jpg deleted file mode 100644 index 9b76914..0000000 Binary files a/site/src/images/250878012_55b96c985c_o.jpg and /dev/null differ diff --git a/site/src/images/3930442_6cbcae1335.jpg b/site/src/images/3930442_6cbcae1335.jpg deleted file mode 100644 index 4d72f1c..0000000 Binary files a/site/src/images/3930442_6cbcae1335.jpg and /dev/null differ diff --git a/site/src/images/3colls_p1.jpg b/site/src/images/3colls_p1.jpg deleted file mode 100644 index 4771c38..0000000 Binary files a/site/src/images/3colls_p1.jpg and /dev/null differ diff --git a/site/src/images/3colls_p2.jpg b/site/src/images/3colls_p2.jpg deleted file mode 100644 index c1c842f..0000000 Binary files a/site/src/images/3colls_p2.jpg and /dev/null differ diff --git a/site/src/images/3colls_p3.jpg b/site/src/images/3colls_p3.jpg deleted file mode 100644 index 3e0c38d..0000000 Binary files a/site/src/images/3colls_p3.jpg and /dev/null differ diff --git a/site/src/images/6267035_eeec5b0f16.jpg b/site/src/images/6267035_eeec5b0f16.jpg deleted file mode 100644 index 949e5e1..0000000 Binary files a/site/src/images/6267035_eeec5b0f16.jpg and /dev/null differ diff --git a/site/src/images/63325054_12298eb2a3.jpg b/site/src/images/63325054_12298eb2a3.jpg deleted file mode 100644 index 7db0e37..0000000 Binary files a/site/src/images/63325054_12298eb2a3.jpg and /dev/null differ diff --git a/site/src/images/79968762_e063fc1317.jpg b/site/src/images/79968762_e063fc1317.jpg deleted file mode 100644 index 7d817f6..0000000 Binary files a/site/src/images/79968762_e063fc1317.jpg and /dev/null differ diff --git a/site/src/images/85895062_beb6249744.jpg b/site/src/images/85895062_beb6249744.jpg deleted file mode 100644 index 67bdb09..0000000 Binary files a/site/src/images/85895062_beb6249744.jpg and /dev/null differ diff --git a/site/src/images/86461088_9a747a6a5e.jpg b/site/src/images/86461088_9a747a6a5e.jpg deleted file mode 100644 index a045ee5..0000000 Binary files a/site/src/images/86461088_9a747a6a5e.jpg and /dev/null differ diff --git a/site/src/images/87022458_3981942f0c.jpg b/site/src/images/87022458_3981942f0c.jpg deleted file mode 100644 index 1f02e80..0000000 Binary files a/site/src/images/87022458_3981942f0c.jpg and /dev/null differ diff --git a/site/src/images/90208926_7d64788f30.jpg b/site/src/images/90208926_7d64788f30.jpg deleted file mode 100644 index da7ec4b..0000000 Binary files a/site/src/images/90208926_7d64788f30.jpg and /dev/null differ diff --git a/site/src/images/92211824_d01a4ce59c.jpg b/site/src/images/92211824_d01a4ce59c.jpg deleted file mode 100644 index 871f2d9..0000000 Binary files a/site/src/images/92211824_d01a4ce59c.jpg and /dev/null differ diff --git a/site/src/images/98452447_1be256a96c.jpg b/site/src/images/98452447_1be256a96c.jpg deleted file mode 100644 index 2fbf0ff..0000000 Binary files a/site/src/images/98452447_1be256a96c.jpg and /dev/null differ diff --git a/site/src/images/bug_votes.png b/site/src/images/bug_votes.png deleted file mode 100644 index 1f42ea5..0000000 Binary files a/site/src/images/bug_votes.png and /dev/null differ diff --git a/site/src/images/config_tool_snap.png b/site/src/images/config_tool_snap.png deleted file mode 100644 index 05e1b14..0000000 Binary files a/site/src/images/config_tool_snap.png and /dev/null differ diff --git a/site/src/images/index.page b/site/src/images/index.page deleted file mode 100644 index 1fae5eb..0000000 --- a/site/src/images/index.page +++ /dev/null @@ -1,7 +0,0 @@ ---- -title: Images -inMenu: false -directoryName: Images ---- - -Images are here, nothing else. Move along. diff --git a/site/src/images/iron_mongrel.jpg b/site/src/images/iron_mongrel.jpg deleted file mode 100644 index a1d9b6b..0000000 Binary files a/site/src/images/iron_mongrel.jpg and /dev/null differ diff --git a/site/src/images/li1a-c1.gif b/site/src/images/li1a-c1.gif deleted file mode 100644 index c14da91..0000000 Binary files a/site/src/images/li1a-c1.gif and /dev/null differ diff --git a/site/src/images/li1a.gif b/site/src/images/li1a.gif deleted file mode 100644 index 95b6659..0000000 Binary files a/site/src/images/li1a.gif and /dev/null differ diff --git a/site/src/images/li1b-c1.gif b/site/src/images/li1b-c1.gif deleted file mode 100644 index 20a27a5..0000000 Binary files a/site/src/images/li1b-c1.gif and /dev/null differ diff --git a/site/src/images/li1b.gif b/site/src/images/li1b.gif deleted file mode 100644 index 2121721..0000000 Binary files a/site/src/images/li1b.gif and /dev/null differ diff --git a/site/src/images/li2-c1.gif b/site/src/images/li2-c1.gif deleted file mode 100644 index e60fad1..0000000 Binary files a/site/src/images/li2-c1.gif and /dev/null differ diff --git a/site/src/images/li2.gif b/site/src/images/li2.gif deleted file mode 100644 index 5517ad2..0000000 Binary files a/site/src/images/li2.gif and /dev/null differ diff --git a/site/src/images/li3-c1.gif b/site/src/images/li3-c1.gif deleted file mode 100644 index e5af2b4..0000000 Binary files a/site/src/images/li3-c1.gif and /dev/null differ diff --git a/site/src/images/li3.gif b/site/src/images/li3.gif deleted file mode 100644 index e5af2b4..0000000 Binary files a/site/src/images/li3.gif and /dev/null differ diff --git a/site/src/images/li4.gif b/site/src/images/li4.gif deleted file mode 100644 index 712c6bf..0000000 Binary files a/site/src/images/li4.gif and /dev/null differ diff --git a/site/src/images/mongrel_not_scgi.jpg b/site/src/images/mongrel_not_scgi.jpg deleted file mode 100644 index cdfd536..0000000 Binary files a/site/src/images/mongrel_not_scgi.jpg and /dev/null differ diff --git a/site/src/images/rss.png b/site/src/images/rss.png deleted file mode 100644 index 6e7b676..0000000 Binary files a/site/src/images/rss.png and /dev/null differ diff --git a/site/src/images/side_p1.gif b/site/src/images/side_p1.gif deleted file mode 100644 index 045060e..0000000 Binary files a/site/src/images/side_p1.gif and /dev/null differ diff --git a/site/src/images/side_p2.gif b/site/src/images/side_p2.gif deleted file mode 100644 index a26577d..0000000 Binary files a/site/src/images/side_p2.gif and /dev/null differ diff --git a/site/src/images/side_p3.gif b/site/src/images/side_p3.gif deleted file mode 100644 index c8a0bf1..0000000 Binary files a/site/src/images/side_p3.gif and /dev/null differ diff --git a/site/src/images/tl_contact-c1-on.gif b/site/src/images/tl_contact-c1-on.gif deleted file mode 100644 index 2687378..0000000 Binary files a/site/src/images/tl_contact-c1-on.gif and /dev/null differ diff --git a/site/src/images/tl_contact-c1.gif b/site/src/images/tl_contact-c1.gif deleted file mode 100644 index 9c15bf7..0000000 Binary files a/site/src/images/tl_contact-c1.gif and /dev/null differ diff --git a/site/src/images/tl_contact-on.gif b/site/src/images/tl_contact-on.gif deleted file mode 100644 index 15f095f..0000000 Binary files a/site/src/images/tl_contact-on.gif and /dev/null differ diff --git a/site/src/images/tl_contact.gif b/site/src/images/tl_contact.gif deleted file mode 100644 index fbd30a5..0000000 Binary files a/site/src/images/tl_contact.gif and /dev/null differ diff --git a/site/src/images/tl_home-c1-on.gif b/site/src/images/tl_home-c1-on.gif deleted file mode 100644 index d9e8a8a..0000000 Binary files a/site/src/images/tl_home-c1-on.gif and /dev/null differ diff --git a/site/src/images/tl_home-c1.gif b/site/src/images/tl_home-c1.gif deleted file mode 100644 index d8fd5c4..0000000 Binary files a/site/src/images/tl_home-c1.gif and /dev/null differ diff --git a/site/src/images/tl_home-on.gif b/site/src/images/tl_home-on.gif deleted file mode 100644 index 1f0b402..0000000 Binary files a/site/src/images/tl_home-on.gif and /dev/null differ diff --git a/site/src/images/tl_home.gif b/site/src/images/tl_home.gif deleted file mode 100644 index f4346c5..0000000 Binary files a/site/src/images/tl_home.gif and /dev/null differ diff --git a/site/src/images/tl_sitemap-c1-on.gif b/site/src/images/tl_sitemap-c1-on.gif deleted file mode 100644 index 8c1ac0f..0000000 Binary files a/site/src/images/tl_sitemap-c1-on.gif and /dev/null differ diff --git a/site/src/images/tl_sitemap-c1.gif b/site/src/images/tl_sitemap-c1.gif deleted file mode 100644 index 3232910..0000000 Binary files a/site/src/images/tl_sitemap-c1.gif and /dev/null differ diff --git a/site/src/images/tl_sitemap-on.gif b/site/src/images/tl_sitemap-on.gif deleted file mode 100644 index acaa272..0000000 Binary files a/site/src/images/tl_sitemap-on.gif and /dev/null differ diff --git a/site/src/images/tl_sitemap.gif b/site/src/images/tl_sitemap.gif deleted file mode 100644 index 0dbdbf5..0000000 Binary files a/site/src/images/tl_sitemap.gif and /dev/null differ diff --git a/site/src/images/tn_bg1.gif b/site/src/images/tn_bg1.gif deleted file mode 100644 index 8f0165e..0000000 Binary files a/site/src/images/tn_bg1.gif and /dev/null differ diff --git a/site/src/images/tn_bg2.gif b/site/src/images/tn_bg2.gif deleted file mode 100644 index 993eb72..0000000 Binary files a/site/src/images/tn_bg2.gif and /dev/null differ diff --git a/site/src/images/visual.jpg b/site/src/images/visual.jpg deleted file mode 100644 index 8627594..0000000 Binary files a/site/src/images/visual.jpg and /dev/null differ diff --git a/site/src/images/visual_dog.jpg b/site/src/images/visual_dog.jpg deleted file mode 100644 index 4e78a15..0000000 Binary files a/site/src/images/visual_dog.jpg and /dev/null differ diff --git a/site/src/index.page b/site/src/index.page deleted file mode 100644 index b84a635..0000000 --- a/site/src/index.page +++ /dev/null @@ -1,62 +0,0 @@ ---- -title: Home -inMenu: false -directoryName: Home ---- -h1. What is Mongrel? - -Mongrel is a fast HTTP library and server for Ruby that is intended for hosting -Ruby web applications of any kind using plain HTTP rather than FastCGI or SCGI. -It is framework agnostic and already supports "Ruby On -Rails":http://www.rubyonrails.org, "Og+Nitro":http://www.nitroproject.org/, -"Camping":http://camping.rubyforge.org/files/README.html, and -"IOWA":http://enigo.com/projects/iowa/tutorial/what_is_it.html frameworks. - -h2. Getting Started - -The easiest way to get started with Mongrel is to install it via RubyGems -and then run a Ruby on Rails application. You can do this easily: - - $ sudo gem install mongrel - $ cd myrailsapp - $ mongrel_rails start -d - -Which runs Mongrel in the background. You can stop it with: - - $ mongrel_rails stop - -And you're all set. There's quite a few options you can set for the -start command. Use the *mongrel_rails start -h* to see them all. - -h2. Win32 Support - -Win32 is fully supported by Mongrel with services and CPU -affinity support. You should read the "Win32 HOWTO":docs/win32.html -for information on getting started. - -The main thing with Win32 support is that there is no *fork* -API for Ruby, so you have to use the services features to -get persistent servers running. You can get this services -support by doing: - - > gem install mongrel_service - -And then just run @mongrel_rails@ to see what @services::@ commands -are available. - - -h1. Next Steps - -Now that you're a Mongrel user, there's some thing you should -do to educate yourself: - -* "Join the mailing list":http://rubyforge.org/mailman/listinfo/mongrel-users -* "Read the documentation":docs/index.html -* Learn to use --help when you want to know what Mongrel commands can do. - -The last one is important. A lot of effort went into making -Mongrel as self-documenting as possible. Before you hit the -mailing list asking how to do something, try passing that -command --help and see if it tells you. If it's still not -clear then ask away. - diff --git a/site/src/license.page b/site/src/license.page deleted file mode 100644 index c7db371..0000000 --- a/site/src/license.page +++ /dev/null @@ -1,73 +0,0 @@ ---- -title: Licensing -inMenu: true -directoryName: Licensing ---- - -h1. Mongrel Licensing - -Mongrel is licensed under Ruby's License. This means that it's also licensed under the GPL2 for people who get worked up about the Ruby license lacking explicit permission for use. These people mainly come from Florida; who knows why. Anyway: - - Mongrel Web Server (Mongrel) is copyrighted free software by Zed A. Shaw - and contributors. You can redistribute it and/or - modify it under either the terms of the GPL2 or the conditions below: - - 1. You may make and give away verbatim copies of the source form of the - software without restriction, provided that you duplicate all of the - original copyright notices and associated disclaimers. - - 2. You may modify your copy of the software in any way, provided that - you do at least ONE of the following: - - a) place your modifications in the Public Domain or otherwise make them - Freely Available, such as by posting said modifications to Usenet or an - equivalent medium, or by allowing the author to include your - modifications in the software. - - b) use the modified software only within your corporation or - organization. - - c) rename any non-standard executables so the names do not conflict with - standard executables, which must also be provided. - - d) make other distribution arrangements with the author. - - 3. You may distribute the software in object code or executable - form, provided that you do at least ONE of the following: - - a) distribute the executables and library files of the software, - together with instructions (in the manual page or equivalent) on where - to get the original distribution. - - b) accompany the distribution with the machine-readable source of the - software. - - c) give non-standard executables non-standard names, with - instructions on where to get the original software distribution. - - d) make other distribution arrangements with the author. - - 4. You may modify and include the part of the software into any other - software (possibly commercial). But some files in the distribution - are not written by the author, so that they are not under this terms. - - 5. The scripts and library files supplied as input to or produced as - output from the software do not automatically fall under the - copyright of the software, but belong to whomever generated them, - and may be sold commercially, and may be aggregated with this - software. - - 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR - IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - PURPOSE. - - -h2. GemPlugins - -The GemPlugins system is both freely available *and* licensed under the Ruby License. Feel free to use it just like you would Ruby and work it into your projects as you need. - -h2. Some Charities To Consider - -Any charity that helps children is a good one. Zed's personal favorite is "The Train Platform Schools":http://www.globalgiving.com/pr/1100/proj1042a.html in India. They help children who are extremely poor get food, medical attention, and education by holding small school sessions on the train platforms in Bhubaneswar, India. - diff --git a/site/src/news.include b/site/src/news.include deleted file mode 100644 index 1ba0e99..0000000 --- a/site/src/news.include +++ /dev/null @@ -1,112 +0,0 @@ -
- -
Dec-29-2007
-
-
Mongrel 1.1.3 and 1.0.5, security update
- -

Mongrel 1.1.3 and 1.0.5 are out. They fix a security flaw in the DirHandler as reported on the list. You should upgrade when you get the chance.

- Download - more

-
- -
Dec-15-2007
-
-
Mongrel 1.1.2, holiday edition
- -

Mongrel 1.1.2 is out. It fixes a few bugs and adds JRuby 1.0.x compatibility.

- Download - more

-
- -
Nov-12-2007
-
-
Mongrel 1.1.1, never forget
- -

Mongrel 1.1.1 is out. It fixes the mongrel_rails restart bug.

- Download - more

-
- -
Nov-1-2007
-
-
Mongrel 1.1, caffeinated edition
- -

Mongrel 1.1 is out, with JRuby support. Mongrel_cluster is also updated to 1.0.4.

- Download - more

-
- -
Oct-29-2007
-
-
Mongrel 1.0.4, bugfix release
- -

Mongrel 1.0.4 is out. It fixes three bugs that were introduced in 1.0.3.

- Download - more

-
- -
Oct-26-2007
-
-
Mongrel 1.0.3 is out
- -

Mongrel 1.0.3 is out with an asspile of bug fixes.

- Download - more

-
- -
Jan-22-2007
-
-
Mongrel 1.0.1 Is Official
- -

It's out for everyone to fondle and admire.

- Download - more

-
- -
Dec-19-2006
-
-
Mongrel 1.0 RC1 -- Win32 TOO
- -

1.0 RC1 is out with all the win32 goodies.

- Read About It - more

-
- -
Dec-15-2006
-
-
Mongrel 0.3.20 -- 5 Hour Deadline
- -

Last one before 1.0 RC1 so check it hard.

- Read About It - more

-
- -
Dec-14-2006
-
-
Mongrel 0.3.19 -- The Gnostic MIME Types
- -

One more release for Mongrel with MIME types, handling of a few more dumb clients, - and a patch to allow multiple listeners.

- Read About It - more

-
- -
Nov-25-2006
-
-
Mongrel 0.3.18 -- FreeBSD Tweaks, Camping Fix
- -

One step close to 1.0 RC1 this release adds a bit of a boost for FreeBSD people.

- Read About It - more

-
- -
Nov-24-2006
-
-
Mongrel 0.3.17 -- Close to 1.0 RC1
- -

The release that will become the 1.0 RC1 release. Install and test like normal.

- Read About It - more

-
- -
diff --git a/site/src/news.page b/site/src/news.page deleted file mode 100644 index 322aab0..0000000 --- a/site/src/news.page +++ /dev/null @@ -1,907 +0,0 @@ ---- -title: News -inMenu: true -directoryName: News -ordering: 2 ---- - -h1. Latest News - -h2. Dec 29: Mongrel 1.1.3 and 1.0.5, security update. For serious. - -Mongrel 1.1.3 and 1.0.5 are out. They fix a security flaw in the DirHandler as reported on the list. The flaw may or may not be already mitigated by your proxy configuration, but you should upgrade when you get the chance (or downgrade to 1.0.3). - -h2. Dec 15: Mongrel 1.1.2, holiday edition. - -Mongrel 1.1.2 is out. It fixes a few bugs and adds JRuby 1.0.x compatibility. - -h2. Nov 12: Mongrel 1.1.1, never forget. - -Mongrel 1.1.1 is out. It fixes the mongrel_rails restart bug that annoyed everybody, as well as a couple of other things. - -h2. Nov 1: Mongrel 1.1, caffeinated edition - -Mongrel 1.1 is out, with JRuby support. Mongrel_cluster is also updated to 1.0.4, with fixes for a Capistrano recipe bug. The URIClassifier has been updated; if you still need the old one (you don't), it's available in the mongrel_experimental gem. - -h2. Oct 29: Mongrel 1.0.4, spooky. - -Mongrel 1.0.4 is out. It fixes three bugs that were introduced in 1.0.3. - -h2. Oct 26: Mongrel 1.0.3 drops! - -Mongrel 1.0.3 is finally out with an asspile of bug fixes. It's now a signed gem, so add the Mongrel public certificate via: - - $ wget http://rubyforge.org/frs/download.php/25325/mongrel-public_cert.pem - $ gem cert --add mongrel-public_cert.pem - -Now install via: - - $ gem install mongrel --include-dependencies -P HighSecurity - -Manual downloads (gems and tarballs) are at http://mongrel.rubyforge.org/releases/. - -Mongrel 1.1 is coming real soon now with JRuby support and a few other things. - -h2. Jan 22: Mongrel 1.0.1, baby! - -Alright folks, after nearly a month of pounding and beating up the Mongrel 1.0 RC1 release we're putting out the official 1.0.1 release. It's official, so let the chaos spread across the 2.0 web in a destructive blaze viewable from the buckle of Orion's Belt. - -Or, you could just install it with: - - $ gem install mongrel - -It should properly pull all the required dependencies, and updating your gems should -get all the new cool stuff. - -h3. What happened to 1.0? - -We decided to follow official Rails Configuration Management Board Standards and do a silent 1.0 followed by an official 1.0.1. There weren't any bugs in 1.0 but we didn't want to break with tradition by not offering a 1.0.1. (Yes, this is a joke.) - -Also, this forces the upgrade even for people who grabbed 1.0 from the releases directory. - -h3. Information - - * "RDoc":/rdoc/ - * "Coverage Report":/coverage/ - * "Report Bugs":http://rubyforge.org/tracker/index.php?group_id=1306&atid=5145 - * "Documentation":/docs/index.html - * "Adoptions":/adoption.html - * "Books":/books.html - -h3. Are You Using It? - -I want to build up a good list of people who are using Mongrel, no matter what you use it for or where. Any use is a good use. I'll be filling in documentation and collecting up all the pictures of people's dogs that I've collected, so adding more "mongrel success stories" would be a great addition. - -If you *wrote a book* or mentioned Mongrel in a book then tell me that too. I want to make sure more than just my book is mentioned. I'll be adding to that list as well. - -You can post to the mailing list or email one of the project members. If you ask us to keep the company secret then we won't post your usage, just keep it for our own records and smug self-satisfaction. - -h2. Dec 19: Mongrel 1.0 RC1 Full Win32 Build - -It's *finally* here. Mongrel 1.0 RC1 for everyone to test, even the win32 folks. I managed to get everything to build on windows, including fastthread, and even cleaned up the "releases source":http://mongrel.rubyforge.org/releases/ so that -it should install cleaner. Win32 will have to try and report problems, as it seems rubygems is real finicky on win32. - -UNIX Install with: - - $ gem install mongrel --source=http://mongrel.rubyforge.org/releases - -WIN32 Install with: - - $ gem uninstall mongrel - $ gem uninstall gem_plugin - $ gem uninstall fastthread - $ gem install fastthread --source=http://mongrel.rubyforge.org/releases - $ gem install mongrel --source=http://mongrel.rubyforge.org/releases - $ gem install mongrel_service --source=http://mongrel.rubyforge.org/releases - -If you have problems with fastthread then skip it, it's optional on Win32. The -win32 process is more involved because there hasn't been a stable release of it -for a while now. That's why you have to remove everything you can and then -re-install. - - Make sure that gem_plugin is version 0.2.2 or the whole thing dies. - -If you have problems installing any of this then add a / to the end of the source: - - $ gem install mongrel --source=http://mongrel.rubyforge.org/releases/ - -Yes, that's retarded, blame the rubygems folks. - -You can view the ChangeLog for this latest release -"in the releases":http://mongrel.rubyforge.org/releases/ChangeLog directory -like normal. This ChangeLog covers everything done since 0.3.18 but it's -in svn log format so only read it if you're really uptight. - -And as usual, report any bugs. I'll be posting instructions on using the -new mongrel_service when I get them from Luis. - -h3. IT'S RC1 FOR A REASON - -Before you go off installing this thing in your production servers because you -missed the RC1 identifier, remember that RC means "Release Candidate". Test -it to death, use it, report bugs, but only a fool installs it in mission -critical situations without fully testing it. - - -h2. Dec 15: 0.3.20 5 Hour Deadline - -Another fancy release with just a few little changes from yesterday: - -# Set-Cookie, Set-Cookie2, Warning, and WWW-Authenticate are allowed as duplicate headers. -# mongrel_rails stop now has a --wait option to go with --force. It will wait for either the given timeout in SECONDS or the PID file to go away. If the PID file goes away it just exits. If the timeout happens then it does a kill -9 on the mongrel process. -# The MIME types as of 22:00 PDT are included in this release. Five more hours to make changes and complain if you don't like them. "Edit the wiki":http://wiki.rubyonrails.org/rails/pages/TheGnosticMimeTypes to make a difference. -# Default MIME type is application/octet-stream (it was with 0.3.19, but now you all know). - -Install with: - - $ gem install fastthread --source=http://mongrel.rubyforge.org/releases - $ gem install mongrel --source=http://mongrel.rubyforge.org/releases - -This release will be what goes in the 1.0 RC1 with the exception of any changes we -have to make for win32 and the final version of the MIME types. - -h3. Using The Force - -Mongrel is *very* conservative when it shuts down. It will wait up to 60 seconds for threads to exit before it finally exits gracefully. Most people don't understand this so they think Mongrel is stuck, when actually it's doing what everyone also wants which is not lose a single connection. - -The hypocrisy is that people want Mongrel's shutdown to be "robust" but mean two things. "Robust" when you've gotta have Mongrel down NOW to avoid the digg to your fancy social network mashup with potato porn means "down now! now! NOW! don't wait! NOW!" - -"Robust" when you're rolling out the latest version of your crafted ultimate killer online PIM software your company has banked its reputation on means "very carefully, we don't want to lose a single byte in any request ever." Don't ask me why these people are using HTTP but oh well. - -Mongrel is "robust" in the second form. To make Mongrel "robust" in the first form, you use the force: - - $ mongrel_rails stop --force - -This sends mongrel a kill -9 and then *you* must delete the .pid file. If you don't mongrel now does this when you try to start: - - $ mongrel_rails start -e production -d - ** !!! PID file log/mongrel.pid already exists. Mongrel could be running already. Check your log/mongrel.log for errors. - ** !!! Exiting with error. You must stop mongrel and clear the .pid before I'll attempt a start. - -So, if you had to force it down, you've gotta do the clean-up. Now, let's say you do want to give most requests a chance to get out, but maybe not the usual time, you can now use --wait with force: - - $ mongrel_rails stop --force --wait 15 - -The --wait parameter only makes sense with --force. When you do this, Mongrel will watch the mongrel.pid file for 15 seconds. If the PID file goes away on its own (meaning the process exited anyway) then the stop command is ignored and mongrel_rails exits. If 15 seconds pass by and the PID file is still there *then* mongrel sends kill -9 to ruin your customer's day. - -But don't worry, you've probably planned your outages and have scheduled this with your customers and have "come back later" pages right? - - -h2. Dec 14: 0.3.19 The Gnostic MIME Types - -This release features two major capitulations on Mongrel's stance of not being -a full web server. The first is Mongrel now sports a YAML file with 739 MIME -types in it that it will use. The second is Mongrel will now accept clients who -insist on doing their requests with "GET http://host:3000/index.html HTTP/1.1" -even though it's not understood by a web server (that's for *proxies* people). - -It also features a patch to allow for multiple listeners on the request chains, -so anyone running *mongrel_upload_progress* should test it heavily. Finally, -we're getting close to having a clean build for win32, and my apology for -holding things back on that. - -Install with: - - $ gem install fastthread --source=http://mongrel.rubyforge.org/releases - $ gem install mongrel --source=http://mongrel.rubyforge.org/releases - -If you get an error about the missing mime_types.yml file then uninstall Mongrel -completely and reinstall. - -Now, the MIME types are not finalized because, after looking at several sources -I found out everyone is completely out to lunch. I gathered together several -sources and recommended mime types, merged them all together, sorted and made -them unique. - -I now have a wiki page entitle "The Gnostic MIME Types":http://wiki.rubyonrails.org/rails/pages/TheGnosticMimeTypes -and I'm going to leave it up for the next 24 hours. People can edit the list to -remove what they think are invalid, correct the list, and fight over wiki wars -to make the MIME type list. - -Whatever survives after the wars will become the official Mongrel MIME types. -The ones that remain will be labeled "The Gnostic MIME Types" and simply -documented on the Mongrel site so people know what happened. - -Let the battle begin! - -h2. Nov 25: 0.3.18 FreeBSD Tweak and Camping Fix - -Alright folks, I put in a fix for camping and added the patch by Thomas Hurst for the accf_http deferred accept settings for FreeBSD. - -As usual, please test this release out and let me know if it has any additional problems. I'll be working on win32 builds today and tomorrow with Luis. - -Install with: - - $ gem install fastthread --source=http://mongrel.rubyforge.org/releases - $ gem install mongrel --source=http://mongrel.rubyforge.org/releases - -Fastthread didn't change so you don't need the first install if you've got it already. - - -h2. Nov 24: 0.3.17 Almost 1.0 RC1 - -We're hard at work getting the hot new win32 service Luis wrote out -and ready for production. We're hoping to have that included in the -1.0 RC1 release we make very soon. - -This pre-release is just to make sure that we didn't step on any toes. -Install it with: - - $ gem install fastthread --source=http://mongrel.rubyforge.org/releases - $ gem install mongrel --source=http://mongrel.rubyforge.org/releases - -The fastthread gem implements mentalguy's fastthread set of Thread locking -alternatives. It is optional, so if it causes you problems, remove it from -your gems: - - $ gem uninstall fastthread - -Restart Mongrel and all will be as it was before. The fastthread stuff will -hopefully make Mongrel a little quicker and also reduce it's memory leakage -potential. - -I've also updated all the stale documentation, including the -"Apache documentation":/docs/apache.html and added information -pimping people's "books":/books.html including *mine*. If there's -a book I've missed then shoot me an e-mail and I'll pimp it equally -as well. I want as much information for Mongrel as possible available -to as many people as possible. - -Finally, there's an "Atom":http://www.atomenabled.org/ feed available -which will let people track changes to all the documentation. Try it -at "http://mongrel.rubyforge.org/feed.atom":http://mongrel.rubyforge.org/feed.atom -and let me know how you like it. - -"Read the ChangeLog":http://mongrel.rubyforge.org/releases/ChangeLog - -h2. Sep 18: Finally! 0.3.13.4 Is Official (for Unix)! - -Everyone's favorite web server went gold this weekend. I let it sit for -a while to make sure all the remaining bugs were out, and people seem to -be doing really well with the pre-release. This release only fixes the -problem of Start, Restart, Stop, and Stats class names clashing with -people's Rails models. Otherwise, if you've been tracking the periodic -releases then you know what's up. - -I'll be posting *win32* releases and a full change log over the next week. -This release should be very stable and once everyone's actually migrated -to it and I've worked out any remaining kinks I'll bump the version up -before working on 0.4. - -h3. INSTALLING - -As usual you install it using: - - gem install mongrel - -And I'm really really sorry about the forty thousand gems that get listed. -I promise to drive one of the RubyGems guys into a corner until they help -me clean that mess out. - -*Win32* people will be able to upgrade in the next week or so. - -h3. CHANGE LOG - -Coming soon... it's lots of stuff. - -h2. Jun 30: Mongrel 0.3.13.3 -- Ruby Licensed Release - -After talking with various people deep inside the Ruby machine, I've decided -to release Mongrel Ruby licensed as of 0.3.13.3. This release should make -quite a few people happy. It also means that contributors will hopefully -feel better about their contributions and people using Mongrel have more freedom. - -This release also fixes a problem with the -B option not actually logging -object counts. The object count logging isn't perfect, but some folks use -it. - -This release also will print the access log to the screen when you run it in -your console. This was requested by a few folks, but I'm not convinced I like -it. Try it out and if you do or don't then mention it in the mailing list. - -As usual, do your: - - gem install mongrel - -To get the release, and if it doesn't show up then you have to wait -for the ruby gems mirror to sync up. - -h2. Jun 25: Mongrel 0.3.13.2 -- RailsConf 2006 Release - -This is the release that came out of RailsConf hacking with folks like Rick -Olsen, Why The Luck Stiff and other incredibly cool folks. The conference -was great, so lets hope this release is good too. The big thing it adds -is *upload progress in Mongrel*. That's right, Why and Rick pinned me down -and made me put it in Mongrel. They worked up the mongrel_upload_progress -plugin and are now working on Rails and Camping code to make it happen. - -Install from the gem servers with your usual commands: - - gem update - - *or* - - gem update mongrel - - *or* - - gem install mongrel - -But if you can't wait for the gem mirrors to update, then you can also do: - - gem install mongrel --source=http://mongrel.rubyforge.org/releases - -To get around it all. - - -h2. Jun 20: Mongrel 0.3.13.2 Pre-Release -- Small Fixes - -This is a small release that fixes a little bug, some of the documentation, -and adds the new RedirectHandler code and a @redirect@ call for the mongrel.conf -files. It's fresh so don't rely on it. Everyone should upgrade with the -usual *gem update* command (which tells you it's "Upgrading...") and tell -me how it works. - -This release fixes: - -* The -C configure file option was busted because of an errant line move. -* Adds RedirectHandler thanks to Jonas Pfenniger and a new redirect call to Configurator. -* Fixes mongrel_service documentation which was referring to -r instead of -c and -C instead of -u. - -h3. Using RedirectHandler - -Redirects are pretty simple. You simply have either a new RedirectHandler class you can -use or you can put this in a mongrel.conf and pass that to -S: - - redirect "/from", "/to" - -It also accepts regex for the @from@ parameter and can take a block. Play with it -if you're interested. - -h3. Deflate And Safari - -It looks like Safari does not honor the @Content-Encoding: deflate@ response, so -avoid using DeflateFilter until I can find out why. *This* is why you don't hand -code network protocol parsers. - - -h2. Jun 16: Mongrel 0.3.13 -- Finally Out! - -After a huge push, tons of delays to fix bugs and add enhancements, and lots of -feedback and contributions from many great people, I'm happy to announce the -official *release of Mongrel 0.3.13*. - -This release features lots of documentation, cleaned status output, improved IO processing, -a major bug fix for a thread leak, and an improvement in the win32 support. - -Read below from past news for all the stuff that was fixed. The main change that *win32* folks -should be aware of is they have to install a second little gem to get the services support. -This is slightly annoying, but the change makes it possible to work independently on the services -support and not hold back future Mongrel releases. - -h3. Getting The Release - -For normal people you should do this: - - $ sudo gem install mongrel - -Of use update. If update don't work then remove mongrel and re-install. - -h3. Win32: Getting The Release - -For *win32* people, you just do this: - - $ gem install mongrel - $ gem install mongrel_service - -When you do the install, pick the mswin32 version. After you install the -mongrel_service you now just use @mongrel_rails@ like everyone else, but -you get some new fancy @service::@ commands. - -h3. Reporting Bugs - -Send them to the mailing list and make sure you have your OS, versions, web server, -etc. - - -h2. Jun 5: Mongrel 0.3.13 Pre-Release -- Katana Suicide Concurrency - -We are *days* away from the official 0.3.13 release, which will be followed -quickly by 0.4 code named Enterprisey Edition 1.2. This latest pre-release -update closes off the last of the annoying bugs, and adds one very nasty -feature people should check out before we release. Read about Katanas below. - -@This release doesn't have win32 yet. That'll be uploaded Monday.@ - -h3. GETTING IT - -Best thing to do is this: - - $ gem install daemons - $ gem install mongrel --source=http://mongrel.rubyforge.org/releases/ - -h3. WHAT'S FIXED - -* Fixes a failure of -P to find PID files. -* Changes the RailsHandler so that only passes GET or HEAD requests to the DirHandler for page caching. -* Confirms that the new send_file and upload to tempfile works on win32. More tests with big files uploaded on win32 are needed. -* Lots of documentation on installing, with more to come. Full Apache documentation and information on writing your own snazzy handlers and filters. -* François SIMOND suggested a check for allow_concurrency and to avoid locking Rails if that's set to true. I tried it, had to change the patch but I left it in. Read below. -* Moved some of the "change to user/group" code around so that any Mongrel command can use it. -* Various code clean-ups and big improvements on the unit test coverage and reporting. Check out "the coverage report":http://mongrel.rubyforge.org/coverage/ -* Lots of thrashing and code review, not much more will come for 0.3.13 unless an obviously broken piece needs work. - - -h3. KATANA SUICIDE CONCURRENCY - -I resisted doing this, but it's going to come down sooner or later now that -François SIMOND figured it out. Mongrel was protecting the world from the -allow_concurrency "feature" but now it lets you kill yourself in obscenely -horrible ways. - -If you set ActionController::Base.allow_concurrency=true in your -config/environments/* then Mongrel will *NOT* guard the Rails Dispatcher. This -means that you'll get full threaded madness thrashing -your Rails controllers until they die horribly slicing -themselves into tiny little bits leaving you breathless -with the destruction. - -Mongrel will obnoxiously warn you about this, and people who try it will NOT -get support from me without mad amounts of dough. If you turn this on, and -your world comes crashing around your head, then I warned you. Otherwise, go -ahead and give it a try and see if that improves things for you. - -Enjoy the release, and "report those bugs":http://rubyforge.org/tracker/?atid=5145&group_id=1306&func=browse - - -h2. May 11: Mongrel 0.3.13 Pre-Release -- Out of Hibernation - -This release is the long awaited 0.3.13 with the fancy -file upload and conditional response code. It's also -the start to the big push toward 0.4 Mongrel Enterprisey Edition 1.2. - -The big fixes and features in 0.3.13 are: - -* Lots of documentation being written or already written. -* Large file uploads are streamed to a temp file rather than ram. (Thanks Why!) -* Conditional HTTP responses for static files. (Thanks Dan Kubb!) -* A fix to the start command's --help so that --num-procs and --timeout are more clear. -* A fix to the -B option since some idiot decided that they can change the object_id of an object to take a parameter. -* No longer spews tons of junk to mongrel.log related to invalid parsing or closed client sockets. -* Documented HttpRequest's escape, unescape, and query_parse (which were stolen from Camping). -* Removed some compiler warnings for unused variables in the C extension. -* Rake now aborts with an obvious message if the http11 extension doesn't build. -* Requires 'resolv-replace' by default to prevent DNS queries from blocking Mongrel. - -This release is right now in pre-release state while I work on the -documentation. Please grab it and test it with the following: - - gem install daemons - gem install mongrel --source=http://mongrel.rubyforge.org/releases/ - -As usual, win32 folks will have to wait while I test out this build -on Windows. - - -h2. Apr-10: Mongrel 0.3.12.4 -- Relaxed Parser, Date Fix - -This release is a small change over the previous one. It mostly is for -people who want to use Mongrel for webdav which needs its own set of -request types (what people like to annoyingly call "verbs"). It also -fixes a date formatting error where the month wasn't three characters long. - -* Corrects the date format returned so that months are three chars only. -* Fixes a problem where DirHandler wasn't returning Last-Modified and Etag -headers for unknown MIME types. -* Implements a default mime type for anything it doesn't know about, and -lets you set it via an attribute in DirHandler if you want different. -* Cleans up the file serving code in DirHandler a bit. -* Relaxes the parser to that it will accept any request methods as long as -they are upper case, digits, safe chars ($ - _ .) and with length from 1-20 -characters. Anything outside this restriction is still rejected with a -close. - -You can get it from the gem repository like normal. People who are on -win32 should have no problems but there will be another small release -that cleans up the win32 code in the near future. - - -h2. Apr-3: Mongrel 0.3.12.2 -- Thread Debugging - -This release has a small fix for a big problem where people uploading -files or using multipart forms would not receive the CONTENT_TYPE and -get garbage in their request parameters. - -It also adds a few things to help people debug their use of threads -within their Ruby on Rails applications. When you run mongrel_rails -with the -B (debugging) option Mongrel will report all active threads -between each request to log/mongrel_debug/thread.log. If you see -reports of Mongrel being overloaded, threads getting killed, or having -to wait for Mongrel to shutdown then turn on debugging and look in this -log. You most likely are doing something that keeps the thread from -exiting. - -Mongrel also deals with dead threads much better. First the graceful shutdown -will wait 10 seconds for a request to finish before aborting it -during the shutdown process. Second it will find processing threads which have -taken longer than 60+timeout seconds and kill them. Finally, you -can put a value into your own Thread.current and when you use the thread.log -you can figure out which controller's and actions are creating the -bad threads. - -For example, lets say you see a thread leak. Many times this is caused -by trying to make a connection to a remote resource that isn't there, -but you're not sure. What you do is put this into the suspected -controller's action: - - Thread.current[:bad_controller_action] = true - -Or some of other tag to differentiate it with the other threads. Then -run Mongrel with -B and if you see this in the KEYS list then you know -that this is the controller. - -Finally, there seems to be a bug in Rails where it is constantly dropping -the connection to MySQL. I've found this error on nearly everything and -it's worse when you run WEBrick. It seems to get a little better when -you set *ActionController::Base.allow_concurrency* in your config/environments -the problem is lessened especially if you run Mongrel. - -I'm still trying to determine the cause of this, but if you see this problem -please report it to me with what system you are running and how often -you see it. *Remember, this is a Rails problem not a Mongrel problem -since I see it with WEBrick, FastCGI, SCGI, and on Win32, FreeBSD, OSX, and Linux.* - - -h2. Apr-3: Mongrel 0.3.12.2 -- Iron Mongrel - -!/images/iron_mongrel.jpg! - -This is the Iron Mongrel release. It is the result of trying to trash Mongrel -until it can't move and then fixing anything that comes up. The testing -methods used are: - -# Increased the number of unit tests against the main C parts. -# Write several tests against Mongrel's parser which throw it tons of random data. -# Use "Peach Fuzz":http://peachfuzz.sourceforge.net/ to thrash several live apps with randomness. -# Wrote several extensive little scripts to explore the edges of death for Mongrel. -# Heavy code audits covering as much code as possible to find any possible loose ends. - -The end result is a lot of little fixes which make Mongrel more robust against -badly behaving clients and possibly against many potential security risks in -the future. In general Mongrel 0.3.12.2 behaves more consistently compared -to past releases when given random data or maliciously formatted data. - -The main changes are related to how IO is processed and how the HTTP parser rejects -"bad" input. What the parser now blocks is: - -* Any header over 112k. -* Any query string over 10k. -* Any header field value over 80k. -* Any header field name over 256 bytes. -* Any request URI greater than 512 bytes. - -As soon as these conditions are detected the client is disconnected immediately and a -log message is printed out listing the IP address, the exact cause, and the data that caused it. I'll -remove the data dump later, but I want people to shoot me valid requests that cause parser -errors. - -That's not all though. I've started a "security":security.html page where I'll publish -the results of security threats, tests, and improvements as well as any advice for -folks. - -This release also features a few little features here and there: - -* Initial support for a "config script". I'll be documenting this more, but it basically lets you use the Mongrel::RailsConfigurator to augment your application's config via a small script. Just pass "-S config/mongrel.rb" and put any Mongrel::RailsConfigurator statements that are reasonable. -* Mongrel will report the correct REMOTE_ADDR variable, but it does a little trick where if there -is an X-FORWARDED-FOR header then it sets REMOTE_ADDR to that. -* Fixes for little bugs like double log messages, but not a lot of changes to the overall core. - -Go ahead and install the usual way: gem install mongrel *or* gem upgrade - -The logo is courtesy court3nay from "caboose":http://caboo.se/ - -h2. Mar-30: Mongrel 0.3.12 -- OFFICIAL Release - -This is the long awaited (like 2 weeks) 0.3.12 release of Mongrel. This release -has received heavier testing than previous releases and supports a whole raft of -improvements to existing functionality plus some new stuff. The big points of this -release are: - -* The Mongrel::Configurator and Mongrel::Rails::Configurator for simple configuration (mostly for frameworks to use). -* Dynamically loadable handlers from the GemPlugins system. Next release will let you write and add your own handlers. -* Chained handlers. That's right, you can stack a series of handlers on any URIs and they'll be processed in order. This gives you an advanced and fast pipe-lined processing system and is already used to implement the extensive debugging support Mongrel has. -* Debugging, Debugging, Debugging. Try the -B option and then look in the log/mongrel_debug logs. I'll be beefing this up to insane usefulness for the 0.3.13 release. -* Support for sendfile on FreeBSD, Linux, and Solaris if you install the "ruby-sendfile":http://rubyforge.org/projects/ruby-sendfile gem. This is experimental but already gives a 20% boost on static files. -* Additional proper headers for static files from the DirHandler in order to allow browsers to cache the content. People using Mongrel for development or small sites will love this combined with the sendfile support. -* Lots and lots of little tweaks to improve speed. Mongrel is starting to hit a wall again with performance so I'll be looking for new hot-spots to move to C in the near future. -* Initial support for Rails 1.1. Remember *if you use Typo it is broken not Mongrel*. Typo is being frantically fixed so be patient. -* Fix for a bad typo on Win32 that prevented people from using additional mime types files (stupid Emacs and it's damn capitalize command being exactly the same as Copy in every other editor). -* Ability to specify a timeout throttling setting and a max number of concurrent connections with additional attempts at cleaning dead threads out. Future debugging will help people spot these. -* Lots of new Camping support and integration (thanks to Trotter Cashion for using Mongrel with Camping like crazy). -* A handy -C option for the mongrel_rails script that lets you specify the options you'd normally do on the command line as a YAML hash. More on this later. - -Everyone can go "download 0.3.12":http://rubyforge.org/frs/?group_id=1306 like normal or do the usual -"gem install mongrel" or "gem update" to get the latest and greatest. - - If you followed pre-release please uninstall first. - -Enjoy and report those bugs! - -h3. Next Stop, Funded - -The next steps with Mongrel will be to add the capability for users of Mongrel to write their own Configurator scripts and to test the living daylights out of it. If you missed my last announcement, Mongrel is getting *commercial sponsorship* from EastMedia (http://www.eastmedia.com/) in partnership with VeriSign (http://www.verisign.com/) for use in a potentially large scale project. My role in this is to make sure Mongrel can handle the required role and will not ever crash. I'll be spending the next few weeks putting out less features and doing more stability and speed tweaks. Stay tuned. Should be fun. - -h2. Mar-27: Mongrel 0.3.12 -- Pre-Release - -This release is a little different as it's larger than previous releases and -therefore needs to have more testing before I put it on the regular gem -servers. People interested in testing will install using: - - $ gem uninstall mongrel - $ gem uninstall gem_plugin - $ gem install mongrel --source=http://mongrel.rubyforge.org/releases/ - -Windows people may need to uninstall their services and re-install them. Please let me -know if this happens to you. Otherwise test this with your apps and tell me how it works. - -Adventurous people on FreeBSD or Linux (maybe Solaris) might want to do "gem install sendfile" -as well to see if they get faster static file serving. Worked for me on FreeBSD no problems. - -This release features an insane number of changes, too frequent to mention -in just this little new snippet, but here's the big ones: - -* A more complete "Mongrel::Configurator":http://mongrel.rubyforge.org/rdoc/classes/Mongrel/Configurator.html and "Mongrel::Rails::RailsConfigurator":http://mongrel.rubyforge.org/rdoc/classes/Mongrel/Rails/RailsConfigurator.html -* The mongrel_rails script is implemented using the new Configurator scheme and works much better. -* Win32 start-up scripts are adapted to the new setup but not using the Configurator. -* You can pass a config file to mongrel_rails start and it will load that (command line options override). -* Graceful restart works more reliably (not in Win32 since it uses services). -* Reload works better and doesn't break the restart. -* More logging of the start-up process. -* There is a wicked nice debugging framework that logs object counts, open files, and request params. Try mongrel_rails start -B and look in log/mongrel_debug. -* The Rails specific components are now in Mongrel::Rails modules. -* More examples using the Mongrel::Configurator. -* Dramatic speed improvements on FreeBSD, especially if you install the ruby18-nopthreads version. -* Slight speed improvements on Mac OSX. -* Platforms that can install "ruby-sendfile":http://rubyforge.org/projects/ruby-sendfile will get an estimated 20% speed boost in static file serving. This is currently FreeBSD, Linux, and Solaris. -* Lots of little bug fixes and minor speed tweaks. - -I'm holding the official 0.3.12 release until after Rails 1.1 is officially released so I can test it. - -Please do the install process and try out your applications for me. I'll be posting some hand - -h2. Mar-15: Mongrel 0.3.11 -- Edge Rails Compliant - -The main thing with this release is that it works with edge Rails -and has all the right dependencies. There was a nasty bug with -how RubyGems loads auto required gems when any dependency is loaded. -In order to avoid this GemPlugins will now require the init.rb for -the plugin directly rather than through RubyGems. There are also -other little tweaks to clean up how Rails runs. - -The second thing for this release is full Win32 support for all tweaks -including the nice TCP hack from Sean Treadway, the new GemPlugins system, -and a *nice* mongrel_config setup. The new mongrel_config lets you manage -all of your Mongrel Rails services from one web page and doesn't require -any Rails to run. - -"Download 0.3.11":http://rubyforge.org/frs/?group_id=1306 - -h2. Mar-12: Mongrel 0.3.10.1 -- Big Release Day - -This release is a bigger release than those in the -past but it was necessary as it touched many little -parts of the code base and includes a more complete -GemPlugin functionality. This release features the -following changes: - -* GemPlugin now supports including and easily finding resources and config files - you package with your gems. -* GemPlugin loading doesn't use any deprecated RubyGems APIs. -* GemPlugin comes with a generator called *gpgen* that will make it easy to start off - a plugin project. -* A complete document on "Writing A Mongrel Plugin":/docs/gem_plugin.html that - also explains how they work. -* The "Mongrel Config Tool":/images/config_tool_snap.png that demonstrates - building a useful command for controlling a Mongrel server. -** It uses a "Camping":http://camping.rubyforge.org/ to present an interface. -** Demonstrates combining Camping handlers with Mongrel handlers. -** Shows how to use the new GemPlugin resources API to include ERB templates, images, - and CSS stylesheets which are loaded out of the gem (no external install needed). -* Restructuring of the project source a bit to support testing all the - default plugins and to make building much easier. -* Properly loads any gems that depend on Rails (including GemPlugins) until the - very last minute after Rails is loaded and configured. -* A slight hack courtesy of Sean Treadway which jacks up the default server - listen queue from 5 to 1024. This should work on all platforms where - available and should improve concurrency for everyone. -* A more complete and useful Camping postamble that makes it the same size - as the WEBrick one. Also makes sure that Camping handlers and Mongrel - handlers can live in peace together. - -There's also a bunch of bug fixes: - -* Should work well with edge rails now and tries to be very nice. -* It holds of Rails configuration until the absolute latest time to - avoid having the daemonize call from closing log files Rails opens. -* Tweaks to the API docs in various places and cleaned out dead code. -* Lots of fixes to the build. If you get the source and are on Unix - you can just do "rake install" to install the whole thing via gems. - -This release has been tested on Linux, OSX, and FreeBSD with only -light testing on Win32. I'll be making the 0.3.11 release Win32 -specific so that the config tool can be useful for those folks too. - -Otherwise this is a large release so please grab it and test like -mad. - -"Download 0.3.10":http://rubyforge.org/frs/?group_id=1306 - - -h2. Mar-06: Mongrel 0.3.9 -- Gem Based Plugins - -This release features the beginning of a plugin system based -on RubyGems to dynamically load installed plugins for Mongrel. -The gist of it is that plugin authors create gems that users -install via *gem install snazzy_plugin*. Users then automagically -get that plugin for Mongrel. - -What I've done with this release is break out this functionality -into a new sub-project called "GemPlugin":gem_plugin_rdoc and -released it with a Ruby license (rather than LGPL like Mongrel). -This will let anyone else who needs a similar plugin system to -*steal* this blind and use it. - -A sample plugin is available that you can install after this update. -Just do: - - $ gem install mongrel_status - -If you run mongrel_rails now you'll see a new command "status". -Change to a Rails application directory where you have a daemon -running and it'll print out the PID. - -There will be tons of documentation coming out, and the ability -to write Handlers and Filters this way as well. Feel free -to write any Mongrel commands you want. - -A final note: This isn't hooked into win32 yet. That should -come tomorrow. - -"Download 0.3.9":http://rubyforge.org/frs/?group_id=1306 - -h2. Mar-04: Mongrel 0.3.8 -- Bug Fix Release - -A small release that fixes a few bugs reported to the tracker and adds -one enhancement that was requested. Rails applications can now access -the RailsHandler that is being used and then work with the DirHandler -that is responsible for serving files. For example: - - render_text @request.cgi.handler.files.can_serve(@request['PATH_INFO']) - -Will return the physical location of the given URI. This will be the basis -of an improved send_file and possibly file-upload system. - -* Fix for mongrel_rails_service -n parameter name clash. -* Fix for giving mongrel_rails_service paths with spaces in the name. -* Fix for a compiler warning in the C extension on Debian. -* Improvement to the Rakefile for cleanly building win32 and regular gems. -* Access to RailsHandler from within Rails applications. -* Tested Platforms: Linux, Win32, FreeBSD, OSX - -"Download 0.3.8":http://rubyforge.org/frs/?group_id=1306 - - -h2. Mar-03: Mongrel 0.3.7.1 -- Solid Rails, Win32, SwitchTower, Docs - -A slightly longer time between releases but this is packed with lots of good -things for people who want to run Mongrel. We're talking Win32 CPU affinity, -better service, POSIX signal control for SwitchTower, more tested platforms, -little bug fixes, and documentation on deployment best practices. - -This release has also been tested on tons of platforms: Linux, NetBSD, FreeBSD, -Windows, and Mac OSX. Under FreeBSD Mongrel seems to ignore signals unless -you do one more network connection, but the other platforms work great. - -* Initial beginning of the plugin support that will let people write - their own handlers and other things for Mongrel. -* Timeout now works again but couldn't find an alternative to the buggy Timeout class. -* SwitchTower friendly signal handling for mongrel_rails. -* Win32: New option that lets you set a mongrel service's CPU affinity. -* Win32: Indicates default environment used for the services. -* Win32: Avoids touching signals when on windows. -* A fix for CGI encoding redirects wrong when SERVER_PORT isn't specified. -* Tested on: Linux, Win32, FreeBSD, NetBSD, OSX. - -"Download 0.3.7":http://rubyforge.org/frs/?group_id=1306 - - -h2. Feb-22: Mongrel 0.3.6 -- Win32 Services Galore - -Thanks to Luis Lavena we have an almost complete win32 service -runner and management script that lets you setup services in windows for -all the different rails apps you have. This means you can control the -services from the command line or from the Services console. -"Check the Win32 HOWTO":docs/win32.html for more information on using it. -It still has some problems with stopping, but otherwise it's great. - -"Download 0.3.6":http://rubyforge.org/frs/?group_id=1306 - -h2. Feb-18: Mongrel 0.3.5 -- CGI Actually Works - -The CGIWrapper code I had written was complete and utter crap, so -I rewrote it and now it should be very correct. After looking at -more CGI code I think I'll set my sights on the CGI::process, CGI::Cookie::process, -and read_multipart functions as the next place to put my efforts. These -three functions are so full of hand coded parsing that rewriting them with -a Ragel processor would be a huge gain. - -"Download 0.3.5":http://rubyforge.org/frs/?group_id=1306 - -h2. Feb-16: Mongrel 0.3.4 -- Win32 Pre-built Gems - -This release has pre-built win32 gems thanks to Wilson Bilkovich attacking the -Rakefile and hooking up some build instructions for me. You should now be able -to install on win32 without a build system just like with other projects. - -I've also managed to clean up the CGIWrapper so that it works better with Mongrel -to Rails integration. It should be much more stable and serve files correctly, and -it's been tested with eXPlain PMT as well as Typo. The next release will involve -automated tests against as many Rails applications as I can find. - -Finally, there is a fix for the command subsystem for a nil error when you didn't -give mongrel_rails a command. It now lists the commands. - -There is a small warning message I threw in that I want people to report if they -see. You'll know it if you see it in the log/mongrel.log file or on the console. - -"Download 0.3.4":http://rubyforge.org/frs/?group_id=1306 - - -h2. Feb-14: Mongrel 0.3.3 Released - -This is a very small release that does nothing but add a one line fix -for a major bug. Basically, the 0.3.2 release works great with Rails, -but other runners will have problems since I didn't require the timeout -library needed. Everyone should upgrade. - -"Download 0.3.3":http://rubyforge.org/frs/?group_id=1306 - -h2. Feb-13: Mongrel 0.3.2 Released - -Lots of little things people asked for in 0.3.1 release. Changes are: - -* FAQ questions answered on threading and deployment scenarios. -* Added some additional text to make the side icons a little clearer. -* Created a "dogs":/dogs.html page with some people's favorite pets. -* Write out a better message for *mongrel_rails start* giving the environment and other stuff. -* Default to using ENV['RAILS_ENV'] or "default" as environment. -* Removed the restriction on the environments so people can have custom ones. -* Added options for: -** _-n_ Number of processor threads. -** _-t_ Timeout for each processor before it kills a request. -** _-m_ Specify additional MIME type mappings in YAML format. -** _-c_ Change to directory before starting (both for start and stop commands) -** _-r_ Use a different document root from "public" -* Use "rb" as open mode on all platforms (for windows binary files) -* Fixed bug in DirHandler which prevented people from altering MIME mapping. - -"Download 0.3.2":http://rubyforge.org/frs/?group_id=1306 - -h2. Feb-12: Mongrel 0.3.1 Released - -This release improves the support for Ruby On Rails, creates a new -Command/Plugin functionality, and fixes a huge nasty bug in how content -was served with Rails. If you saw weird file serving such as broken -images and other bad downloads then this is the fix for you. - -"Download 0.3.1":http://rubyforge.org/frs/?group_id=1306 - - -h2. Feb-12: New site created. - -This is kind of an experiment in seeing what type of site is possible -using just Creative Commons licensed content. See the "attributions":attributions.html -page for more information. - - - diff --git a/site/src/not_mongrel.page b/site/src/not_mongrel.page deleted file mode 100644 index b7ff121..0000000 --- a/site/src/not_mongrel.page +++ /dev/null @@ -1,97 +0,0 @@ ---- -title: Not Mongrel -inMenu: true -directoryName: Not Mongrel ---- - -h1. What Mongrel Isn't - -h2. Or, Write Your Own Damn Web Server - -Every once in a while I get someone who sends me an e-mail a lot like this: - - "Hey Zed! I got this great idea for Mongrel. All you have to do is - completely change the internal processing, add 200 more methods to the HTTP - parser, make it run on Solaris ZFS with AIX backends, serve Bittorrent over - Ethernet, and have it save Korean orphans while eating a Mango in the back - seat of an El Camino driven by twenty midget clowns. If you do that I'll be - rich! Uh, we'll be rich!" - -Mongrel is an HTTP server for Ruby applications. It does the bare minimum necessary to -serve a Ruby application. That's it. No more, no less. I fight off features all the -time until they're absolutely needed, and usually if someone needs it they can write -their own special GemPlugin and serve it up without even talking to me. Mongrel is -great that way and I love when people extend it for their own uses. - -Notice I said "I love it when people extend it for their own uses." I didn't say -any of the following: - -* "I love doing other people's dirty work so that they can make millions off the sweat on my back." -* "I am your whore, so sure I'll get right to writing that Bittorrent client." -* "I would love to be your corporate tool since I'm all about getting screwed." -* "Wow that idea is so brilliant I think I'll sign an NDA right away so you can take all my rights and all my work." - -If you have a feature that you think would be great for Mongrel, then go for it, but you -implement it first. I can give you advice, give you help, encouragement, meet you for -coffee at conferences and I'll even take reasonable patches if you find bugs and do come up -with nice little ideas. - -But don't send me monster patches that make your application work better and expect -it to get put into the Mongrel core within the hour. This is called "code fisting". - -h2. Code Fisting - -I worked with this guy once who walked into my office one day to tell me that -he had started reorganizing the code base for the product. Problem was he -started this completely useless reorganization two days before a big -deployment, checked it into the CVS repository without telling anyone, didn't -get it working at all, and then had to go on vacation that same day. He was in -my office to *tell* me to clean up his mess since his changes completely broke -the build. He did all of this without telling anyone or asking first. - -This is "code fisting", where you shove large amounts of code at people where -it isn't wanted. When you do this all you're doing is pissing off the people -you work with and costing your employer money. In an open source project it -can get you kicked out, ridiculed in public, and jeopardize your reputation. - -I find that people who do this seem to not understand the #1 rule about working -with others on a software project: - - "Whenever you do something make sure it causes the least amount of suffering - for others." - -Change is important and the project needs it to improve, but if you go -thrusting your nasty designs on other people in surprise Ninja moves then -you're not following the rule. - -So how do you reduce the suffering that comes from big changes? - -h2. Code Lube - -Code lube is the answer to *necessary* code fisting. Code lube is a -combination of communication, coordination, and gently applying your changes -slowly over time until they're in sync with the rest of the world. You have to -baby step the other participants and if they aren't receptive, then put your -stuff into a patch or a branch and come back to it later. - -This includes changes that aren't related to code. Deployments need to be -heavily coordinated. Moving servers, changing database schemas, installing new -versions of tools, and changing important documentation all require talking -with people. - - -h2. Contributing To Mongrel - -Hook everyone up with a bit of code lube. Talk with people on the project, -contribute something small and useful first. Don't just change all the -STDERR usage to $stderr so that you can get a nice printout for your unit -tests (especially when there's already a simpler existing way). Talk with -people first and see if they're receptive. - -If they're not receptive, take the Mongrel code and do it yourself. You never -know, maybe we're all stupid and you're brilliant. Since Mongrel is open source -and you've apparently got the free time, then grab the code and try out your -idea. If it turns out to be a great one *then* talk with people to get it -implemented. - -Otherwise, have fun with the project. diff --git a/site/src/plugins.page b/site/src/plugins.page deleted file mode 100644 index 8ac946d..0000000 --- a/site/src/plugins.page +++ /dev/null @@ -1,22 +0,0 @@ ---- -title: Plugins -inMenu: true -directoryName: Plugins ---- - -h1. Available Mongrel Plugins - -Mongrel is designed to be *very* easy to extend with the "GemPlugin":/gem_plugin_rdoc/index.html system. With GemPlugin anyone can extend Mongrel's commands or handlers then distribute them as regular RubyGems for people to install. - -To install a plugin you typically install it like you do any other gem by running @gem install GEMNAME@ and replace GEMNAME with the name below. All gems are managed by their authors, but most authors hang out in the "mailing list":http://rubyforge.org/mailman/listinfo/mongrel-users and will answer your questions. - -* mongrel_cluster -- Very sweet plugin that lets you manage pack of Mongrels easily as well as dealing with Capistrano issues. - -h2. Getting Your Plugin Listed - -Just shoot a message to the "mailing list":http://rubyforge.org/mail/?group_id=1306 -and you'll get hooked up. - -h2. Licensing - -Mongrel and GemPlugin are both "licensed the same as Ruby":/license.page so you can use it the same as Ruby. diff --git a/site/src/security.page b/site/src/security.page deleted file mode 100644 index b7d169d..0000000 --- a/site/src/security.page +++ /dev/null @@ -1,75 +0,0 @@ ---- -title: Security -inMenu: true -directoryName: Security -ordering: 2 ---- - -!/images/iron_mongrel.jpg! - -h1. Iron Mongrel Security - -This is where we'll be putting security tests, alerts, and advice for people running Mongrel. We test Mongrel fairly heavily using the following techniques: - -# Unit testing what I can. Mongrel is a server so many tests have to be done "live". -# Thrashing Mongrel's HTTP parser internally with random or near-random data (called fuzzing). -# Using "Peach Fuzz":http://peachfuzz.sourceforge.net/ to thrash several live apps with randomness. -# Running several extensive little scripts to explore the edges of death for Mongrel. -# Heavy code audits covering as much code as possible to find any possible loose ends. - -The end result is a lot of little fixes which make Mongrel more robust against badly behaving clients and possibly against many potential security risks in the future. - - -h2. Mongrels HTTP Restrictions - -Many of the exploits out there currently for web servers tend to exploit either -ambiguous areas of the HTTP grammar, or the lack of size specifications in the -protocol. To protect against this Mongrel uses a fairly strict parser, but -since many browser authors don't read specifications (and hell, who'd want to -read the mountain of HTTP specifications out there), it can't be too -strict. What it does enforce (apart from well formed headers and request -lines) is the following size restrictions on each part: - -* Any header over 112k. -* Any query string over 10k. -* Any header field value over 80k. -* Any header field name over 256 bytes. -* Any request URI greater than 512 bytes. - -The large header size and field value is due to cookies being allowed to be so -massive. It's not too clear whether a browser is allowed to cram all 20 of the -4k cookies into one cookie header, or if it should use multiple, but the end -result is that a web server has to parser at least 112k of garbage before it -can declare a client malicious. - -Now, when we say Mongrel is strict, we don't mean that it will abort on any minor -little error according to the HTTP 1.1 RFC. Mongrel's parser is pretty -forgiving on formats. Where Mongrel is exact is (as mentioned before) in it's -treatment of sizes and boundary characters. Clients that can't even get that -right aren't following the most basic safety elements of HTTP and you probably -shouldn't deal with them. - - -h2. Quiet Things Happens To Bad People - -Rather than wasting any more time--and in order to not give out any information -to potentially malicious attackers--Mongrel just closes the socket immediately. -This may confuse good people, but it's the best way to deal with bad requests. - -The assumption is that either the requesting client is not functioning -correctly or it's attempting an attack. If it's not functioning correctly then -what's the point of sending back any results? It probably can't parse them -anyway. If it's an attacker then why give them any more information? - -Caught in the middle are people who are using a poorly written client. We'd -suggest in those cases that they report the problem to the client's authors or -contact us to see if it's an error on Mongrel's part. - -h2. Reporting Security Problems - -If you think you've found a security problem with Mongrel, please report it to the list right away at http://rubyforge.org/mailman/listinfo/mongrel-users. We're usually very responsive and will probably help even if the security problem is outside of Mongrel or if you need help securing your system. - -h2. Logo - -The logo is courtesy court3nay from "caboose":http://caboo.se/ - diff --git a/site/src/sitemap.page b/site/src/sitemap.page deleted file mode 100644 index 05f652d..0000000 --- a/site/src/sitemap.page +++ /dev/null @@ -1,10 +0,0 @@ ---- -title: Sitemap -inMenu: true -directoryName: Sitemap -ordering: 4 ---- - -h1. Sitemap - -{sitemap: } \ No newline at end of file -- cgit v1.2.3-24-ge0c7 From 58caf568843cf25fcc3c916541b15cb05ea042c2 Mon Sep 17 00:00:00 2001 From: evanweaver Date: Wed, 13 Feb 2008 05:32:51 +0000 Subject: Remove site tasks that no longer apply. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-1@958 19e92222-5c0b-0410-8929-a290d50e31e9 --- Rakefile | 39 ++------------------------------------- 1 file changed, 2 insertions(+), 37 deletions(-) diff --git a/Rakefile b/Rakefile index f47d7a2..6b2aba9 100644 --- a/Rakefile +++ b/Rakefile @@ -9,6 +9,7 @@ e = Echoe.new("mongrel") do |p| p.clean_pattern = ['ext/http11/*.{bundle,so,o,obj,pdb,lib,def,exp}', 'lib/*.{bundle,so,o,obj,pdb,lib,def,exp}', 'ext/http11/Makefile', 'pkg', 'lib/*.bundle', '*.gem', 'site/output', '.config', 'lib/http11.jar', 'ext/http11_java/classes', 'coverage'] p.url = "http://mongrel.rubyforge.org" p.rdoc_pattern = ['README', 'LICENSE', 'CHANGELOG', 'COPYING', 'lib/**/*.rb', 'doc/**/*.rdoc'] + p.docs_host = 'mongrel.cloudbur.st:/home/eweaver/www/mongrel/htdocs/web' p.ignore_pattern = /^(pkg|site|projects|doc|log)|CVS|\.log/ p.ruby_version = '>=1.8.4' p.dependencies = ['gem_plugin >=0.2.3'] @@ -194,44 +195,8 @@ end #### Site upload tasks namespace :site do - - desc "Package and upload .gem files and .tgz files for Mongrel and all subprojects to http://mongrel.rubyforge.org/releases/" - task :source => [:package_all] do - rm_rf "pkg/gems" - rm_rf "pkg/tars" - mkdir_p "pkg/gems" - mkdir_p "pkg/tars" - - FileList["**/*.gem"].each { |gem| mv gem, "pkg/gems" } - FileList["**/*.tgz"].each {|tgz| mv tgz, "pkg/tars" } - - sh "rm -rf pkg/mongrel*" - sh "gem generate_index -d pkg" - sh "scp -r CHANGELOG pkg/* rubyforge.org:/var/www/gforge-projects/mongrel/releases/" - sh "svn log -v > SVN_LOG" - sh "scp -r SVN_LOG pkg/* rubyforge.org:/var/www/gforge-projects/mongrel/releases/" - rm "SVN_LOG" - end - - desc "Upload the website" - task :web do - # Requires the 'webgem' gem - sh "cd site; webgen; webgen; curl 'http://feed43.com/mongrel.xml' > output/rss.xml; rsync -azv --no-perms --no-times output/* rubyforge.org:/var/www/gforge-projects/mongrel/" - puts "\nMake sure to re-run the site update 6 hours later if you updated the news. This delay is required for Feed43 to pick up the site changes." - end - - desc "Upload the rdocs" - task :rdoc => [:doc] do - sh "rsync -azv --no-perms --no-times doc/* rubyforge.org:/var/www/gforge-projects/mongrel/rdoc/" - sh "cd projects/gem_plugin; rake site:rdoc" - end - desc "Upload the coverage report" task :coverage => [:rcov] do - sh "rsync -azv --no-perms --no-times test/coverage/* rubyforge.org:/var/www/gforge-projects/mongrel/coverage/" rescue nil + sh "rsync -azv --no-perms --no-times test/coverage/* mongrel.cloudbur.st:/home/eweaver/www/mongrel/htdocs/web/coverage" rescue nil end - - desc "Upload the website, the rdocs, and the coverage report" - task :all => [:clean, :web, :rdoc, :coverage] - end -- cgit v1.2.3-24-ge0c7 From cf0c084f0a82f532bde1a168e2478a57f102bced Mon Sep 17 00:00:00 2001 From: evanweaver Date: Wed, 20 Feb 2008 04:48:42 +0000 Subject: Failing test for pass traversal issue. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-1@963 19e92222-5c0b-0410-8929-a290d50e31e9 --- lib/mongrel/handlers.rb | 16 ++++++---------- test/test_handlers.rb | 26 +++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 13 deletions(-) diff --git a/lib/mongrel/handlers.rb b/lib/mongrel/handlers.rb index 9b9798e..2a6bca4 100644 --- a/lib/mongrel/handlers.rb +++ b/lib/mongrel/handlers.rb @@ -8,7 +8,6 @@ require 'mongrel/stats' require 'zlib' require 'yaml' - module Mongrel # You implement your application handler with this. It's very light giving @@ -102,7 +101,8 @@ module Mongrel # # If you pass nil as the root path, it will not check any locations or # expand any paths. This lets you serve files from multiple drives - # on win32. + # on win32. It should probably not be used in a public-facing way + # without additional checks. # # The default content type is "text/plain; charset=ISO-8859-1" but you # can change it anything you want using the DirHandler.default_content_type @@ -120,7 +120,7 @@ module Mongrel # You give it the path to the directory root and and optional listing_allowed and index_html def initialize(path, listing_allowed=true, index_html="index.html") @path = File.expand_path(path) if path - @listing_allowed=listing_allowed + @listing_allowed = listing_allowed @index_html = index_html @default_content_type = "application/octet-stream".freeze end @@ -132,12 +132,8 @@ module Mongrel # Add the drive letter or root path req_path = File.join(@path, req_path) if @path req_path = File.expand_path req_path - - # do not remove the check for @path at the beginning, it's what prevents - # the serving of arbitrary files (and good programmer Rule #1 Says: If - # you don't understand something, it's not because I'm stupid, it's - # because you are). - if req_path.index(@path) == 0 and File.exist? req_path + + if File.exist? req_path # and (!@path or req_path.index(@path) == 0) # It exists and it's in the right location if File.directory? req_path # The request is for a directory @@ -157,7 +153,7 @@ module Mongrel return req_path end else - # does not exist or isn't in the right spot or isn't valid because not start with @path + # does not exist or isn't in the right spot return nil end end diff --git a/test/test_handlers.rb b/test/test_handlers.rb index 72abbbc..1005dd0 100644 --- a/test/test_handlers.rb +++ b/test/test_handlers.rb @@ -49,11 +49,17 @@ class HandlersTest < Test::Unit::TestCase uri "/relative", :handler => Mongrel::DirHandler.new(nil, listing_allowed=false, index_html="none") end end + + File.open("/tmp/testfile", 'w') do + # Do nothing + end + @config.run end def teardown @config.stop(false, true) + File.delete "/tmp/testfile" end def test_more_web_server @@ -66,14 +72,28 @@ class HandlersTest < Test::Unit::TestCase "http://localhost:9998/files_nodir/rdoc/", "http://localhost:9998/status", ]) - - # XXX This can't possibly have good coverage. check_status res, String end + + def test_nil_dirhandler + # Camping uses this internally + handler = Mongrel::DirHandler.new(nil, false) + assert handler.can_serve("/tmp/testfile") + # Not a bug! A nil @file parameter is the only circumstance under which + # we are allowed to serve any existing file + assert handler.can_serve("../../../../../../../../../../tmp/testfile") + end + + def test_non_nil_dirhandler_is_not_vulnerable_to_path_traversal + # The famous security bug of Mongrel 1.1.2 + handler = Mongrel::DirHandler.new("/doc", false) + assert_nil handler.can_serve("/tmp/testfile") + assert_nil handler.can_serve("../../../../../../../../../../tmp/testfile") + end def test_deflate Net::HTTP.start("localhost", 9998) do |h| - # test that no accept-encoding returns a non-deflated response + # Test that no accept-encoding returns a non-deflated response req = h.get("/dumb") assert( !req['Content-Encoding'] || -- cgit v1.2.3-24-ge0c7 From 0f8b09cf115fea94d9135a71e2189e00703b4fc2 Mon Sep 17 00:00:00 2001 From: evanweaver Date: Wed, 20 Feb 2008 04:48:59 +0000 Subject: Restore fix for path traversal issue; fix camping handler. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-1@964 19e92222-5c0b-0410-8929-a290d50e31e9 --- lib/mongrel/handlers.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mongrel/handlers.rb b/lib/mongrel/handlers.rb index 2a6bca4..e643025 100644 --- a/lib/mongrel/handlers.rb +++ b/lib/mongrel/handlers.rb @@ -133,7 +133,7 @@ module Mongrel req_path = File.join(@path, req_path) if @path req_path = File.expand_path req_path - if File.exist? req_path # and (!@path or req_path.index(@path) == 0) + if File.exist? req_path and (!@path or req_path.index(@path) == 0) # It exists and it's in the right location if File.directory? req_path # The request is for a directory -- cgit v1.2.3-24-ge0c7 From 3998dcf8a1fe28a9f7c36370a406dcc912da8e8b Mon Sep 17 00:00:00 2001 From: evanweaver Date: Wed, 20 Feb 2008 04:55:39 +0000 Subject: Update the changelog. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-1@965 19e92222-5c0b-0410-8929-a290d50e31e9 --- CHANGELOG | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG b/CHANGELOG index a578579..88ada4b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,4 +1,6 @@ +v1.1.4. Fix camping handler. + v1.1.3. Fix security flaw of DirHandler; reported on mailing list. v1.1.2. Fix worker termination bug; fix JRuby 1.0.3 load order issue; fix require issue on systems without Rubygems. -- cgit v1.2.3-24-ge0c7 From ad445e765221dcfe5dffe98457dd7dc2f21c02fa Mon Sep 17 00:00:00 2001 From: evanweaver Date: Wed, 20 Feb 2008 04:59:41 +0000 Subject: Close #10 (@throttle wrongly treated as seconds instead of 100th of seconds). git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-1@966 19e92222-5c0b-0410-8929-a290d50e31e9 --- lib/mongrel.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mongrel.rb b/lib/mongrel.rb index 9451748..d99c56d 100644 --- a/lib/mongrel.rb +++ b/lib/mongrel.rb @@ -96,7 +96,7 @@ module Mongrel @host = host @port = port @workers = ThreadGroup.new - @throttle = throttle + @throttle = throttle / 100.0 @num_processors = num_processors @timeout = timeout end @@ -286,7 +286,7 @@ module Mongrel thread[:started_on] = Time.now @workers.add(thread) - sleep @throttle/100.0 if @throttle > 0 + sleep @throttle if @throttle > 0 end rescue StopServer break -- cgit v1.2.3-24-ge0c7 From 6dc90047ed8bbd1c5f3ac6416661e9e80b40526d Mon Sep 17 00:00:00 2001 From: evanweaver Date: Wed, 20 Feb 2008 05:02:39 +0000 Subject: Update changelog. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-1@967 19e92222-5c0b-0410-8929-a290d50e31e9 --- CHANGELOG | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG b/CHANGELOG index 88ada4b..6075d77 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,5 @@ -v1.1.4. Fix camping handler. +v1.1.4. Fix camping handler. Correct treatment of @throttle parameter. v1.1.3. Fix security flaw of DirHandler; reported on mailing list. -- cgit v1.2.3-24-ge0c7 From 8c6bb977323ce55127f42e9e71866a8575d80c56 Mon Sep 17 00:00:00 2001 From: evanweaver Date: Wed, 20 Feb 2008 05:27:46 +0000 Subject: TODO is now kept in the Trac milestones. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-1@969 19e92222-5c0b-0410-8929-a290d50e31e9 --- TODO | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 TODO diff --git a/TODO b/TODO deleted file mode 100644 index 3e32555..0000000 --- a/TODO +++ /dev/null @@ -1,5 +0,0 @@ - -v1.2. Rewrite and merge mongrel cluster and mongrel_rails into something small and maintainable. Remove gem_plugin entirely. - -v1.1.1. See if Java is setting the server version string in the request properly. - -- cgit v1.2.3-24-ge0c7 From 34983d6fd6e5b0f7c31d05e1b379162d68a3f5a8 Mon Sep 17 00:00:00 2001 From: evanweaver Date: Wed, 20 Feb 2008 05:28:03 +0000 Subject: Improve clean pattern so that it removes some extra log files the tests leave around. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-1@970 19e92222-5c0b-0410-8929-a290d50e31e9 --- Rakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index 6b2aba9..36f907e 100644 --- a/Rakefile +++ b/Rakefile @@ -6,7 +6,7 @@ require 'echoe' e = Echoe.new("mongrel") do |p| p.summary = "A small fast HTTP library and server that runs Rails, Camping, Nitro and Iowa apps." p.author ="Zed A. Shaw" - p.clean_pattern = ['ext/http11/*.{bundle,so,o,obj,pdb,lib,def,exp}', 'lib/*.{bundle,so,o,obj,pdb,lib,def,exp}', 'ext/http11/Makefile', 'pkg', 'lib/*.bundle', '*.gem', 'site/output', '.config', 'lib/http11.jar', 'ext/http11_java/classes', 'coverage'] + p.clean_pattern = ['ext/http11/*.{bundle,so,o,obj,pdb,lib,def,exp}', 'lib/*.{bundle,so,o,obj,pdb,lib,def,exp}', 'ext/http11/Makefile', 'pkg', 'lib/*.bundle', '*.gem', 'site/output', '.config', 'lib/http11.jar', 'ext/http11_java/classes', 'coverage', 'test_*.log', 'log'] p.url = "http://mongrel.rubyforge.org" p.rdoc_pattern = ['README', 'LICENSE', 'CHANGELOG', 'COPYING', 'lib/**/*.rb', 'doc/**/*.rdoc'] p.docs_host = 'mongrel.cloudbur.st:/home/eweaver/www/mongrel/htdocs/web' -- cgit v1.2.3-24-ge0c7 From 03f1d87de53de35d78a5ee5ae1c40b65586f2912 Mon Sep 17 00:00:00 2001 From: evanweaver Date: Wed, 20 Feb 2008 05:49:44 +0000 Subject: Add concurrency benchmarks, mostly copied from Thin's. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-1@971 19e92222-5c0b-0410-8929-a290d50e31e9 --- test/benchmark/previous.rb | 11 +++++++ test/benchmark/simple.rb | 11 +++++++ test/benchmark/utils.rb | 82 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 104 insertions(+) create mode 100644 test/benchmark/previous.rb create mode 100644 test/benchmark/simple.rb create mode 100644 test/benchmark/utils.rb diff --git a/test/benchmark/previous.rb b/test/benchmark/previous.rb new file mode 100644 index 0000000..8b6182a --- /dev/null +++ b/test/benchmark/previous.rb @@ -0,0 +1,11 @@ +# Benchmark to compare Mongrel performance against +# previous Mongrel version (the one installed as a gem). +# +# Run with: +# +# ruby previous.rb [num of request] +# + +require File.dirname(__FILE__) + '/utils' + +benchmark "print", %w(current gem), 1000, [1, 10, 100] diff --git a/test/benchmark/simple.rb b/test/benchmark/simple.rb new file mode 100644 index 0000000..906f74c --- /dev/null +++ b/test/benchmark/simple.rb @@ -0,0 +1,11 @@ +# +# Simple benchmark to compare Mongrel performance against +# other webservers supported by Rack. +# + +require File.dirname(__FILE__) + '/utils' + +libs = %w(current gem WEBrick EMongrel Thin) +libs = ARGV if ARGV.any? + +benchmark "print", libs, 1000, [1, 10, 100] diff --git a/test/benchmark/utils.rb b/test/benchmark/utils.rb new file mode 100644 index 0000000..feb22c1 --- /dev/null +++ b/test/benchmark/utils.rb @@ -0,0 +1,82 @@ + +require 'rubygems' +require 'rack' +require 'rack/lobster' + +def run(handler_name, n=1000, c=1) + port = 7000 + + server = fork do + [STDOUT, STDERR].each { |o| o.reopen "/dev/null" } + + case handler_name + when 'EMongrel' + require 'swiftcore/evented_mongrel' + handler_name = 'Mongrel' + + when 'Thin' + require 'thin' + hander_name = 'Thin' + + when 'gem' # Load the current Mongrel gem + require 'mongrel' + handler_name = 'Mongrel' + + when 'current' # Load the current Mongrel version under /lib + require File.dirname(__FILE__) + '/../lib/mongrel' + handler_name = 'Mongrel' + + end + + app = Rack::Lobster.new + + handler = Rack::Handler.const_get(handler_name) + handler.run app, :Host => '0.0.0.0', :Port => port + end + + sleep 2 + + out = `nice -n20 ab -c #{c} -n #{n} http://127.0.0.1:#{port}/ 2> /dev/null` + + Process.kill('SIGKILL', server) + Process.wait + + if requests = out.match(/^Requests.+?(\d+\.\d+)/) + requests[1].to_i + else + 0 + end +end + +def benchmark(type, servers, request, concurrency_levels) + send "#{type}_benchmark", servers, request, concurrency_levels +end + +def graph_benchmark(servers, request, concurrency_levels) + require '/usr/local/lib/ruby/gems/1.8/gems/gruff-0.2.9/lib/gruff' + g = Gruff::Area.new + g.title = "Server benchmark" + + servers.each do |server| + g.data(server, concurrency_levels.collect { |c| print '.'; run(server, request, c) }) + end + puts + + g.x_axis_label = 'Concurrency' + g.y_axis_label = 'Requests / sec' + g.labels = {} + concurrency_levels.each_with_index { |c, i| g.labels[i] = c.to_s } + + g.write('bench.png') + `open bench.png` +end + +def print_benchmark(servers, request, concurrency_levels) + puts 'server request concurrency req/s' + puts '=' * 42 + concurrency_levels.each do |c| + servers.each do |server| + puts "#{server.ljust(8)} #{request} #{c.to_s.ljust(4)} #{run(server, request, c)}" + end + end +end \ No newline at end of file -- cgit v1.2.3-24-ge0c7 From af1e1581afac9437e623eb54ef533f240858fd47 Mon Sep 17 00:00:00 2001 From: evanweaver Date: Wed, 20 Feb 2008 05:58:10 +0000 Subject: Add list of all known contributors. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-1@972 19e92222-5c0b-0410-8929-a290d50e31e9 --- CONTRIBUTORS | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 CONTRIBUTORS diff --git a/CONTRIBUTORS b/CONTRIBUTORS new file mode 100644 index 0000000..3268298 --- /dev/null +++ b/CONTRIBUTORS @@ -0,0 +1,17 @@ + +Zed A. Shaw +Luis Lavena +Wilson Bilkovich +Why the Lucky Stiff +Dan Kubb +MenTaLguY +Filipe Lautert +Rick Olson +Wayne E. Seguin +Kirk Haines +Bradley Taylor +Matt Pelletier +Ry Dahl +Nick Sieger +Evan Weaver +Marc-André Cournoyer -- cgit v1.2.3-24-ge0c7 From 5a10ba13b2c2f56b8ffb0978ebb36ff26a7715e5 Mon Sep 17 00:00:00 2001 From: evanweaver Date: Wed, 20 Feb 2008 06:15:30 +0000 Subject: Move tests from tests/ into tests/unit/ so they parallel tests/benchmark. They are mainly unit tests anyway; we can clean them up more moving forward. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-1@973 19e92222-5c0b-0410-8929-a290d50e31e9 --- test/test_cgi_wrapper.rb | 26 ---- test/test_command.rb | 86 ------------ test/test_conditional.rb | 107 --------------- test/test_configurator.rb | 87 ------------- test/test_debug.rb | 25 ---- test/test_handlers.rb | 123 ----------------- test/test_helper.rb | 66 ++++++++++ test/test_http11.rb | 156 ---------------------- test/test_redirect_handler.rb | 44 ------- test/test_request_progress.rb | 99 -------------- test/test_response.rb | 127 ------------------ test/test_stats.rb | 35 ----- test/test_uriclassifier.rb | 261 ------------------------------------- test/test_ws.rb | 115 ---------------- test/testhelp.rb | 66 ---------- test/unit/test_cgi_wrapper.rb | 26 ++++ test/unit/test_command.rb | 86 ++++++++++++ test/unit/test_conditional.rb | 107 +++++++++++++++ test/unit/test_configurator.rb | 87 +++++++++++++ test/unit/test_debug.rb | 25 ++++ test/unit/test_handlers.rb | 123 +++++++++++++++++ test/unit/test_http11.rb | 156 ++++++++++++++++++++++ test/unit/test_redirect_handler.rb | 44 +++++++ test/unit/test_request_progress.rb | 99 ++++++++++++++ test/unit/test_response.rb | 127 ++++++++++++++++++ test/unit/test_stats.rb | 35 +++++ test/unit/test_uriclassifier.rb | 261 +++++++++++++++++++++++++++++++++++++ test/unit/test_ws.rb | 115 ++++++++++++++++ 28 files changed, 1357 insertions(+), 1357 deletions(-) delete mode 100644 test/test_cgi_wrapper.rb delete mode 100644 test/test_command.rb delete mode 100644 test/test_conditional.rb delete mode 100644 test/test_configurator.rb delete mode 100644 test/test_debug.rb delete mode 100644 test/test_handlers.rb create mode 100644 test/test_helper.rb delete mode 100644 test/test_http11.rb delete mode 100644 test/test_redirect_handler.rb delete mode 100644 test/test_request_progress.rb delete mode 100644 test/test_response.rb delete mode 100644 test/test_stats.rb delete mode 100644 test/test_uriclassifier.rb delete mode 100644 test/test_ws.rb delete mode 100644 test/testhelp.rb create mode 100644 test/unit/test_cgi_wrapper.rb create mode 100644 test/unit/test_command.rb create mode 100644 test/unit/test_conditional.rb create mode 100644 test/unit/test_configurator.rb create mode 100644 test/unit/test_debug.rb create mode 100644 test/unit/test_handlers.rb create mode 100644 test/unit/test_http11.rb create mode 100644 test/unit/test_redirect_handler.rb create mode 100644 test/unit/test_request_progress.rb create mode 100644 test/unit/test_response.rb create mode 100644 test/unit/test_stats.rb create mode 100644 test/unit/test_uriclassifier.rb create mode 100644 test/unit/test_ws.rb diff --git a/test/test_cgi_wrapper.rb b/test/test_cgi_wrapper.rb deleted file mode 100644 index 449f6d0..0000000 --- a/test/test_cgi_wrapper.rb +++ /dev/null @@ -1,26 +0,0 @@ - -require 'test/testhelp' - -class MockHttpRequest - attr_reader :body - - def params - return { 'REQUEST_METHOD' => 'GET'} - end -end - -class CGIWrapperTest < Test::Unit::TestCase - - def test_set_cookies_output_cookies - request = MockHttpRequest.new - response = nil # not needed for this test - output_headers = {} - - cgi = Mongrel::CGIWrapper.new(request, response) - session = CGI::Session.new(cgi, 'database_manager' => CGI::Session::MemoryStore) - cgi.send_cookies(output_headers) - - assert(output_headers.has_key?("Set-Cookie")) - assert_equal("_session_id="+session.session_id+"; path=", output_headers["Set-Cookie"]) - end -end \ No newline at end of file diff --git a/test/test_command.rb b/test/test_command.rb deleted file mode 100644 index 3cb9643..0000000 --- a/test/test_command.rb +++ /dev/null @@ -1,86 +0,0 @@ -# Copyright (c) 2005 Zed A. Shaw -# You can redistribute it and/or modify it under the same terms as Ruby. -# -# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html -# for more information. - -require 'test/testhelp' - -class TestCommand < GemPlugin::Plugin "/commands" - include Mongrel::Command::Base - - def configure - options [ - ["-e", "--environment ENV", "Rails environment to run as", :@environment, ENV['RAILS_ENV'] || "development"], - ['', '--user USER', "User to run as", :@user, nil], - ["-d", "--daemonize", "Whether to run in the background or not", :@daemon, false], - ["-x", "--test", "Used to let the test run failures", :@test, false], - ] - end - - def validate - valid_dir? ".", "Can't validate current directory." - valid_exists? "Rakefile", "Rakefile not there, test is invalid." - if @test - valid_exist? "BADFILE", "Yeah, badfile" - valid_file? "BADFILE", "Not even a file" - valid_dir? "BADDIR", "No dir here" - valid? false, "Total failure" - end - - return @valid - end - - - def run - $test_command_ran = true - end -end - -class CommandTest < Test::Unit::TestCase - - def setup - $test_command_ran = false - end - - def teardown - end - - def run_cmd(args) - Mongrel::Command::Registry.instance.run args - end - - def test_run_command - redirect_test_io do - run_cmd ["testcommand"] - assert $test_command_ran, "command didn't run" - end - end - - def test_command_error - redirect_test_io do - run_cmd ["crapcommand"] - end - end - - def test_command_listing - redirect_test_io do - run_cmd ["help"] - end - end - - def test_options - redirect_test_io do - run_cmd ["testcommand","-h"] - run_cmd ["testcommand","--help"] - run_cmd ["testcommand","-e","test","-d","--user"] - end - end - - def test_version - redirect_test_io do - run_cmd ["testcommand", "--version"] - end - end - -end diff --git a/test/test_conditional.rb b/test/test_conditional.rb deleted file mode 100644 index cd3ce06..0000000 --- a/test/test_conditional.rb +++ /dev/null @@ -1,107 +0,0 @@ -# Copyright (c) 2005 Zed A. Shaw -# You can redistribute it and/or modify it under the same terms as Ruby. -# -# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html -# for more information. - -require 'test/testhelp' - -include Mongrel - -class ConditionalResponseTest < Test::Unit::TestCase - def setup - @server = HttpServer.new('127.0.0.1', 3501) - @server.register('/', Mongrel::DirHandler.new('.')) - @server.run - - @http = Net::HTTP.new(@server.host, @server.port) - - # get the ETag and Last-Modified headers - @path = '/README' - res = @http.start { |http| http.get(@path) } - assert_not_nil @etag = res['ETag'] - assert_not_nil @last_modified = res['Last-Modified'] - assert_not_nil @content_length = res['Content-Length'] - end - - def teardown - @server.stop(true) - end - - # status should be 304 Not Modified when If-None-Match is the matching ETag - def test_not_modified_via_if_none_match - assert_status_for_get_and_head Net::HTTPNotModified, 'If-None-Match' => @etag - end - - # status should be 304 Not Modified when If-Modified-Since is the matching Last-Modified date - def test_not_modified_via_if_modified_since - assert_status_for_get_and_head Net::HTTPNotModified, 'If-Modified-Since' => @last_modified - end - - # status should be 304 Not Modified when If-None-Match is the matching ETag - # and If-Modified-Since is the matching Last-Modified date - def test_not_modified_via_if_none_match_and_if_modified_since - assert_status_for_get_and_head Net::HTTPNotModified, 'If-None-Match' => @etag, 'If-Modified-Since' => @last_modified - end - - # status should be 200 OK when If-None-Match is invalid - def test_invalid_if_none_match - assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => 'invalid' - assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => 'invalid', 'If-Modified-Since' => @last_modified - end - - # status should be 200 OK when If-Modified-Since is invalid - def test_invalid_if_modified_since - assert_status_for_get_and_head Net::HTTPOK, 'If-Modified-Since' => 'invalid' - assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => @etag, 'If-Modified-Since' => 'invalid' - end - - # status should be 304 Not Modified when If-Modified-Since is greater than the Last-Modified header, but less than the system time - def test_if_modified_since_greater_than_last_modified - sleep 2 - last_modified_plus_1 = (Time.httpdate(@last_modified) + 1).httpdate - assert_status_for_get_and_head Net::HTTPNotModified, 'If-Modified-Since' => last_modified_plus_1 - assert_status_for_get_and_head Net::HTTPNotModified, 'If-None-Match' => @etag, 'If-Modified-Since' => last_modified_plus_1 - end - - # status should be 200 OK when If-Modified-Since is less than the Last-Modified header - def test_if_modified_since_less_than_last_modified - last_modified_minus_1 = (Time.httpdate(@last_modified) - 1).httpdate - assert_status_for_get_and_head Net::HTTPOK, 'If-Modified-Since' => last_modified_minus_1 - assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => @etag, 'If-Modified-Since' => last_modified_minus_1 - end - - # status should be 200 OK when If-Modified-Since is a date in the future - def test_future_if_modified_since - the_future = Time.at(2**31-1).httpdate - assert_status_for_get_and_head Net::HTTPOK, 'If-Modified-Since' => the_future - assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => @etag, 'If-Modified-Since' => the_future - end - - # status should be 200 OK when If-None-Match is a wildcard - def test_wildcard_match - assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => '*' - assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => '*', 'If-Modified-Since' => @last_modified - end - - private - - # assert the response status is correct for GET and HEAD - def assert_status_for_get_and_head(response_class, headers = {}) - %w{ get head }.each do |method| - res = @http.send(method, @path, headers) - assert_kind_of response_class, res - assert_equal @etag, res['ETag'] - case response_class.to_s - when 'Net::HTTPNotModified' then - assert_nil res['Last-Modified'] - assert_nil res['Content-Length'] - when 'Net::HTTPOK' then - assert_equal @last_modified, res['Last-Modified'] - assert_equal @content_length, res['Content-Length'] - else - fail "Incorrect response class: #{response_class}" - end - end - end -end diff --git a/test/test_configurator.rb b/test/test_configurator.rb deleted file mode 100644 index dd99f00..0000000 --- a/test/test_configurator.rb +++ /dev/null @@ -1,87 +0,0 @@ -# Copyright (c) 2005 Zed A. Shaw -# You can redistribute it and/or modify it under the same terms as Ruby. -# -# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html -# for more information. - -require 'test/testhelp' - -$test_plugin_fired = 0 - -class TestPlugin < GemPlugin::Plugin "/handlers" - include Mongrel::HttpHandlerPlugin - - def process(request, response) - $test_plugin_fired += 1 - end -end - - -class Sentinel < GemPlugin::Plugin "/handlers" - include Mongrel::HttpHandlerPlugin - - def process(request, response) - raise "This Sentinel plugin shouldn't run." - end -end - - -class ConfiguratorTest < Test::Unit::TestCase - - def test_base_handler_config - @config = nil - - redirect_test_io do - @config = Mongrel::Configurator.new :host => "localhost" do - listener :port => 4501 do - # 2 in front should run, but the sentinel shouldn't since dirhandler processes the request - uri "/", :handler => plugin("/handlers/testplugin") - uri "/", :handler => plugin("/handlers/testplugin") - uri "/", :handler => Mongrel::DirHandler.new(".") - uri "/", :handler => plugin("/handlers/testplugin") - - uri "/test", :handler => plugin("/handlers/testplugin") - uri "/test", :handler => plugin("/handlers/testplugin") - uri "/test", :handler => Mongrel::DirHandler.new(".") - uri "/test", :handler => plugin("/handlers/testplugin") - - debug "/" - setup_signals - - run_config(File.dirname(__FILE__) + "/../test/mongrel.conf") - load_mime_map(File.dirname(__FILE__) + "/../test/mime.yaml") - - run - end - end - end - - # pp @config.listeners.values.first.classifier.routes - - @config.listeners.each do |host,listener| - assert listener.classifier.uris.length == 3, "Wrong number of registered URIs" - assert listener.classifier.uris.include?("/"), "/ not registered" - assert listener.classifier.uris.include?("/test"), "/test not registered" - end - - res = Net::HTTP.get(URI.parse('http://localhost:4501/test')) - assert res != nil, "Didn't get a response" - assert $test_plugin_fired == 3, "Test filter plugin didn't run 3 times." - - redirect_test_io do - res = Net::HTTP.get(URI.parse('http://localhost:4501/')) - - assert res != nil, "Didn't get a response" - assert $test_plugin_fired == 6, "Test filter plugin didn't run 6 times." - end - - redirect_test_io do - @config.stop(false, true) - end - - assert_raise Errno::EBADF, Errno::ECONNREFUSED do - res = Net::HTTP.get(URI.parse("http://localhost:4501/")) - end - end - -end diff --git a/test/test_debug.rb b/test/test_debug.rb deleted file mode 100644 index 2f7be24..0000000 --- a/test/test_debug.rb +++ /dev/null @@ -1,25 +0,0 @@ -# Copyright (c) 2005 Zed A. Shaw -# You can redistribute it and/or modify it under the same terms as Ruby. -# -# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html -# for more information. - -require 'test/testhelp' -require 'mongrel/debug' - -class MongrelDbgTest < Test::Unit::TestCase - - def test_tracing_to_log - FileUtils.rm_rf "log/mongrel_debug" - - MongrelDbg::configure - out = StringIO.new - - MongrelDbg::begin_trace(:rails) - MongrelDbg::trace(:rails, "Good stuff") - MongrelDbg::end_trace(:rails) - - assert File.exist?("log/mongrel_debug"), "Didn't make logging directory" - end - -end diff --git a/test/test_handlers.rb b/test/test_handlers.rb deleted file mode 100644 index 1005dd0..0000000 --- a/test/test_handlers.rb +++ /dev/null @@ -1,123 +0,0 @@ -# Copyright (c) 2005 Zed A. Shaw -# You can redistribute it and/or modify it under the same terms as Ruby. -# -# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html -# for more information. - -require 'test/testhelp' - -class SimpleHandler < Mongrel::HttpHandler - def process(request, response) - response.start do |head,out| - head["Content-Type"] = "text/html" - results = "Your request:
#{request.params.to_yaml}
View the files." - out << results - end - end -end - -class DumbHandler < Mongrel::HttpHandler - def process(request, response) - response.start do |head,out| - head["Content-Type"] = "text/html" - out.write("test") - end - end -end - -def check_status(results, expecting) - results.each do |res| - assert(res.kind_of?(expecting), "Didn't get #{expecting}, got: #{res.class}") - end -end - -class HandlersTest < Test::Unit::TestCase - - def setup - stats = Mongrel::StatisticsFilter.new(:sample_rate => 1) - - @config = Mongrel::Configurator.new :host => '127.0.0.1', :port => 9998 do - listener do - uri "/", :handler => SimpleHandler.new - uri "/", :handler => stats - uri "/404", :handler => Mongrel::Error404Handler.new("Not found") - uri "/dumb", :handler => Mongrel::DeflateFilter.new - uri "/dumb", :handler => DumbHandler.new, :in_front => true - uri "/files", :handler => Mongrel::DirHandler.new("doc") - uri "/files_nodir", :handler => Mongrel::DirHandler.new("doc", listing_allowed=false, index_html="none") - uri "/status", :handler => Mongrel::StatusHandler.new(:stats_filter => stats) - uri "/relative", :handler => Mongrel::DirHandler.new(nil, listing_allowed=false, index_html="none") - end - end - - File.open("/tmp/testfile", 'w') do - # Do nothing - end - - @config.run - end - - def teardown - @config.stop(false, true) - File.delete "/tmp/testfile" - end - - def test_more_web_server - res = hit([ "http://localhost:9998/test", - "http://localhost:9998/dumb", - "http://localhost:9998/404", - "http://localhost:9998/files/rdoc/index.html", - "http://localhost:9998/files/rdoc/nothere.html", - "http://localhost:9998/files/rdoc/", - "http://localhost:9998/files_nodir/rdoc/", - "http://localhost:9998/status", - ]) - check_status res, String - end - - def test_nil_dirhandler - # Camping uses this internally - handler = Mongrel::DirHandler.new(nil, false) - assert handler.can_serve("/tmp/testfile") - # Not a bug! A nil @file parameter is the only circumstance under which - # we are allowed to serve any existing file - assert handler.can_serve("../../../../../../../../../../tmp/testfile") - end - - def test_non_nil_dirhandler_is_not_vulnerable_to_path_traversal - # The famous security bug of Mongrel 1.1.2 - handler = Mongrel::DirHandler.new("/doc", false) - assert_nil handler.can_serve("/tmp/testfile") - assert_nil handler.can_serve("../../../../../../../../../../tmp/testfile") - end - - def test_deflate - Net::HTTP.start("localhost", 9998) do |h| - # Test that no accept-encoding returns a non-deflated response - req = h.get("/dumb") - assert( - !req['Content-Encoding'] || - !req['Content-Encoding'].include?('deflate')) - assert_equal "test", req.body - - req = h.get("/dumb", {"Accept-Encoding" => "deflate"}) - # -MAX_WBITS stops zlib from looking for a zlib header - inflater = Zlib::Inflate.new(-Zlib::MAX_WBITS) - assert req['Content-Encoding'].include?('deflate') - assert_equal "test", inflater.inflate(req.body) - end - end - - # TODO: find out why this fails on win32 but nowhere else - #def test_posting_fails_dirhandler - # req = Net::HTTP::Post.new("http://localhost:9998/files/rdoc/") - # req.set_form_data({'from'=>'2005-01-01', 'to'=>'2005-03-31'}, ';') - # res = hit [["http://localhost:9998/files/rdoc/",req]] - # check_status res, Net::HTTPNotFound - #end - - def test_unregister - @config.listeners["127.0.0.1:9998"].unregister("/") - end -end - diff --git a/test/test_helper.rb b/test/test_helper.rb new file mode 100644 index 0000000..42ead2c --- /dev/null +++ b/test/test_helper.rb @@ -0,0 +1,66 @@ +# Copyright (c) 2005 Zed A. Shaw +# You can redistribute it and/or modify it under the same terms as Ruby. +# +# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html +# for more information. + + +HERE = File.dirname(__FILE__) +%w(lib ext bin test).each do |dir| + $LOAD_PATH.unshift "#{HERE}/../#{dir}" +end + +require 'rubygems' +require 'test/unit' +require 'net/http' +require 'timeout' +require 'cgi/session' +require 'fileutils' +require 'benchmark' +require 'digest/sha1' +require 'uri' +require 'stringio' +require 'pp' + +require 'mongrel' +require 'mongrel/stats' + +if ENV['DEBUG'] + require 'ruby-debug' + Debugger.start +end + +def redirect_test_io + orig_err = STDERR.dup + orig_out = STDOUT.dup + STDERR.reopen("test_stderr.log") + STDOUT.reopen("test_stdout.log") + + begin + yield + ensure + STDERR.reopen(orig_err) + STDOUT.reopen(orig_out) + end +end + +# Either takes a string to do a get request against, or a tuple of [URI, HTTP] where +# HTTP is some kind of Net::HTTP request object (POST, HEAD, etc.) +def hit(uris) + results = [] + uris.each do |u| + res = nil + + if u.kind_of? String + res = Net::HTTP.get(URI.parse(u)) + else + url = URI.parse(u[0]) + res = Net::HTTP.new(url.host, url.port).start {|h| h.request(u[1]) } + end + + assert res != nil, "Didn't get a response: #{u}" + results << res + end + + return results +end diff --git a/test/test_http11.rb b/test/test_http11.rb deleted file mode 100644 index da311af..0000000 --- a/test/test_http11.rb +++ /dev/null @@ -1,156 +0,0 @@ -# Copyright (c) 2005 Zed A. Shaw -# You can redistribute it and/or modify it under the same terms as Ruby. -# -# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html -# for more information. - -require 'test/testhelp' - -include Mongrel - -class HttpParserTest < Test::Unit::TestCase - - def test_parse_simple - parser = HttpParser.new - req = {} - http = "GET / HTTP/1.1\r\n\r\n" - nread = parser.execute(req, http, 0) - - assert nread == http.length, "Failed to parse the full HTTP request" - assert parser.finished?, "Parser didn't finish" - assert !parser.error?, "Parser had error" - assert nread == parser.nread, "Number read returned from execute does not match" - - assert_equal 'HTTP/1.1', req['SERVER_PROTOCOL'] - assert_equal '/', req['REQUEST_PATH'] - assert_equal 'HTTP/1.1', req['HTTP_VERSION'] - assert_equal '/', req['REQUEST_URI'] - assert_equal 'CGI/1.2', req['GATEWAY_INTERFACE'] - assert_equal 'GET', req['REQUEST_METHOD'] - assert_nil req['FRAGMENT'] - assert_nil req['QUERY_STRING'] - - parser.reset - assert parser.nread == 0, "Number read after reset should be 0" - end - - def test_parse_dumbfuck_headers - parser = HttpParser.new - req = {} - should_be_good = "GET / HTTP/1.1\r\naaaaaaaaaaaaa:++++++++++\r\n\r\n" - nread = parser.execute(req, should_be_good, 0) - assert_equal should_be_good.length, nread - assert parser.finished? - assert !parser.error? - - nasty_pound_header = "GET / HTTP/1.1\r\nX-SSL-Bullshit: -----BEGIN CERTIFICATE-----\r\n\tMIIFbTCCBFWgAwIBAgICH4cwDQYJKoZIhvcNAQEFBQAwcDELMAkGA1UEBhMCVUsx\r\n\tETAPBgNVBAoTCGVTY2llbmNlMRIwEAYDVQQLEwlBdXRob3JpdHkxCzAJBgNVBAMT\r\n\tAkNBMS0wKwYJKoZIhvcNAQkBFh5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMu\r\n\tdWswHhcNMDYwNzI3MTQxMzI4WhcNMDcwNzI3MTQxMzI4WjBbMQswCQYDVQQGEwJV\r\n\tSzERMA8GA1UEChMIZVNjaWVuY2UxEzARBgNVBAsTCk1hbmNoZXN0ZXIxCzAJBgNV\r\n\tBAcTmrsogriqMWLAk1DMRcwFQYDVQQDEw5taWNoYWVsIHBhcmQYJKoZIhvcNAQEB\r\n\tBQADggEPADCCAQoCggEBANPEQBgl1IaKdSS1TbhF3hEXSl72G9J+WC/1R64fAcEF\r\n\tW51rEyFYiIeZGx/BVzwXbeBoNUK41OK65sxGuflMo5gLflbwJtHBRIEKAfVVp3YR\r\n\tgW7cMA/s/XKgL1GEC7rQw8lIZT8RApukCGqOVHSi/F1SiFlPDxuDfmdiNzL31+sL\r\n\t0iwHDdNkGjy5pyBSB8Y79dsSJtCW/iaLB0/n8Sj7HgvvZJ7x0fr+RQjYOUUfrePP\r\n\tu2MSpFyf+9BbC/aXgaZuiCvSR+8Snv3xApQY+fULK/xY8h8Ua51iXoQ5jrgu2SqR\r\n\twgA7BUi3G8LFzMBl8FRCDYGUDy7M6QaHXx1ZWIPWNKsCAwEAAaOCAiQwggIgMAwG\r\n\tA1UdEwEB/wQCMAAwEQYJYIZIAYb4QgEBBAQDAgWgMA4GA1UdDwEB/wQEAwID6DAs\r\n\tBglghkgBhvhCAQ0EHxYdVUsgZS1TY2llbmNlIFVzZXIgQ2VydGlmaWNhdGUwHQYD\r\n\tVR0OBBYEFDTt/sf9PeMaZDHkUIldrDYMNTBZMIGaBgNVHSMEgZIwgY+AFAI4qxGj\r\n\tloCLDdMVKwiljjDastqooXSkcjBwMQswCQYDVQQGEwJVSzERMA8GA1UEChMIZVNj\r\n\taWVuY2UxEjAQBgNVBAsTCUF1dGhvcml0eTELMAkGA1UEAxMCQ0ExLTArBgkqhkiG\r\n\t9w0BCQEWHmNhLW9wZXJhdG9yQGdyaWQtc3VwcG9ydC5hYy51a4IBADApBgNVHRIE\r\n\tIjAggR5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMudWswGQYDVR0gBBIwEDAO\r\n\tBgwrBgEEAdkvAQEBAQYwPQYJYIZIAYb4QgEEBDAWLmh0dHA6Ly9jYS5ncmlkLXN1\r\n\tcHBvcnQuYWMudmT4sopwqlBWsvcHViL2NybC9jYWNybC5jcmwwPQYJYIZIAYb4QgEDBDAWLmh0\r\n\tdHA6Ly9jYS5ncmlkLXN1cHBvcnQuYWMudWsvcHViL2NybC9jYWNybC5jcmwwPwYD\r\n\tVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NhLmdyaWQt5hYy51ay9wdWIv\r\n\tY3JsL2NhY3JsLmNybDANBgkqhkiG9w0BAQUFAAOCAQEAS/U4iiooBENGW/Hwmmd3\r\n\tXCy6Zrt08YjKCzGNjorT98g8uGsqYjSxv/hmi0qlnlHs+k/3Iobc3LjS5AMYr5L8\r\n\tUO7OSkgFFlLHQyC9JzPfmLCAugvzEbyv4Olnsr8hbxF1MbKZoQxUZtMVu29wjfXk\r\n\thTeApBv7eaKCWpSp7MCbvgzm74izKhu3vlDk9w6qVrxePfGgpKPqfHiOoGhFnbTK\r\n\twTC6o2xq5y0qZ03JonF7OJspEd3I5zKY3E+ov7/ZhW6DqT8UFvsAdjvQbXyhV8Eu\r\n\tYhixw1aKEPzNjNowuIseVogKOLXxWI5vAi5HgXdS0/ES5gDGsABo4fqovUKlgop3\r\n\tRA==\r\n\t-----END CERTIFICATE-----\r\n\r\n" - parser = HttpParser.new - req = {} - #nread = parser.execute(req, nasty_pound_header, 0) - #assert_equal nasty_pound_header.length, nread - #assert parser.finished? - #assert !parser.error? - end - - def test_parse_error - parser = HttpParser.new - req = {} - bad_http = "GET / SsUTF/1.1" - - error = false - begin - nread = parser.execute(req, bad_http, 0) - rescue => details - error = true - end - - assert error, "failed to throw exception" - assert !parser.finished?, "Parser shouldn't be finished" - assert parser.error?, "Parser SHOULD have error" - end - - def test_fragment_in_uri - parser = HttpParser.new - req = {} - get = "GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.1\r\n\r\n" - assert_nothing_raised do - parser.execute(req, get, 0) - end - assert parser.finished? - assert_equal '/forums/1/topics/2375?page=1', req['REQUEST_URI'] - assert_equal 'posts-17408', req['FRAGMENT'] - end - - # lame random garbage maker - def rand_data(min, max, readable=true) - count = min + ((rand(max)+1) *10).to_i - res = count.to_s + "/" - - if readable - res << Digest::SHA1.hexdigest(rand(count * 100).to_s) * (count / 40) - else - res << Digest::SHA1.digest(rand(count * 100).to_s) * (count / 20) - end - - return res - end - - - def test_horrible_queries - parser = HttpParser.new - - # then that large header names are caught - 10.times do |c| - get = "GET /#{rand_data(10,120)} HTTP/1.1\r\nX-#{rand_data(1024, 1024+(c*1024))}: Test\r\n\r\n" - assert_raises Mongrel::HttpParserError do - parser.execute({}, get, 0) - parser.reset - end - end - - # then that large mangled field values are caught - 10.times do |c| - get = "GET /#{rand_data(10,120)} HTTP/1.1\r\nX-Test: #{rand_data(1024, 1024+(c*1024), false)}\r\n\r\n" - assert_raises Mongrel::HttpParserError do - parser.execute({}, get, 0) - parser.reset - end - end - - # then large headers are rejected too - get = "GET /#{rand_data(10,120)} HTTP/1.1\r\n" - get << "X-Test: test\r\n" * (80 * 1024) - assert_raises Mongrel::HttpParserError do - parser.execute({}, get, 0) - parser.reset - end - - # finally just that random garbage gets blocked all the time - 10.times do |c| - get = "GET #{rand_data(1024, 1024+(c*1024), false)} #{rand_data(1024, 1024+(c*1024), false)}\r\n\r\n" - assert_raises Mongrel::HttpParserError do - parser.execute({}, get, 0) - parser.reset - end - end - - end - - - - def test_query_parse - res = HttpRequest.query_parse("zed=1&frank=#{HttpRequest.escape('&&& ')}") - assert res["zed"], "didn't get the request right" - assert res["frank"], "no frank" - assert_equal "1", res["zed"], "wrong result" - assert_equal "&&& ", HttpRequest.unescape(res["frank"]), "wrong result" - - res = HttpRequest.query_parse("zed=1&zed=2&zed=3&frank=11;zed=45") - assert res["zed"], "didn't get the request right" - assert res["frank"], "no frank" - assert_equal 4,res["zed"].length, "wrong number for zed" - assert_equal "11",res["frank"], "wrong number for frank" - end - -end - diff --git a/test/test_redirect_handler.rb b/test/test_redirect_handler.rb deleted file mode 100644 index 2e03d48..0000000 --- a/test/test_redirect_handler.rb +++ /dev/null @@ -1,44 +0,0 @@ -# Copyright (c) 2005 Zed A. Shaw -# You can redistribute it and/or modify it under the same terms as Ruby. -# -# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html -# for more information. - -require 'test/testhelp' - -class RedirectHandlerTest < Test::Unit::TestCase - - def setup - redirect_test_io do - @server = Mongrel::HttpServer.new('127.0.0.1', 9998) - end - @server.run - @client = Net::HTTP.new('127.0.0.1', 9998) - end - - def teardown - @server.stop(true) - end - - def test_simple_redirect - tester = Mongrel::RedirectHandler.new('/yo') - @server.register("/test", tester) - - sleep(1) - res = @client.request_get('/test') - assert res != nil, "Didn't get a response" - assert_equal ['/yo'], res.get_fields('Location') - end - - def test_rewrite - tester = Mongrel::RedirectHandler.new(/(\w+)/, '+\1+') - @server.register("/test", tester) - - sleep(1) - res = @client.request_get('/test/something') - assert_equal ['/+test+/+something+'], res.get_fields('Location') - end - -end - - diff --git a/test/test_request_progress.rb b/test/test_request_progress.rb deleted file mode 100644 index ba21c27..0000000 --- a/test/test_request_progress.rb +++ /dev/null @@ -1,99 +0,0 @@ -# Copyright (c) 2005 Zed A. Shaw -# You can redistribute it and/or modify it under the same terms as Ruby. -# -# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html -# for more information. - -require 'test/testhelp' - -class UploadBeginHandler < Mongrel::HttpHandler - attr_reader :request_began, :request_progressed, :request_processed - - def initialize - @request_notify = true - end - - def reset - @request_began = false - @request_progressed = false - @request_processed = false - end - - def request_begins(params) - @request_began = true - end - - def request_progress(params,len,total) - @request_progressed = true - end - - def process(request, response) - @request_processed = true - response.start do |head,body| - body.write("test") - end - end - -end - -class RequestProgressTest < Test::Unit::TestCase - def setup - redirect_test_io do - @server = Mongrel::HttpServer.new("127.0.0.1", 9998) - end - @handler = UploadBeginHandler.new - @server.register("/upload", @handler) - @server.run - end - - def teardown - @server.stop(true) - end - - def test_begin_end_progress - Net::HTTP.get("localhost", "/upload", 9998) - assert @handler.request_began - assert @handler.request_progressed - assert @handler.request_processed - end - - def call_and_assert_handlers_in_turn(handlers) - # reset all handlers - handlers.each { |h| h.reset } - - # make the call - Net::HTTP.get("localhost", "/upload", 9998) - - # assert that each one was fired - handlers.each { |h| - assert h.request_began && h.request_progressed && h.request_processed, - "Callbacks NOT fired for #{h}" - } - end - - def test_more_than_one_begin_end_progress - handlers = [@handler] - - second = UploadBeginHandler.new - @server.register("/upload", second) - handlers << second - call_and_assert_handlers_in_turn(handlers) - - # check three handlers - third = UploadBeginHandler.new - @server.register("/upload", third) - handlers << third - call_and_assert_handlers_in_turn(handlers) - - # remove handlers to make sure they've all gone away - @server.unregister("/upload") - handlers.each { |h| h.reset } - Net::HTTP.get("localhost", "/upload", 9998) - handlers.each { |h| - assert !h.request_began && !h.request_progressed && !h.request_processed - } - - # re-register upload to the state before this test - @server.register("/upload", @handler) - end -end diff --git a/test/test_response.rb b/test/test_response.rb deleted file mode 100644 index 123ed98..0000000 --- a/test/test_response.rb +++ /dev/null @@ -1,127 +0,0 @@ -# Copyright (c) 2005 Zed A. Shaw -# You can redistribute it and/or modify it under the same terms as Ruby. -# -# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html -# for more information. - -require 'test/testhelp' - -include Mongrel - -class ResponseTest < Test::Unit::TestCase - - def test_response_headers - out = StringIO.new - resp = HttpResponse.new(out) - resp.status = 200 - resp.header["Accept"] = "text/plain" - resp.header["X-Whatever"] = "stuff" - resp.body.write("test") - resp.finished - - assert out.length > 0, "output didn't have data" - end - - def test_response_200 - io = StringIO.new - resp = HttpResponse.new(io) - resp.start do |head,out| - head["Accept"] = "text/plain" - out.write("tested") - out.write("hello!") - end - - resp.finished - assert io.length > 0, "output didn't have data" - end - - def test_response_duplicate_header_squash - io = StringIO.new - resp = HttpResponse.new(io) - resp.start do |head,out| - head["Content-Length"] = 30 - head["Content-Length"] = 0 - end - - resp.finished - - assert_equal io.length, 95, "too much output" - end - - - def test_response_some_duplicates_allowed - allowed_duplicates = ["Set-Cookie", "Set-Cookie2", "Warning", "WWW-Authenticate"] - io = StringIO.new - resp = HttpResponse.new(io) - resp.start do |head,out| - allowed_duplicates.each do |dup| - 10.times do |i| - head[dup] = i - end - end - end - - resp.finished - - assert_equal io.length, 734, "wrong amount of output" - end - - def test_response_404 - io = StringIO.new - - resp = HttpResponse.new(io) - resp.start(404) do |head,out| - head['Accept'] = "text/plain" - out.write("NOT FOUND") - end - - resp.finished - assert io.length > 0, "output didn't have data" - end - - def test_response_file - contents = "PLAIN TEXT\r\nCONTENTS\r\n" - require 'tempfile' - tmpf = Tempfile.new("test_response_file") - tmpf.binmode - tmpf.write(contents) - tmpf.rewind - - io = StringIO.new - resp = HttpResponse.new(io) - resp.start(200) do |head,out| - head['Content-Type'] = 'text/plain' - resp.send_header - resp.send_file(tmpf.path) - end - io.rewind - tmpf.close - - assert io.length > 0, "output didn't have data" - assert io.read[-contents.length..-1] == contents, "output doesn't end with file payload" - end - - def test_response_with_custom_reason - reason = "You made a bad request" - io = StringIO.new - resp = HttpResponse.new(io) - resp.start(400, false, reason) { |head,out| } - resp.finished - - io.rewind - assert_match(/.* #{reason}$/, io.readline.chomp, "wrong custom reason phrase") - end - - def test_response_with_default_reason - code = 400 - io = StringIO.new - resp = HttpResponse.new(io) - resp.start(code) { |head,out| } - resp.finished - - io.rewind - assert_match(/.* #{HTTP_STATUS_CODES[code]}$/, io.readline.chomp, "wrong default reason phrase") - end - -end - diff --git a/test/test_stats.rb b/test/test_stats.rb deleted file mode 100644 index 404870a..0000000 --- a/test/test_stats.rb +++ /dev/null @@ -1,35 +0,0 @@ -# Copyright (c) 2005 Zed A. Shaw -# You can redistribute it and/or modify it under the same terms as Ruby. -# -# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html -# for more information. - -require 'test/testhelp' - -class StatsTest < Test::Unit::TestCase - - def test_sampling_speed - out = StringIO.new - - s = Mongrel::Stats.new("test") - t = Mongrel::Stats.new("time") - - 100.times { s.sample(rand(20)); t.tick } - - s.dump("FIRST", out) - t.dump("FIRST", out) - - old_mean = s.mean - old_sd = s.sd - - s.reset - t.reset - 100.times { s.sample(rand(30)); t.tick } - - s.dump("SECOND", out) - t.dump("SECOND", out) - assert_not_equal old_mean, s.mean - assert_not_equal old_mean, s.sd - end - -end diff --git a/test/test_uriclassifier.rb b/test/test_uriclassifier.rb deleted file mode 100644 index 28af72c..0000000 --- a/test/test_uriclassifier.rb +++ /dev/null @@ -1,261 +0,0 @@ -# Copyright (c) 2005 Zed A. Shaw -# You can redistribute it and/or modify it under the same terms as Ruby. -# -# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html -# for more information. - -require 'test/testhelp' - -include Mongrel - -class URIClassifierTest < Test::Unit::TestCase - - def test_uri_finding - uri_classifier = URIClassifier.new - uri_classifier.register("/test", 1) - - script_name, path_info, value = uri_classifier.resolve("/test") - assert_equal 1, value - assert_equal "/test", script_name - end - - def test_root_handler_only - uri_classifier = URIClassifier.new - uri_classifier.register("/", 1) - - script_name, path_info, value = uri_classifier.resolve("/test") - assert_equal 1, value - assert_equal "/", script_name - assert_equal "/test", path_info - end - - def test_uri_prefix_ops - test = "/pre/fix/test" - prefix = "/pre" - - uri_classifier = URIClassifier.new - uri_classifier.register(prefix,1) - - script_name, path_info, value = uri_classifier.resolve(prefix) - script_name, path_info, value = uri_classifier.resolve(test) - assert_equal 1, value - assert_equal prefix, script_name - assert_equal test[script_name.length .. -1], path_info - - assert uri_classifier.inspect - assert_equal prefix, uri_classifier.uris[0] - end - - def test_not_finding - test = "/cant/find/me" - uri_classifier = URIClassifier.new - uri_classifier.register(test, 1) - - script_name, path_info, value = uri_classifier.resolve("/nope/not/here") - assert_nil script_name - assert_nil path_info - assert_nil value - end - - def test_exceptions - uri_classifier = URIClassifier.new - - uri_classifier.register("/test", 1) - - failed = false - begin - uri_classifier.register("/test", 1) - rescue => e - failed = true - end - - assert failed - - failed = false - begin - uri_classifier.register("", 1) - rescue => e - failed = true - end - - assert failed - end - - - def test_register_unregister - uri_classifier = URIClassifier.new - - 100.times do - uri_classifier.register("/stuff", 1) - value = uri_classifier.unregister("/stuff") - assert_equal 1, value - end - - uri_classifier.register("/things",1) - script_name, path_info, value = uri_classifier.resolve("/things") - assert_equal 1, value - - uri_classifier.unregister("/things") - script_name, path_info, value = uri_classifier.resolve("/things") - assert_nil value - - end - - - def test_uri_branching - uri_classifier = URIClassifier.new - uri_classifier.register("/test", 1) - uri_classifier.register("/test/this",2) - - script_name, path_info, handler = uri_classifier.resolve("/test") - script_name, path_info, handler = uri_classifier.resolve("/test/that") - assert_equal "/test", script_name, "failed to properly find script off branch portion of uri" - assert_equal "/that", path_info - assert_equal 1, handler, "wrong result for branching uri" - end - - def test_all_prefixing - tests = ["/test","/test/that","/test/this"] - uri = "/test/this/that" - uri_classifier = URIClassifier.new - - current = "" - uri.each_byte do |c| - current << c.chr - uri_classifier.register(current, c) - end - - - # Try to resolve everything with no asserts as a fuzzing - tests.each do |prefix| - current = "" - prefix.each_byte do |c| - current << c.chr - script_name, path_info, handler = uri_classifier.resolve(current) - assert script_name - assert path_info - assert handler - end - end - - # Assert that we find stuff - tests.each do |t| - script_name, path_info, handler = uri_classifier.resolve(t) - assert handler - end - - # Assert we don't find stuff - script_name, path_info, handler = uri_classifier.resolve("chicken") - assert_nil handler - assert_nil script_name - assert_nil path_info - end - - - # Verifies that a root mounted ("/") handler resolves - # such that path info matches the original URI. - # This is needed to accommodate real usage of handlers. - def test_root_mounted - uri_classifier = URIClassifier.new - root = "/" - path = "/this/is/a/test" - - uri_classifier.register(root, 1) - - script_name, path_info, handler = uri_classifier.resolve(root) - assert_equal 1, handler - assert_equal root, path_info - assert_equal root, script_name - - script_name, path_info, handler = uri_classifier.resolve(path) - assert_equal path, path_info - assert_equal root, script_name - assert_equal 1, handler - end - - # Verifies that a root mounted ("/") handler - # is the default point, doesn't matter the order we use - # to register the URIs - def test_classifier_order - tests = ["/before", "/way_past"] - root = "/" - path = "/path" - - uri_classifier = URIClassifier.new - uri_classifier.register(path, 1) - uri_classifier.register(root, 2) - - tests.each do |uri| - script_name, path_info, handler = uri_classifier.resolve(uri) - assert_equal root, script_name, "#{uri} did not resolve to #{root}" - assert_equal uri, path_info - assert_equal 2, handler - end - end - - if ENV['BENCHMARK'] - # Eventually we will have a suite of benchmarks instead of lamely installing a test - - def test_benchmark - - # This URI set should favor a TST. Both versions increase linearly until you hit 14 - # URIs, then the TST flattens out. - @uris = %w( - / - /dag /dig /digbark /dog /dogbark /dog/bark /dug /dugbarking /puppy - /c /cat /cat/tree /cat/tree/mulberry /cats /cot /cot/tree/mulberry /kitty /kittycat -# /eag /eig /eigbark /eog /eogbark /eog/bark /eug /eugbarking /iuppy -# /f /fat /fat/tree /fat/tree/mulberry /fats /fot /fot/tree/mulberry /jitty /jittyfat -# /gag /gig /gigbark /gog /gogbark /gog/bark /gug /gugbarking /kuppy -# /h /hat /hat/tree /hat/tree/mulberry /hats /hot /hot/tree/mulberry /litty /littyhat -# /ceag /ceig /ceigbark /ceog /ceogbark /ceog/cbark /ceug /ceugbarking /ciuppy -# /cf /cfat /cfat/ctree /cfat/ctree/cmulberry /cfats /cfot /cfot/ctree/cmulberry /cjitty /cjittyfat -# /cgag /cgig /cgigbark /cgog /cgogbark /cgog/cbark /cgug /cgugbarking /ckuppy -# /ch /chat /chat/ctree /chat/ctree/cmulberry /chats /chot /chot/ctree/cmulberry /citty /cittyhat - ) - - @requests = %w( - / - /dig - /digging - /dogging - /dogbarking/ - /puppy/barking - /c - /cat - /cat/shrub - /cat/tree - /cat/tree/maple - /cat/tree/mulberry/tree - /cat/tree/oak - /cats/ - /cats/tree - /cod - /zebra - ) - - @classifier = URIClassifier.new - @uris.each do |uri| - @classifier.register(uri, 1) - end - - puts "#{@uris.size} URIs / #{@requests.size * 10000} requests" - - Benchmark.bm do |x| - x.report do - # require 'ruby-prof' - # profile = RubyProf.profile do - 10000.times do - @requests.each do |request| - @classifier.resolve(request) - end - end - # end - # File.open("profile.html", 'w') { |file| RubyProf::GraphHtmlPrinter.new(profile).print(file, 0) } - end - end - end - end - -end - diff --git a/test/test_ws.rb b/test/test_ws.rb deleted file mode 100644 index f019122..0000000 --- a/test/test_ws.rb +++ /dev/null @@ -1,115 +0,0 @@ -# Copyright (c) 2005 Zed A. Shaw -# You can redistribute it and/or modify it under the same terms as Ruby. -# -# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html -# for more information. - -require 'test/testhelp' - -include Mongrel - -class TestHandler < Mongrel::HttpHandler - attr_reader :ran_test - - def process(request, response) - @ran_test = true - response.socket.write("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nhello!\n") - end -end - - -class WebServerTest < Test::Unit::TestCase - - def setup - @valid_request = "GET / HTTP/1.1\r\nHost: www.zedshaw.com\r\nContent-Type: text/plain\r\n\r\n" - - redirect_test_io do - # We set num_processors=1 so that we can test the reaping code - @server = HttpServer.new("127.0.0.1", 9998, num_processors=1) - end - - @tester = TestHandler.new - @server.register("/test", @tester) - redirect_test_io do - @server.run - end - end - - def teardown - redirect_test_io do - @server.stop(true) - end - end - - def test_simple_server - hit(['http://localhost:9998/test']) - assert @tester.ran_test, "Handler didn't really run" - end - - - def do_test(string, chunk, close_after=nil, shutdown_delay=0) - # Do not use instance variables here, because it needs to be thread safe - socket = TCPSocket.new("127.0.0.1", 9998); - request = StringIO.new(string) - chunks_out = 0 - - while data = request.read(chunk) - chunks_out += socket.write(data) - socket.flush - sleep 0.2 - if close_after and chunks_out > close_after - socket.close - sleep 1 - end - end - sleep(shutdown_delay) - socket.write(" ") # Some platforms only raise the exception on attempted write - socket.flush - end - - def test_trickle_attack - do_test(@valid_request, 3) - end - - def test_close_client - assert_raises IOError do - do_test(@valid_request, 10, 20) - end - end - - def test_bad_client - redirect_test_io do - do_test("GET /test HTTP/BAD", 3) - end - end - - def test_header_is_too_long - redirect_test_io do - long = "GET /test HTTP/1.1\r\n" + ("X-Big: stuff\r\n" * 15000) + "\r\n" - assert_raises Errno::ECONNRESET, Errno::EPIPE, Errno::ECONNABORTED, Errno::EINVAL, IOError do - do_test(long, long.length/2, 10) - end - end - end - - def test_num_processors_overload - redirect_test_io do - assert_raises Errno::ECONNRESET, Errno::EPIPE, Errno::ECONNABORTED, Errno::EINVAL do - tests = [ - Thread.new { do_test(@valid_request, 1) }, - Thread.new { do_test(@valid_request, 10) }, - ] - - tests.each {|t| t.join} - end - end - end - - def test_file_streamed_request - body = "a" * (Mongrel::Const::MAX_BODY * 2) - long = "GET /test HTTP/1.1\r\nContent-length: #{body.length}\r\n\r\n" + body - do_test(long, Mongrel::Const::CHUNK_SIZE * 2 -400) - end - -end - diff --git a/test/testhelp.rb b/test/testhelp.rb deleted file mode 100644 index 42ead2c..0000000 --- a/test/testhelp.rb +++ /dev/null @@ -1,66 +0,0 @@ -# Copyright (c) 2005 Zed A. Shaw -# You can redistribute it and/or modify it under the same terms as Ruby. -# -# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html -# for more information. - - -HERE = File.dirname(__FILE__) -%w(lib ext bin test).each do |dir| - $LOAD_PATH.unshift "#{HERE}/../#{dir}" -end - -require 'rubygems' -require 'test/unit' -require 'net/http' -require 'timeout' -require 'cgi/session' -require 'fileutils' -require 'benchmark' -require 'digest/sha1' -require 'uri' -require 'stringio' -require 'pp' - -require 'mongrel' -require 'mongrel/stats' - -if ENV['DEBUG'] - require 'ruby-debug' - Debugger.start -end - -def redirect_test_io - orig_err = STDERR.dup - orig_out = STDOUT.dup - STDERR.reopen("test_stderr.log") - STDOUT.reopen("test_stdout.log") - - begin - yield - ensure - STDERR.reopen(orig_err) - STDOUT.reopen(orig_out) - end -end - -# Either takes a string to do a get request against, or a tuple of [URI, HTTP] where -# HTTP is some kind of Net::HTTP request object (POST, HEAD, etc.) -def hit(uris) - results = [] - uris.each do |u| - res = nil - - if u.kind_of? String - res = Net::HTTP.get(URI.parse(u)) - else - url = URI.parse(u[0]) - res = Net::HTTP.new(url.host, url.port).start {|h| h.request(u[1]) } - end - - assert res != nil, "Didn't get a response: #{u}" - results << res - end - - return results -end diff --git a/test/unit/test_cgi_wrapper.rb b/test/unit/test_cgi_wrapper.rb new file mode 100644 index 0000000..a494655 --- /dev/null +++ b/test/unit/test_cgi_wrapper.rb @@ -0,0 +1,26 @@ + +require 'test/test_helper' + +class MockHttpRequest + attr_reader :body + + def params + return { 'REQUEST_METHOD' => 'GET'} + end +end + +class CGIWrapperTest < Test::Unit::TestCase + + def test_set_cookies_output_cookies + request = MockHttpRequest.new + response = nil # not needed for this test + output_headers = {} + + cgi = Mongrel::CGIWrapper.new(request, response) + session = CGI::Session.new(cgi, 'database_manager' => CGI::Session::MemoryStore) + cgi.send_cookies(output_headers) + + assert(output_headers.has_key?("Set-Cookie")) + assert_equal("_session_id="+session.session_id+"; path=", output_headers["Set-Cookie"]) + end +end \ No newline at end of file diff --git a/test/unit/test_command.rb b/test/unit/test_command.rb new file mode 100644 index 0000000..2e49ff2 --- /dev/null +++ b/test/unit/test_command.rb @@ -0,0 +1,86 @@ +# Copyright (c) 2005 Zed A. Shaw +# You can redistribute it and/or modify it under the same terms as Ruby. +# +# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html +# for more information. + +require 'test/test_helper' + +class TestCommand < GemPlugin::Plugin "/commands" + include Mongrel::Command::Base + + def configure + options [ + ["-e", "--environment ENV", "Rails environment to run as", :@environment, ENV['RAILS_ENV'] || "development"], + ['', '--user USER', "User to run as", :@user, nil], + ["-d", "--daemonize", "Whether to run in the background or not", :@daemon, false], + ["-x", "--test", "Used to let the test run failures", :@test, false], + ] + end + + def validate + valid_dir? ".", "Can't validate current directory." + valid_exists? "Rakefile", "Rakefile not there, test is invalid." + if @test + valid_exist? "BADFILE", "Yeah, badfile" + valid_file? "BADFILE", "Not even a file" + valid_dir? "BADDIR", "No dir here" + valid? false, "Total failure" + end + + return @valid + end + + + def run + $test_command_ran = true + end +end + +class CommandTest < Test::Unit::TestCase + + def setup + $test_command_ran = false + end + + def teardown + end + + def run_cmd(args) + Mongrel::Command::Registry.instance.run args + end + + def test_run_command + redirect_test_io do + run_cmd ["testcommand"] + assert $test_command_ran, "command didn't run" + end + end + + def test_command_error + redirect_test_io do + run_cmd ["crapcommand"] + end + end + + def test_command_listing + redirect_test_io do + run_cmd ["help"] + end + end + + def test_options + redirect_test_io do + run_cmd ["testcommand","-h"] + run_cmd ["testcommand","--help"] + run_cmd ["testcommand","-e","test","-d","--user"] + end + end + + def test_version + redirect_test_io do + run_cmd ["testcommand", "--version"] + end + end + +end diff --git a/test/unit/test_conditional.rb b/test/unit/test_conditional.rb new file mode 100644 index 0000000..769dd91 --- /dev/null +++ b/test/unit/test_conditional.rb @@ -0,0 +1,107 @@ +# Copyright (c) 2005 Zed A. Shaw +# You can redistribute it and/or modify it under the same terms as Ruby. +# +# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html +# for more information. + +require 'test/test_helper' + +include Mongrel + +class ConditionalResponseTest < Test::Unit::TestCase + def setup + @server = HttpServer.new('127.0.0.1', 3501) + @server.register('/', Mongrel::DirHandler.new('.')) + @server.run + + @http = Net::HTTP.new(@server.host, @server.port) + + # get the ETag and Last-Modified headers + @path = '/README' + res = @http.start { |http| http.get(@path) } + assert_not_nil @etag = res['ETag'] + assert_not_nil @last_modified = res['Last-Modified'] + assert_not_nil @content_length = res['Content-Length'] + end + + def teardown + @server.stop(true) + end + + # status should be 304 Not Modified when If-None-Match is the matching ETag + def test_not_modified_via_if_none_match + assert_status_for_get_and_head Net::HTTPNotModified, 'If-None-Match' => @etag + end + + # status should be 304 Not Modified when If-Modified-Since is the matching Last-Modified date + def test_not_modified_via_if_modified_since + assert_status_for_get_and_head Net::HTTPNotModified, 'If-Modified-Since' => @last_modified + end + + # status should be 304 Not Modified when If-None-Match is the matching ETag + # and If-Modified-Since is the matching Last-Modified date + def test_not_modified_via_if_none_match_and_if_modified_since + assert_status_for_get_and_head Net::HTTPNotModified, 'If-None-Match' => @etag, 'If-Modified-Since' => @last_modified + end + + # status should be 200 OK when If-None-Match is invalid + def test_invalid_if_none_match + assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => 'invalid' + assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => 'invalid', 'If-Modified-Since' => @last_modified + end + + # status should be 200 OK when If-Modified-Since is invalid + def test_invalid_if_modified_since + assert_status_for_get_and_head Net::HTTPOK, 'If-Modified-Since' => 'invalid' + assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => @etag, 'If-Modified-Since' => 'invalid' + end + + # status should be 304 Not Modified when If-Modified-Since is greater than the Last-Modified header, but less than the system time + def test_if_modified_since_greater_than_last_modified + sleep 2 + last_modified_plus_1 = (Time.httpdate(@last_modified) + 1).httpdate + assert_status_for_get_and_head Net::HTTPNotModified, 'If-Modified-Since' => last_modified_plus_1 + assert_status_for_get_and_head Net::HTTPNotModified, 'If-None-Match' => @etag, 'If-Modified-Since' => last_modified_plus_1 + end + + # status should be 200 OK when If-Modified-Since is less than the Last-Modified header + def test_if_modified_since_less_than_last_modified + last_modified_minus_1 = (Time.httpdate(@last_modified) - 1).httpdate + assert_status_for_get_and_head Net::HTTPOK, 'If-Modified-Since' => last_modified_minus_1 + assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => @etag, 'If-Modified-Since' => last_modified_minus_1 + end + + # status should be 200 OK when If-Modified-Since is a date in the future + def test_future_if_modified_since + the_future = Time.at(2**31-1).httpdate + assert_status_for_get_and_head Net::HTTPOK, 'If-Modified-Since' => the_future + assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => @etag, 'If-Modified-Since' => the_future + end + + # status should be 200 OK when If-None-Match is a wildcard + def test_wildcard_match + assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => '*' + assert_status_for_get_and_head Net::HTTPOK, 'If-None-Match' => '*', 'If-Modified-Since' => @last_modified + end + + private + + # assert the response status is correct for GET and HEAD + def assert_status_for_get_and_head(response_class, headers = {}) + %w{ get head }.each do |method| + res = @http.send(method, @path, headers) + assert_kind_of response_class, res + assert_equal @etag, res['ETag'] + case response_class.to_s + when 'Net::HTTPNotModified' then + assert_nil res['Last-Modified'] + assert_nil res['Content-Length'] + when 'Net::HTTPOK' then + assert_equal @last_modified, res['Last-Modified'] + assert_equal @content_length, res['Content-Length'] + else + fail "Incorrect response class: #{response_class}" + end + end + end +end diff --git a/test/unit/test_configurator.rb b/test/unit/test_configurator.rb new file mode 100644 index 0000000..f55a8ae --- /dev/null +++ b/test/unit/test_configurator.rb @@ -0,0 +1,87 @@ +# Copyright (c) 2005 Zed A. Shaw +# You can redistribute it and/or modify it under the same terms as Ruby. +# +# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html +# for more information. + +require 'test/test_helper' + +$test_plugin_fired = 0 + +class TestPlugin < GemPlugin::Plugin "/handlers" + include Mongrel::HttpHandlerPlugin + + def process(request, response) + $test_plugin_fired += 1 + end +end + + +class Sentinel < GemPlugin::Plugin "/handlers" + include Mongrel::HttpHandlerPlugin + + def process(request, response) + raise "This Sentinel plugin shouldn't run." + end +end + + +class ConfiguratorTest < Test::Unit::TestCase + + def test_base_handler_config + @config = nil + + redirect_test_io do + @config = Mongrel::Configurator.new :host => "localhost" do + listener :port => 4501 do + # 2 in front should run, but the sentinel shouldn't since dirhandler processes the request + uri "/", :handler => plugin("/handlers/testplugin") + uri "/", :handler => plugin("/handlers/testplugin") + uri "/", :handler => Mongrel::DirHandler.new(".") + uri "/", :handler => plugin("/handlers/testplugin") + + uri "/test", :handler => plugin("/handlers/testplugin") + uri "/test", :handler => plugin("/handlers/testplugin") + uri "/test", :handler => Mongrel::DirHandler.new(".") + uri "/test", :handler => plugin("/handlers/testplugin") + + debug "/" + setup_signals + + run_config(HERE + "/mongrel.conf") + load_mime_map(HERE + "/mime.yaml") + + run + end + end + end + + # pp @config.listeners.values.first.classifier.routes + + @config.listeners.each do |host,listener| + assert listener.classifier.uris.length == 3, "Wrong number of registered URIs" + assert listener.classifier.uris.include?("/"), "/ not registered" + assert listener.classifier.uris.include?("/test"), "/test not registered" + end + + res = Net::HTTP.get(URI.parse('http://localhost:4501/test')) + assert res != nil, "Didn't get a response" + assert $test_plugin_fired == 3, "Test filter plugin didn't run 3 times." + + redirect_test_io do + res = Net::HTTP.get(URI.parse('http://localhost:4501/')) + + assert res != nil, "Didn't get a response" + assert $test_plugin_fired == 6, "Test filter plugin didn't run 6 times." + end + + redirect_test_io do + @config.stop(false, true) + end + + assert_raise Errno::EBADF, Errno::ECONNREFUSED do + res = Net::HTTP.get(URI.parse("http://localhost:4501/")) + end + end + +end diff --git a/test/unit/test_debug.rb b/test/unit/test_debug.rb new file mode 100644 index 0000000..05d92d8 --- /dev/null +++ b/test/unit/test_debug.rb @@ -0,0 +1,25 @@ +# Copyright (c) 2005 Zed A. Shaw +# You can redistribute it and/or modify it under the same terms as Ruby. +# +# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html +# for more information. + +require 'test/test_helper' +require 'mongrel/debug' + +class MongrelDbgTest < Test::Unit::TestCase + + def test_tracing_to_log + FileUtils.rm_rf "log/mongrel_debug" + + MongrelDbg::configure + out = StringIO.new + + MongrelDbg::begin_trace(:rails) + MongrelDbg::trace(:rails, "Good stuff") + MongrelDbg::end_trace(:rails) + + assert File.exist?("log/mongrel_debug"), "Didn't make logging directory" + end + +end diff --git a/test/unit/test_handlers.rb b/test/unit/test_handlers.rb new file mode 100644 index 0000000..1d316e5 --- /dev/null +++ b/test/unit/test_handlers.rb @@ -0,0 +1,123 @@ +# Copyright (c) 2005 Zed A. Shaw +# You can redistribute it and/or modify it under the same terms as Ruby. +# +# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html +# for more information. + +require 'test/test_helper' + +class SimpleHandler < Mongrel::HttpHandler + def process(request, response) + response.start do |head,out| + head["Content-Type"] = "text/html" + results = "Your request:
#{request.params.to_yaml}
View the files." + out << results + end + end +end + +class DumbHandler < Mongrel::HttpHandler + def process(request, response) + response.start do |head,out| + head["Content-Type"] = "text/html" + out.write("test") + end + end +end + +def check_status(results, expecting) + results.each do |res| + assert(res.kind_of?(expecting), "Didn't get #{expecting}, got: #{res.class}") + end +end + +class HandlersTest < Test::Unit::TestCase + + def setup + stats = Mongrel::StatisticsFilter.new(:sample_rate => 1) + + @config = Mongrel::Configurator.new :host => '127.0.0.1', :port => 9998 do + listener do + uri "/", :handler => SimpleHandler.new + uri "/", :handler => stats + uri "/404", :handler => Mongrel::Error404Handler.new("Not found") + uri "/dumb", :handler => Mongrel::DeflateFilter.new + uri "/dumb", :handler => DumbHandler.new, :in_front => true + uri "/files", :handler => Mongrel::DirHandler.new("doc") + uri "/files_nodir", :handler => Mongrel::DirHandler.new("doc", listing_allowed=false, index_html="none") + uri "/status", :handler => Mongrel::StatusHandler.new(:stats_filter => stats) + uri "/relative", :handler => Mongrel::DirHandler.new(nil, listing_allowed=false, index_html="none") + end + end + + File.open("/tmp/testfile", 'w') do + # Do nothing + end + + @config.run + end + + def teardown + @config.stop(false, true) + File.delete "/tmp/testfile" + end + + def test_more_web_server + res = hit([ "http://localhost:9998/test", + "http://localhost:9998/dumb", + "http://localhost:9998/404", + "http://localhost:9998/files/rdoc/index.html", + "http://localhost:9998/files/rdoc/nothere.html", + "http://localhost:9998/files/rdoc/", + "http://localhost:9998/files_nodir/rdoc/", + "http://localhost:9998/status", + ]) + check_status res, String + end + + def test_nil_dirhandler + # Camping uses this internally + handler = Mongrel::DirHandler.new(nil, false) + assert handler.can_serve("/tmp/testfile") + # Not a bug! A nil @file parameter is the only circumstance under which + # we are allowed to serve any existing file + assert handler.can_serve("../../../../../../../../../../tmp/testfile") + end + + def test_non_nil_dirhandler_is_not_vulnerable_to_path_traversal + # The famous security bug of Mongrel 1.1.2 + handler = Mongrel::DirHandler.new("/doc", false) + assert_nil handler.can_serve("/tmp/testfile") + assert_nil handler.can_serve("../../../../../../../../../../tmp/testfile") + end + + def test_deflate + Net::HTTP.start("localhost", 9998) do |h| + # Test that no accept-encoding returns a non-deflated response + req = h.get("/dumb") + assert( + !req['Content-Encoding'] || + !req['Content-Encoding'].include?('deflate')) + assert_equal "test", req.body + + req = h.get("/dumb", {"Accept-Encoding" => "deflate"}) + # -MAX_WBITS stops zlib from looking for a zlib header + inflater = Zlib::Inflate.new(-Zlib::MAX_WBITS) + assert req['Content-Encoding'].include?('deflate') + assert_equal "test", inflater.inflate(req.body) + end + end + + # TODO: find out why this fails on win32 but nowhere else + #def test_posting_fails_dirhandler + # req = Net::HTTP::Post.new("http://localhost:9998/files/rdoc/") + # req.set_form_data({'from'=>'2005-01-01', 'to'=>'2005-03-31'}, ';') + # res = hit [["http://localhost:9998/files/rdoc/",req]] + # check_status res, Net::HTTPNotFound + #end + + def test_unregister + @config.listeners["127.0.0.1:9998"].unregister("/") + end +end + diff --git a/test/unit/test_http11.rb b/test/unit/test_http11.rb new file mode 100644 index 0000000..e083abf --- /dev/null +++ b/test/unit/test_http11.rb @@ -0,0 +1,156 @@ +# Copyright (c) 2005 Zed A. Shaw +# You can redistribute it and/or modify it under the same terms as Ruby. +# +# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html +# for more information. + +require 'test/test_helper' + +include Mongrel + +class HttpParserTest < Test::Unit::TestCase + + def test_parse_simple + parser = HttpParser.new + req = {} + http = "GET / HTTP/1.1\r\n\r\n" + nread = parser.execute(req, http, 0) + + assert nread == http.length, "Failed to parse the full HTTP request" + assert parser.finished?, "Parser didn't finish" + assert !parser.error?, "Parser had error" + assert nread == parser.nread, "Number read returned from execute does not match" + + assert_equal 'HTTP/1.1', req['SERVER_PROTOCOL'] + assert_equal '/', req['REQUEST_PATH'] + assert_equal 'HTTP/1.1', req['HTTP_VERSION'] + assert_equal '/', req['REQUEST_URI'] + assert_equal 'CGI/1.2', req['GATEWAY_INTERFACE'] + assert_equal 'GET', req['REQUEST_METHOD'] + assert_nil req['FRAGMENT'] + assert_nil req['QUERY_STRING'] + + parser.reset + assert parser.nread == 0, "Number read after reset should be 0" + end + + def test_parse_dumbfuck_headers + parser = HttpParser.new + req = {} + should_be_good = "GET / HTTP/1.1\r\naaaaaaaaaaaaa:++++++++++\r\n\r\n" + nread = parser.execute(req, should_be_good, 0) + assert_equal should_be_good.length, nread + assert parser.finished? + assert !parser.error? + + nasty_pound_header = "GET / HTTP/1.1\r\nX-SSL-Bullshit: -----BEGIN CERTIFICATE-----\r\n\tMIIFbTCCBFWgAwIBAgICH4cwDQYJKoZIhvcNAQEFBQAwcDELMAkGA1UEBhMCVUsx\r\n\tETAPBgNVBAoTCGVTY2llbmNlMRIwEAYDVQQLEwlBdXRob3JpdHkxCzAJBgNVBAMT\r\n\tAkNBMS0wKwYJKoZIhvcNAQkBFh5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMu\r\n\tdWswHhcNMDYwNzI3MTQxMzI4WhcNMDcwNzI3MTQxMzI4WjBbMQswCQYDVQQGEwJV\r\n\tSzERMA8GA1UEChMIZVNjaWVuY2UxEzARBgNVBAsTCk1hbmNoZXN0ZXIxCzAJBgNV\r\n\tBAcTmrsogriqMWLAk1DMRcwFQYDVQQDEw5taWNoYWVsIHBhcmQYJKoZIhvcNAQEB\r\n\tBQADggEPADCCAQoCggEBANPEQBgl1IaKdSS1TbhF3hEXSl72G9J+WC/1R64fAcEF\r\n\tW51rEyFYiIeZGx/BVzwXbeBoNUK41OK65sxGuflMo5gLflbwJtHBRIEKAfVVp3YR\r\n\tgW7cMA/s/XKgL1GEC7rQw8lIZT8RApukCGqOVHSi/F1SiFlPDxuDfmdiNzL31+sL\r\n\t0iwHDdNkGjy5pyBSB8Y79dsSJtCW/iaLB0/n8Sj7HgvvZJ7x0fr+RQjYOUUfrePP\r\n\tu2MSpFyf+9BbC/aXgaZuiCvSR+8Snv3xApQY+fULK/xY8h8Ua51iXoQ5jrgu2SqR\r\n\twgA7BUi3G8LFzMBl8FRCDYGUDy7M6QaHXx1ZWIPWNKsCAwEAAaOCAiQwggIgMAwG\r\n\tA1UdEwEB/wQCMAAwEQYJYIZIAYb4QgEBBAQDAgWgMA4GA1UdDwEB/wQEAwID6DAs\r\n\tBglghkgBhvhCAQ0EHxYdVUsgZS1TY2llbmNlIFVzZXIgQ2VydGlmaWNhdGUwHQYD\r\n\tVR0OBBYEFDTt/sf9PeMaZDHkUIldrDYMNTBZMIGaBgNVHSMEgZIwgY+AFAI4qxGj\r\n\tloCLDdMVKwiljjDastqooXSkcjBwMQswCQYDVQQGEwJVSzERMA8GA1UEChMIZVNj\r\n\taWVuY2UxEjAQBgNVBAsTCUF1dGhvcml0eTELMAkGA1UEAxMCQ0ExLTArBgkqhkiG\r\n\t9w0BCQEWHmNhLW9wZXJhdG9yQGdyaWQtc3VwcG9ydC5hYy51a4IBADApBgNVHRIE\r\n\tIjAggR5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMudWswGQYDVR0gBBIwEDAO\r\n\tBgwrBgEEAdkvAQEBAQYwPQYJYIZIAYb4QgEEBDAWLmh0dHA6Ly9jYS5ncmlkLXN1\r\n\tcHBvcnQuYWMudmT4sopwqlBWsvcHViL2NybC9jYWNybC5jcmwwPQYJYIZIAYb4QgEDBDAWLmh0\r\n\tdHA6Ly9jYS5ncmlkLXN1cHBvcnQuYWMudWsvcHViL2NybC9jYWNybC5jcmwwPwYD\r\n\tVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NhLmdyaWQt5hYy51ay9wdWIv\r\n\tY3JsL2NhY3JsLmNybDANBgkqhkiG9w0BAQUFAAOCAQEAS/U4iiooBENGW/Hwmmd3\r\n\tXCy6Zrt08YjKCzGNjorT98g8uGsqYjSxv/hmi0qlnlHs+k/3Iobc3LjS5AMYr5L8\r\n\tUO7OSkgFFlLHQyC9JzPfmLCAugvzEbyv4Olnsr8hbxF1MbKZoQxUZtMVu29wjfXk\r\n\thTeApBv7eaKCWpSp7MCbvgzm74izKhu3vlDk9w6qVrxePfGgpKPqfHiOoGhFnbTK\r\n\twTC6o2xq5y0qZ03JonF7OJspEd3I5zKY3E+ov7/ZhW6DqT8UFvsAdjvQbXyhV8Eu\r\n\tYhixw1aKEPzNjNowuIseVogKOLXxWI5vAi5HgXdS0/ES5gDGsABo4fqovUKlgop3\r\n\tRA==\r\n\t-----END CERTIFICATE-----\r\n\r\n" + parser = HttpParser.new + req = {} + #nread = parser.execute(req, nasty_pound_header, 0) + #assert_equal nasty_pound_header.length, nread + #assert parser.finished? + #assert !parser.error? + end + + def test_parse_error + parser = HttpParser.new + req = {} + bad_http = "GET / SsUTF/1.1" + + error = false + begin + nread = parser.execute(req, bad_http, 0) + rescue => details + error = true + end + + assert error, "failed to throw exception" + assert !parser.finished?, "Parser shouldn't be finished" + assert parser.error?, "Parser SHOULD have error" + end + + def test_fragment_in_uri + parser = HttpParser.new + req = {} + get = "GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.1\r\n\r\n" + assert_nothing_raised do + parser.execute(req, get, 0) + end + assert parser.finished? + assert_equal '/forums/1/topics/2375?page=1', req['REQUEST_URI'] + assert_equal 'posts-17408', req['FRAGMENT'] + end + + # lame random garbage maker + def rand_data(min, max, readable=true) + count = min + ((rand(max)+1) *10).to_i + res = count.to_s + "/" + + if readable + res << Digest::SHA1.hexdigest(rand(count * 100).to_s) * (count / 40) + else + res << Digest::SHA1.digest(rand(count * 100).to_s) * (count / 20) + end + + return res + end + + + def test_horrible_queries + parser = HttpParser.new + + # then that large header names are caught + 10.times do |c| + get = "GET /#{rand_data(10,120)} HTTP/1.1\r\nX-#{rand_data(1024, 1024+(c*1024))}: Test\r\n\r\n" + assert_raises Mongrel::HttpParserError do + parser.execute({}, get, 0) + parser.reset + end + end + + # then that large mangled field values are caught + 10.times do |c| + get = "GET /#{rand_data(10,120)} HTTP/1.1\r\nX-Test: #{rand_data(1024, 1024+(c*1024), false)}\r\n\r\n" + assert_raises Mongrel::HttpParserError do + parser.execute({}, get, 0) + parser.reset + end + end + + # then large headers are rejected too + get = "GET /#{rand_data(10,120)} HTTP/1.1\r\n" + get << "X-Test: test\r\n" * (80 * 1024) + assert_raises Mongrel::HttpParserError do + parser.execute({}, get, 0) + parser.reset + end + + # finally just that random garbage gets blocked all the time + 10.times do |c| + get = "GET #{rand_data(1024, 1024+(c*1024), false)} #{rand_data(1024, 1024+(c*1024), false)}\r\n\r\n" + assert_raises Mongrel::HttpParserError do + parser.execute({}, get, 0) + parser.reset + end + end + + end + + + + def test_query_parse + res = HttpRequest.query_parse("zed=1&frank=#{HttpRequest.escape('&&& ')}") + assert res["zed"], "didn't get the request right" + assert res["frank"], "no frank" + assert_equal "1", res["zed"], "wrong result" + assert_equal "&&& ", HttpRequest.unescape(res["frank"]), "wrong result" + + res = HttpRequest.query_parse("zed=1&zed=2&zed=3&frank=11;zed=45") + assert res["zed"], "didn't get the request right" + assert res["frank"], "no frank" + assert_equal 4,res["zed"].length, "wrong number for zed" + assert_equal "11",res["frank"], "wrong number for frank" + end + +end + diff --git a/test/unit/test_redirect_handler.rb b/test/unit/test_redirect_handler.rb new file mode 100644 index 0000000..3207b46 --- /dev/null +++ b/test/unit/test_redirect_handler.rb @@ -0,0 +1,44 @@ +# Copyright (c) 2005 Zed A. Shaw +# You can redistribute it and/or modify it under the same terms as Ruby. +# +# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html +# for more information. + +require 'test/test_helper' + +class RedirectHandlerTest < Test::Unit::TestCase + + def setup + redirect_test_io do + @server = Mongrel::HttpServer.new('127.0.0.1', 9998) + end + @server.run + @client = Net::HTTP.new('127.0.0.1', 9998) + end + + def teardown + @server.stop(true) + end + + def test_simple_redirect + tester = Mongrel::RedirectHandler.new('/yo') + @server.register("/test", tester) + + sleep(1) + res = @client.request_get('/test') + assert res != nil, "Didn't get a response" + assert_equal ['/yo'], res.get_fields('Location') + end + + def test_rewrite + tester = Mongrel::RedirectHandler.new(/(\w+)/, '+\1+') + @server.register("/test", tester) + + sleep(1) + res = @client.request_get('/test/something') + assert_equal ['/+test+/+something+'], res.get_fields('Location') + end + +end + + diff --git a/test/unit/test_request_progress.rb b/test/unit/test_request_progress.rb new file mode 100644 index 0000000..da9374e --- /dev/null +++ b/test/unit/test_request_progress.rb @@ -0,0 +1,99 @@ +# Copyright (c) 2005 Zed A. Shaw +# You can redistribute it and/or modify it under the same terms as Ruby. +# +# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html +# for more information. + +require 'test/test_helper' + +class UploadBeginHandler < Mongrel::HttpHandler + attr_reader :request_began, :request_progressed, :request_processed + + def initialize + @request_notify = true + end + + def reset + @request_began = false + @request_progressed = false + @request_processed = false + end + + def request_begins(params) + @request_began = true + end + + def request_progress(params,len,total) + @request_progressed = true + end + + def process(request, response) + @request_processed = true + response.start do |head,body| + body.write("test") + end + end + +end + +class RequestProgressTest < Test::Unit::TestCase + def setup + redirect_test_io do + @server = Mongrel::HttpServer.new("127.0.0.1", 9998) + end + @handler = UploadBeginHandler.new + @server.register("/upload", @handler) + @server.run + end + + def teardown + @server.stop(true) + end + + def test_begin_end_progress + Net::HTTP.get("localhost", "/upload", 9998) + assert @handler.request_began + assert @handler.request_progressed + assert @handler.request_processed + end + + def call_and_assert_handlers_in_turn(handlers) + # reset all handlers + handlers.each { |h| h.reset } + + # make the call + Net::HTTP.get("localhost", "/upload", 9998) + + # assert that each one was fired + handlers.each { |h| + assert h.request_began && h.request_progressed && h.request_processed, + "Callbacks NOT fired for #{h}" + } + end + + def test_more_than_one_begin_end_progress + handlers = [@handler] + + second = UploadBeginHandler.new + @server.register("/upload", second) + handlers << second + call_and_assert_handlers_in_turn(handlers) + + # check three handlers + third = UploadBeginHandler.new + @server.register("/upload", third) + handlers << third + call_and_assert_handlers_in_turn(handlers) + + # remove handlers to make sure they've all gone away + @server.unregister("/upload") + handlers.each { |h| h.reset } + Net::HTTP.get("localhost", "/upload", 9998) + handlers.each { |h| + assert !h.request_began && !h.request_progressed && !h.request_processed + } + + # re-register upload to the state before this test + @server.register("/upload", @handler) + end +end diff --git a/test/unit/test_response.rb b/test/unit/test_response.rb new file mode 100644 index 0000000..b49c9df --- /dev/null +++ b/test/unit/test_response.rb @@ -0,0 +1,127 @@ +# Copyright (c) 2005 Zed A. Shaw +# You can redistribute it and/or modify it under the same terms as Ruby. +# +# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html +# for more information. + +require 'test/test_helper' + +include Mongrel + +class ResponseTest < Test::Unit::TestCase + + def test_response_headers + out = StringIO.new + resp = HttpResponse.new(out) + resp.status = 200 + resp.header["Accept"] = "text/plain" + resp.header["X-Whatever"] = "stuff" + resp.body.write("test") + resp.finished + + assert out.length > 0, "output didn't have data" + end + + def test_response_200 + io = StringIO.new + resp = HttpResponse.new(io) + resp.start do |head,out| + head["Accept"] = "text/plain" + out.write("tested") + out.write("hello!") + end + + resp.finished + assert io.length > 0, "output didn't have data" + end + + def test_response_duplicate_header_squash + io = StringIO.new + resp = HttpResponse.new(io) + resp.start do |head,out| + head["Content-Length"] = 30 + head["Content-Length"] = 0 + end + + resp.finished + + assert_equal io.length, 95, "too much output" + end + + + def test_response_some_duplicates_allowed + allowed_duplicates = ["Set-Cookie", "Set-Cookie2", "Warning", "WWW-Authenticate"] + io = StringIO.new + resp = HttpResponse.new(io) + resp.start do |head,out| + allowed_duplicates.each do |dup| + 10.times do |i| + head[dup] = i + end + end + end + + resp.finished + + assert_equal io.length, 734, "wrong amount of output" + end + + def test_response_404 + io = StringIO.new + + resp = HttpResponse.new(io) + resp.start(404) do |head,out| + head['Accept'] = "text/plain" + out.write("NOT FOUND") + end + + resp.finished + assert io.length > 0, "output didn't have data" + end + + def test_response_file + contents = "PLAIN TEXT\r\nCONTENTS\r\n" + require 'tempfile' + tmpf = Tempfile.new("test_response_file") + tmpf.binmode + tmpf.write(contents) + tmpf.rewind + + io = StringIO.new + resp = HttpResponse.new(io) + resp.start(200) do |head,out| + head['Content-Type'] = 'text/plain' + resp.send_header + resp.send_file(tmpf.path) + end + io.rewind + tmpf.close + + assert io.length > 0, "output didn't have data" + assert io.read[-contents.length..-1] == contents, "output doesn't end with file payload" + end + + def test_response_with_custom_reason + reason = "You made a bad request" + io = StringIO.new + resp = HttpResponse.new(io) + resp.start(400, false, reason) { |head,out| } + resp.finished + + io.rewind + assert_match(/.* #{reason}$/, io.readline.chomp, "wrong custom reason phrase") + end + + def test_response_with_default_reason + code = 400 + io = StringIO.new + resp = HttpResponse.new(io) + resp.start(code) { |head,out| } + resp.finished + + io.rewind + assert_match(/.* #{HTTP_STATUS_CODES[code]}$/, io.readline.chomp, "wrong default reason phrase") + end + +end + diff --git a/test/unit/test_stats.rb b/test/unit/test_stats.rb new file mode 100644 index 0000000..012c6a5 --- /dev/null +++ b/test/unit/test_stats.rb @@ -0,0 +1,35 @@ +# Copyright (c) 2005 Zed A. Shaw +# You can redistribute it and/or modify it under the same terms as Ruby. +# +# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html +# for more information. + +require 'test/test_helper' + +class StatsTest < Test::Unit::TestCase + + def test_sampling_speed + out = StringIO.new + + s = Mongrel::Stats.new("test") + t = Mongrel::Stats.new("time") + + 100.times { s.sample(rand(20)); t.tick } + + s.dump("FIRST", out) + t.dump("FIRST", out) + + old_mean = s.mean + old_sd = s.sd + + s.reset + t.reset + 100.times { s.sample(rand(30)); t.tick } + + s.dump("SECOND", out) + t.dump("SECOND", out) + assert_not_equal old_mean, s.mean + assert_not_equal old_mean, s.sd + end + +end diff --git a/test/unit/test_uriclassifier.rb b/test/unit/test_uriclassifier.rb new file mode 100644 index 0000000..a438065 --- /dev/null +++ b/test/unit/test_uriclassifier.rb @@ -0,0 +1,261 @@ +# Copyright (c) 2005 Zed A. Shaw +# You can redistribute it and/or modify it under the same terms as Ruby. +# +# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html +# for more information. + +require 'test/test_helper' + +include Mongrel + +class URIClassifierTest < Test::Unit::TestCase + + def test_uri_finding + uri_classifier = URIClassifier.new + uri_classifier.register("/test", 1) + + script_name, path_info, value = uri_classifier.resolve("/test") + assert_equal 1, value + assert_equal "/test", script_name + end + + def test_root_handler_only + uri_classifier = URIClassifier.new + uri_classifier.register("/", 1) + + script_name, path_info, value = uri_classifier.resolve("/test") + assert_equal 1, value + assert_equal "/", script_name + assert_equal "/test", path_info + end + + def test_uri_prefix_ops + test = "/pre/fix/test" + prefix = "/pre" + + uri_classifier = URIClassifier.new + uri_classifier.register(prefix,1) + + script_name, path_info, value = uri_classifier.resolve(prefix) + script_name, path_info, value = uri_classifier.resolve(test) + assert_equal 1, value + assert_equal prefix, script_name + assert_equal test[script_name.length .. -1], path_info + + assert uri_classifier.inspect + assert_equal prefix, uri_classifier.uris[0] + end + + def test_not_finding + test = "/cant/find/me" + uri_classifier = URIClassifier.new + uri_classifier.register(test, 1) + + script_name, path_info, value = uri_classifier.resolve("/nope/not/here") + assert_nil script_name + assert_nil path_info + assert_nil value + end + + def test_exceptions + uri_classifier = URIClassifier.new + + uri_classifier.register("/test", 1) + + failed = false + begin + uri_classifier.register("/test", 1) + rescue => e + failed = true + end + + assert failed + + failed = false + begin + uri_classifier.register("", 1) + rescue => e + failed = true + end + + assert failed + end + + + def test_register_unregister + uri_classifier = URIClassifier.new + + 100.times do + uri_classifier.register("/stuff", 1) + value = uri_classifier.unregister("/stuff") + assert_equal 1, value + end + + uri_classifier.register("/things",1) + script_name, path_info, value = uri_classifier.resolve("/things") + assert_equal 1, value + + uri_classifier.unregister("/things") + script_name, path_info, value = uri_classifier.resolve("/things") + assert_nil value + + end + + + def test_uri_branching + uri_classifier = URIClassifier.new + uri_classifier.register("/test", 1) + uri_classifier.register("/test/this",2) + + script_name, path_info, handler = uri_classifier.resolve("/test") + script_name, path_info, handler = uri_classifier.resolve("/test/that") + assert_equal "/test", script_name, "failed to properly find script off branch portion of uri" + assert_equal "/that", path_info + assert_equal 1, handler, "wrong result for branching uri" + end + + def test_all_prefixing + tests = ["/test","/test/that","/test/this"] + uri = "/test/this/that" + uri_classifier = URIClassifier.new + + current = "" + uri.each_byte do |c| + current << c.chr + uri_classifier.register(current, c) + end + + + # Try to resolve everything with no asserts as a fuzzing + tests.each do |prefix| + current = "" + prefix.each_byte do |c| + current << c.chr + script_name, path_info, handler = uri_classifier.resolve(current) + assert script_name + assert path_info + assert handler + end + end + + # Assert that we find stuff + tests.each do |t| + script_name, path_info, handler = uri_classifier.resolve(t) + assert handler + end + + # Assert we don't find stuff + script_name, path_info, handler = uri_classifier.resolve("chicken") + assert_nil handler + assert_nil script_name + assert_nil path_info + end + + + # Verifies that a root mounted ("/") handler resolves + # such that path info matches the original URI. + # This is needed to accommodate real usage of handlers. + def test_root_mounted + uri_classifier = URIClassifier.new + root = "/" + path = "/this/is/a/test" + + uri_classifier.register(root, 1) + + script_name, path_info, handler = uri_classifier.resolve(root) + assert_equal 1, handler + assert_equal root, path_info + assert_equal root, script_name + + script_name, path_info, handler = uri_classifier.resolve(path) + assert_equal path, path_info + assert_equal root, script_name + assert_equal 1, handler + end + + # Verifies that a root mounted ("/") handler + # is the default point, doesn't matter the order we use + # to register the URIs + def test_classifier_order + tests = ["/before", "/way_past"] + root = "/" + path = "/path" + + uri_classifier = URIClassifier.new + uri_classifier.register(path, 1) + uri_classifier.register(root, 2) + + tests.each do |uri| + script_name, path_info, handler = uri_classifier.resolve(uri) + assert_equal root, script_name, "#{uri} did not resolve to #{root}" + assert_equal uri, path_info + assert_equal 2, handler + end + end + + if ENV['BENCHMARK'] + # Eventually we will have a suite of benchmarks instead of lamely installing a test + + def test_benchmark + + # This URI set should favor a TST. Both versions increase linearly until you hit 14 + # URIs, then the TST flattens out. + @uris = %w( + / + /dag /dig /digbark /dog /dogbark /dog/bark /dug /dugbarking /puppy + /c /cat /cat/tree /cat/tree/mulberry /cats /cot /cot/tree/mulberry /kitty /kittycat +# /eag /eig /eigbark /eog /eogbark /eog/bark /eug /eugbarking /iuppy +# /f /fat /fat/tree /fat/tree/mulberry /fats /fot /fot/tree/mulberry /jitty /jittyfat +# /gag /gig /gigbark /gog /gogbark /gog/bark /gug /gugbarking /kuppy +# /h /hat /hat/tree /hat/tree/mulberry /hats /hot /hot/tree/mulberry /litty /littyhat +# /ceag /ceig /ceigbark /ceog /ceogbark /ceog/cbark /ceug /ceugbarking /ciuppy +# /cf /cfat /cfat/ctree /cfat/ctree/cmulberry /cfats /cfot /cfot/ctree/cmulberry /cjitty /cjittyfat +# /cgag /cgig /cgigbark /cgog /cgogbark /cgog/cbark /cgug /cgugbarking /ckuppy +# /ch /chat /chat/ctree /chat/ctree/cmulberry /chats /chot /chot/ctree/cmulberry /citty /cittyhat + ) + + @requests = %w( + / + /dig + /digging + /dogging + /dogbarking/ + /puppy/barking + /c + /cat + /cat/shrub + /cat/tree + /cat/tree/maple + /cat/tree/mulberry/tree + /cat/tree/oak + /cats/ + /cats/tree + /cod + /zebra + ) + + @classifier = URIClassifier.new + @uris.each do |uri| + @classifier.register(uri, 1) + end + + puts "#{@uris.size} URIs / #{@requests.size * 10000} requests" + + Benchmark.bm do |x| + x.report do + # require 'ruby-prof' + # profile = RubyProf.profile do + 10000.times do + @requests.each do |request| + @classifier.resolve(request) + end + end + # end + # File.open("profile.html", 'w') { |file| RubyProf::GraphHtmlPrinter.new(profile).print(file, 0) } + end + end + end + end + +end + diff --git a/test/unit/test_ws.rb b/test/unit/test_ws.rb new file mode 100644 index 0000000..3385e0a --- /dev/null +++ b/test/unit/test_ws.rb @@ -0,0 +1,115 @@ +# Copyright (c) 2005 Zed A. Shaw +# You can redistribute it and/or modify it under the same terms as Ruby. +# +# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html +# for more information. + +require 'test/test_helper' + +include Mongrel + +class TestHandler < Mongrel::HttpHandler + attr_reader :ran_test + + def process(request, response) + @ran_test = true + response.socket.write("HTTP/1.1 200 OK\r\nContent-Type: text/plain\r\n\r\nhello!\n") + end +end + + +class WebServerTest < Test::Unit::TestCase + + def setup + @valid_request = "GET / HTTP/1.1\r\nHost: www.zedshaw.com\r\nContent-Type: text/plain\r\n\r\n" + + redirect_test_io do + # We set num_processors=1 so that we can test the reaping code + @server = HttpServer.new("127.0.0.1", 9998, num_processors=1) + end + + @tester = TestHandler.new + @server.register("/test", @tester) + redirect_test_io do + @server.run + end + end + + def teardown + redirect_test_io do + @server.stop(true) + end + end + + def test_simple_server + hit(['http://localhost:9998/test']) + assert @tester.ran_test, "Handler didn't really run" + end + + + def do_test(string, chunk, close_after=nil, shutdown_delay=0) + # Do not use instance variables here, because it needs to be thread safe + socket = TCPSocket.new("127.0.0.1", 9998); + request = StringIO.new(string) + chunks_out = 0 + + while data = request.read(chunk) + chunks_out += socket.write(data) + socket.flush + sleep 0.2 + if close_after and chunks_out > close_after + socket.close + sleep 1 + end + end + sleep(shutdown_delay) + socket.write(" ") # Some platforms only raise the exception on attempted write + socket.flush + end + + def test_trickle_attack + do_test(@valid_request, 3) + end + + def test_close_client + assert_raises IOError do + do_test(@valid_request, 10, 20) + end + end + + def test_bad_client + redirect_test_io do + do_test("GET /test HTTP/BAD", 3) + end + end + + def test_header_is_too_long + redirect_test_io do + long = "GET /test HTTP/1.1\r\n" + ("X-Big: stuff\r\n" * 15000) + "\r\n" + assert_raises Errno::ECONNRESET, Errno::EPIPE, Errno::ECONNABORTED, Errno::EINVAL, IOError do + do_test(long, long.length/2, 10) + end + end + end + + def test_num_processors_overload + redirect_test_io do + assert_raises Errno::ECONNRESET, Errno::EPIPE, Errno::ECONNABORTED, Errno::EINVAL do + tests = [ + Thread.new { do_test(@valid_request, 1) }, + Thread.new { do_test(@valid_request, 10) }, + ] + + tests.each {|t| t.join} + end + end + end + + def test_file_streamed_request + body = "a" * (Mongrel::Const::MAX_BODY * 2) + long = "GET /test HTTP/1.1\r\nContent-length: #{body.length}\r\n\r\n" + body + do_test(long, Mongrel::Const::CHUNK_SIZE * 2 -400) + end + +end + -- cgit v1.2.3-24-ge0c7 From 41220d846bbe57c6b50c0a86c4f86030f6d14b05 Mon Sep 17 00:00:00 2001 From: evanweaver Date: Wed, 20 Feb 2008 06:26:33 +0000 Subject: Move tools/trickletest into test/tools. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-1@974 19e92222-5c0b-0410-8929-a290d50e31e9 --- test/tools/trickletest.rb | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 test/tools/trickletest.rb diff --git a/test/tools/trickletest.rb b/test/tools/trickletest.rb new file mode 100644 index 0000000..e19ed71 --- /dev/null +++ b/test/tools/trickletest.rb @@ -0,0 +1,45 @@ +require 'socket' +require 'stringio' + +def do_test(st, chunk) + s = TCPSocket.new('127.0.0.1',ARGV[0].to_i); + req = StringIO.new(st) + nout = 0 + randstop = rand(st.length / 10) + STDERR.puts "stopping after: #{randstop}" + + begin + while data = req.read(chunk) + nout += s.write(data) + s.flush + sleep 0.1 + if nout > randstop + STDERR.puts "BANG! after #{nout} bytes." + break + end + end + rescue Object => e + STDERR.puts "ERROR: #{e}" + ensure + s.close + end +end + +content = "-" * (1024 * 240) +st = "GET / HTTP/1.1\r\nHost: www.zedshaw.com\r\nContent-Type: text/plain\r\nContent-Length: #{content.length}\r\n\r\n#{content}" + +puts "length: #{content.length}" + +threads = [] +ARGV[1].to_i.times do + t = Thread.new do + size = 100 + puts ">>>> #{size} sized chunks" + do_test(st, size) + end + + t.abort_on_exception = true + threads << t +end + +threads.each {|t| t.join} -- cgit v1.2.3-24-ge0c7 From 7015d3fc47f1e33b763206d3da08d43b8ef85913 Mon Sep 17 00:00:00 2001 From: evanweaver Date: Wed, 20 Feb 2008 06:27:10 +0000 Subject: Update manifest for changed test layout; add CONTRIBUTORS file to the RDoc pattern in the Rakefile. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-1@975 19e92222-5c0b-0410-8929-a290d50e31e9 --- Manifest | 37 ++++++++++++++++++++----------------- Rakefile | 2 +- tools/trickletest.rb | 45 --------------------------------------------- 3 files changed, 21 insertions(+), 63 deletions(-) delete mode 100644 tools/trickletest.rb diff --git a/Manifest b/Manifest index 6a77dad..2896ec6 100644 --- a/Manifest +++ b/Manifest @@ -1,5 +1,6 @@ bin/mongrel_rails CHANGELOG +CONTRIBUTORS COPYING examples/builder.rb examples/camping/blog.rb @@ -43,27 +44,29 @@ lib/mongrel/stats.rb lib/mongrel/tcphack.rb lib/mongrel/uri_classifier.rb lib/mongrel.rb +lib/mongrel.rb.rej LICENSE Manifest mongrel-public_cert.pem -mongrel.gemspec README setup.rb +test/benchmark/previous.rb +test/benchmark/simple.rb +test/benchmark/utils.rb test/mime.yaml test/mongrel.conf -test/test_cgi_wrapper.rb -test/test_command.rb -test/test_conditional.rb -test/test_configurator.rb -test/test_debug.rb -test/test_handlers.rb -test/test_http11.rb -test/test_redirect_handler.rb -test/test_request_progress.rb -test/test_response.rb -test/test_stats.rb -test/test_uriclassifier.rb -test/test_ws.rb -test/testhelp.rb -TODO -tools/trickletest.rb +test/test_helper.rb +test/tools/trickletest.rb +test/unit/test_cgi_wrapper.rb +test/unit/test_command.rb +test/unit/test_conditional.rb +test/unit/test_configurator.rb +test/unit/test_debug.rb +test/unit/test_handlers.rb +test/unit/test_http11.rb +test/unit/test_redirect_handler.rb +test/unit/test_request_progress.rb +test/unit/test_response.rb +test/unit/test_stats.rb +test/unit/test_uriclassifier.rb +test/unit/test_ws.rb diff --git a/Rakefile b/Rakefile index 36f907e..af373a8 100644 --- a/Rakefile +++ b/Rakefile @@ -8,7 +8,7 @@ e = Echoe.new("mongrel") do |p| p.author ="Zed A. Shaw" p.clean_pattern = ['ext/http11/*.{bundle,so,o,obj,pdb,lib,def,exp}', 'lib/*.{bundle,so,o,obj,pdb,lib,def,exp}', 'ext/http11/Makefile', 'pkg', 'lib/*.bundle', '*.gem', 'site/output', '.config', 'lib/http11.jar', 'ext/http11_java/classes', 'coverage', 'test_*.log', 'log'] p.url = "http://mongrel.rubyforge.org" - p.rdoc_pattern = ['README', 'LICENSE', 'CHANGELOG', 'COPYING', 'lib/**/*.rb', 'doc/**/*.rdoc'] + p.rdoc_pattern = ['README', 'LICENSE', 'CONTRIBUTORS', 'CHANGELOG', 'COPYING', 'lib/**/*.rb', 'doc/**/*.rdoc'] p.docs_host = 'mongrel.cloudbur.st:/home/eweaver/www/mongrel/htdocs/web' p.ignore_pattern = /^(pkg|site|projects|doc|log)|CVS|\.log/ p.ruby_version = '>=1.8.4' diff --git a/tools/trickletest.rb b/tools/trickletest.rb deleted file mode 100644 index e19ed71..0000000 --- a/tools/trickletest.rb +++ /dev/null @@ -1,45 +0,0 @@ -require 'socket' -require 'stringio' - -def do_test(st, chunk) - s = TCPSocket.new('127.0.0.1',ARGV[0].to_i); - req = StringIO.new(st) - nout = 0 - randstop = rand(st.length / 10) - STDERR.puts "stopping after: #{randstop}" - - begin - while data = req.read(chunk) - nout += s.write(data) - s.flush - sleep 0.1 - if nout > randstop - STDERR.puts "BANG! after #{nout} bytes." - break - end - end - rescue Object => e - STDERR.puts "ERROR: #{e}" - ensure - s.close - end -end - -content = "-" * (1024 * 240) -st = "GET / HTTP/1.1\r\nHost: www.zedshaw.com\r\nContent-Type: text/plain\r\nContent-Length: #{content.length}\r\n\r\n#{content}" - -puts "length: #{content.length}" - -threads = [] -ARGV[1].to_i.times do - t = Thread.new do - size = 100 - puts ">>>> #{size} sized chunks" - do_test(st, size) - end - - t.abort_on_exception = true - threads << t -end - -threads.each {|t| t.join} -- cgit v1.2.3-24-ge0c7 -- cgit v1.2.3-24-ge0c7 From 48e885e60cabacc1c4940f6b62c3c7daa846b880 Mon Sep 17 00:00:00 2001 From: evanweaver Date: Fri, 22 Feb 2008 04:50:18 +0000 Subject: Remove fastthread and cgi_multipart_eof_fix from 1.2 gem dependencies. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-2@978 19e92222-5c0b-0410-8929-a290d50e31e9 --- Rakefile | 3 --- 1 file changed, 3 deletions(-) diff --git a/Rakefile b/Rakefile index af373a8..c98ee34 100644 --- a/Rakefile +++ b/Rakefile @@ -36,14 +36,11 @@ e = Echoe.new("mongrel") do |p| when /mswin/ self.files += ['lib/http11.so'] self.platform = Gem::Platform::WIN32 - add_dependency('cgi_multipart_eof_fix', '>= 2.4') when /java/ self.files += ['lib/http11.jar'] self.platform = 'jruby' # XXX Is this right? else add_dependency('daemons', '>= 1.0.3') - add_dependency('fastthread', '>= 1.0.1') - add_dependency('cgi_multipart_eof_fix', '>= 2.4') end end -- cgit v1.2.3-24-ge0c7 From 75e95bfb474d283387fdc50d8edb27a9d01bd1a1 Mon Sep 17 00:00:00 2001 From: evanweaver Date: Sat, 23 Feb 2008 19:45:25 +0000 Subject: Add 'doc' to clean pattern. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-2@979 19e92222-5c0b-0410-8929-a290d50e31e9 --- Rakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index c98ee34..52961c4 100644 --- a/Rakefile +++ b/Rakefile @@ -6,7 +6,7 @@ require 'echoe' e = Echoe.new("mongrel") do |p| p.summary = "A small fast HTTP library and server that runs Rails, Camping, Nitro and Iowa apps." p.author ="Zed A. Shaw" - p.clean_pattern = ['ext/http11/*.{bundle,so,o,obj,pdb,lib,def,exp}', 'lib/*.{bundle,so,o,obj,pdb,lib,def,exp}', 'ext/http11/Makefile', 'pkg', 'lib/*.bundle', '*.gem', 'site/output', '.config', 'lib/http11.jar', 'ext/http11_java/classes', 'coverage', 'test_*.log', 'log'] + p.clean_pattern = ['ext/http11/*.{bundle,so,o,obj,pdb,lib,def,exp}', 'lib/*.{bundle,so,o,obj,pdb,lib,def,exp}', 'ext/http11/Makefile', 'pkg', 'lib/*.bundle', '*.gem', 'site/output', '.config', 'lib/http11.jar', 'ext/http11_java/classes', 'coverage', 'test_*.log', 'log', 'doc'] p.url = "http://mongrel.rubyforge.org" p.rdoc_pattern = ['README', 'LICENSE', 'CONTRIBUTORS', 'CHANGELOG', 'COPYING', 'lib/**/*.rb', 'doc/**/*.rdoc'] p.docs_host = 'mongrel.cloudbur.st:/home/eweaver/www/mongrel/htdocs/web' -- cgit v1.2.3-24-ge0c7 From 4cb24e9017c368c8e68edab5ca694b29a8ccdad4 Mon Sep 17 00:00:00 2001 From: evanweaver Date: Sat, 23 Feb 2008 19:48:53 +0000 Subject: Update all constants for the release, as Luis reminded me. $ rpl -R -x'.java' -x'.c' -x'.rb' '1.1.3' '1.1.4' * git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-2@980 19e92222-5c0b-0410-8929-a290d50e31e9 --- ext/http11/http11.c | 2 +- ext/http11_java/org/jruby/mongrel/Http11.java | 2 +- lib/mongrel/const.rb | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ext/http11/http11.c b/ext/http11/http11.c index 6603745..2982467 100644 --- a/ext/http11/http11.c +++ b/ext/http11/http11.c @@ -384,7 +384,7 @@ void Init_http11() DEF_GLOBAL(server_protocol, "SERVER_PROTOCOL"); DEF_GLOBAL(server_protocol_value, "HTTP/1.1"); DEF_GLOBAL(http_host, "HTTP_HOST"); - DEF_GLOBAL(mongrel_version, "Mongrel 1.1.3"); /* XXX Why is this defined here? */ + DEF_GLOBAL(mongrel_version, "Mongrel 1.2.0"); /* XXX Why is this defined here? */ DEF_GLOBAL(server_software, "SERVER_SOFTWARE"); DEF_GLOBAL(port_80, "80"); diff --git a/ext/http11_java/org/jruby/mongrel/Http11.java b/ext/http11_java/org/jruby/mongrel/Http11.java index 68cb665..3a6699e 100644 --- a/ext/http11_java/org/jruby/mongrel/Http11.java +++ b/ext/http11_java/org/jruby/mongrel/Http11.java @@ -215,7 +215,7 @@ public class Http11 extends RubyObject { req.setInstanceVariable("@http_body", RubyString.newString(runtime, new ByteList(hp.parser.buffer, at, length))); req.aset(runtime.newString("SERVER_PROTOCOL"),runtime.newString("HTTP/1.1")); - req.aset(runtime.newString("SERVER_SOFTWARE"),runtime.newString("Mongrel 1.1.3")); + req.aset(runtime.newString("SERVER_SOFTWARE"),runtime.newString("Mongrel 1.2.0")); } }; diff --git a/lib/mongrel/const.rb b/lib/mongrel/const.rb index 8a6982a..a9b100e 100644 --- a/lib/mongrel/const.rb +++ b/lib/mongrel/const.rb @@ -65,7 +65,7 @@ module Mongrel REQUEST_URI='REQUEST_URI'.freeze REQUEST_PATH='REQUEST_PATH'.freeze - MONGREL_VERSION="1.1.3".freeze + MONGREL_VERSION="1.2.0".freeze MONGREL_TMP_BASE="mongrel".freeze -- cgit v1.2.3-24-ge0c7 From e02fa9500e93da977c77cc3a8c421b20c8f7a5d9 Mon Sep 17 00:00:00 2001 From: evanweaver Date: Sat, 23 Feb 2008 20:16:17 +0000 Subject: Add IOError to test exception list because JRuby trunk started throwing it instead of one of the old ones. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-2@981 19e92222-5c0b-0410-8929-a290d50e31e9 --- test/unit/test_ws.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/unit/test_ws.rb b/test/unit/test_ws.rb index 3385e0a..d239e18 100644 --- a/test/unit/test_ws.rb +++ b/test/unit/test_ws.rb @@ -4,7 +4,7 @@ # Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html # for more information. -require 'test/test_helper' +require 'test/testhelp' include Mongrel @@ -94,7 +94,7 @@ class WebServerTest < Test::Unit::TestCase def test_num_processors_overload redirect_test_io do - assert_raises Errno::ECONNRESET, Errno::EPIPE, Errno::ECONNABORTED, Errno::EINVAL do + assert_raises Errno::ECONNRESET, Errno::EPIPE, Errno::ECONNABORTED, Errno::EINVAL, IOError do tests = [ Thread.new { do_test(@valid_request, 1) }, Thread.new { do_test(@valid_request, 10) }, -- cgit v1.2.3-24-ge0c7 From 20f0964f82bd35e4d2b22ba3e30d4d5dfbca480f Mon Sep 17 00:00:00 2001 From: evanweaver Date: Fri, 29 Feb 2008 19:23:12 +0000 Subject: Gems 1.0.1 needs Platform::CURRENT instead of Platform::WIN32 for some reason. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-2@985 19e92222-5c0b-0410-8929-a290d50e31e9 --- Rakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index 52961c4..9103235 100644 --- a/Rakefile +++ b/Rakefile @@ -35,7 +35,7 @@ e = Echoe.new("mongrel") do |p| case RUBY_PLATFORM when /mswin/ self.files += ['lib/http11.so'] - self.platform = Gem::Platform::WIN32 + self.platform = Gem::Platform::CURRENT when /java/ self.files += ['lib/http11.jar'] self.platform = 'jruby' # XXX Is this right? -- cgit v1.2.3-24-ge0c7 From 3059c858dbd7916ad4fe0075f13ae73084d858e1 Mon Sep 17 00:00:00 2001 From: evanweaver Date: Sat, 1 Mar 2008 21:47:47 +0000 Subject: Use correct requirement for test helper in test/unit/test_ws.rb (Eric Wong). git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-2@986 19e92222-5c0b-0410-8929-a290d50e31e9 --- test/unit/test_ws.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/test_ws.rb b/test/unit/test_ws.rb index d239e18..68a79a8 100644 --- a/test/unit/test_ws.rb +++ b/test/unit/test_ws.rb @@ -4,7 +4,7 @@ # Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html # for more information. -require 'test/testhelp' +require 'test/test_helper' include Mongrel -- cgit v1.2.3-24-ge0c7 From 18e93c034db0c08bcc5b5f7a72a8fb6e909c009c Mon Sep 17 00:00:00 2001 From: evanweaver Date: Mon, 24 Mar 2008 03:48:10 +0000 Subject: Backport Eric's changes to the http parser from trunk (Eric Wong). Apply fix for Ragel 6 (Eric Wong, Ry Dahl). Two tests fail with the new parser (1 failed with the old parser). Needs investigation. Close #12 (mongrel_rails send_signal leaves a filehandle open until gc). Close #14 (mongrel_rails command line option --num-procs does not change the max number of procs). Close #15 (mongrel squashes helpful exception in register method). Close #16, XXX needs audit! (CGIWrapper "options" attr_reader has no corresponding @options variable). Close #20 (Mongrel doesn't erase temporary files during it's operation on windows). Close #19, XXX needs audit! (HttpResponse#reset does not properly reset HeaderOut). Close #22 (gem_plugin should load gems from Gem.path not Gem.dir). Close #23 (mongrel_cluster's mongrel_rails configuration option isn't fully respected). If I had git, being offline wouldn't have resulted in one massive commit. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-2@995 19e92222-5c0b-0410-8929-a290d50e31e9 --- Rakefile | 4 +- bin/mongrel_rails | 2 +- ext/http11/ext_help.h | 1 + ext/http11/http11.c | 165 ++++- ext/http11/http11_parser.c | 492 +++++++------- ext/http11/http11_parser.java.rl | 1 + ext/http11/http11_parser.rl | 30 +- ext/http11/http11_parser_common.rl | 2 +- .../org/jruby/mongrel/Http11Parser.java | 712 +++++++++------------ lib/mongrel.rb | 13 +- lib/mongrel/cgi.rb | 4 +- lib/mongrel/http_request.rb | 2 +- lib/mongrel/http_response.rb | 5 +- projects/gem_plugin/CHANGELOG | 2 + projects/gem_plugin/lib/gem_plugin.rb | 11 +- .../mongrel_cluster/lib/mongrel_cluster/init.rb | 6 +- .../lib/mongrel_cluster/recipes_2.rb | 3 +- test/unit/test_handlers.rb | 10 + test/unit/test_http11.rb | 156 ----- test/unit/test_http_parser.rb | 156 +++++ 20 files changed, 927 insertions(+), 850 deletions(-) delete mode 100644 test/unit/test_http11.rb create mode 100644 test/unit/test_http_parser.rb diff --git a/Rakefile b/Rakefile index 9103235..9ea061c 100644 --- a/Rakefile +++ b/Rakefile @@ -53,13 +53,13 @@ task :ragel do Dir.chdir "ext/http11" do target = "http11_parser.c" File.unlink target if File.exist? target - sh "ragel http11_parser.rl | rlgen-cd -G2 -o #{target}" + sh "ragel http11_parser.rl -C -G2 -o #{target}" raise "Failed to build C source" unless File.exist? target end Dir.chdir "ext/http11" do target = "../../ext/http11_java/org/jruby/mongrel/Http11Parser.java" File.unlink target if File.exist? target - sh "ragel -J http11_parser.java.rl | rlgen-java -o #{target}" + sh "ragel http11_parser.rl -J -o #{target}" raise "Failed to build Java source" unless File.exist? target end end diff --git a/bin/mongrel_rails b/bin/mongrel_rails index bb3205a..c32b818 100644 --- a/bin/mongrel_rails +++ b/bin/mongrel_rails @@ -194,7 +194,7 @@ module Mongrel end def Mongrel::send_signal(signal, pid_file) - pid = open(pid_file).read.to_i + pid = File.read(pid_file).to_i print "Sending #{signal} to Mongrel at PID #{pid}..." begin Process.kill(signal, pid) diff --git a/ext/http11/ext_help.h b/ext/http11/ext_help.h index 8b4d754..08c0e1e 100644 --- a/ext/http11/ext_help.h +++ b/ext/http11/ext_help.h @@ -4,6 +4,7 @@ #define RAISE_NOT_NULL(T) if(T == NULL) rb_raise(rb_eArgError, "NULL found for " # T " when shouldn't be."); #define DATA_GET(from,type,name) Data_Get_Struct(from,type,name); RAISE_NOT_NULL(name); #define REQUIRE_TYPE(V, T) if(TYPE(V) != T) rb_raise(rb_eTypeError, "Wrong argument type for " # V " required " # T); +#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) #ifdef DEBUG #define TRACE() fprintf(stderr, "> %s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__) diff --git a/ext/http11/http11.c b/ext/http11/http11.c index 2982467..a228019 100644 --- a/ext/http11/http11.c +++ b/ext/http11/http11.c @@ -7,7 +7,13 @@ #include #include #include "http11_parser.h" -#include + +#ifndef RSTRING_PTR +#define RSTRING_PTR(s) (RSTRING(s)->ptr) +#endif +#ifndef RSTRING_LEN +#define RSTRING_LEN(s) (RSTRING(s)->len) +#endif static VALUE mMongrel; static VALUE cHttpParser; @@ -15,8 +21,9 @@ static VALUE eHttpParserError; #define id_handler_map rb_intern("@handler_map") #define id_http_body rb_intern("@http_body") +#define HTTP_PREFIX "HTTP_" +#define HTTP_PREFIX_LEN (sizeof(HTTP_PREFIX) - 1) -static VALUE global_http_prefix; static VALUE global_request_method; static VALUE global_request_uri; static VALUE global_fragment; @@ -59,10 +66,119 @@ DEF_MAX_LENGTH(REQUEST_PATH, 1024); DEF_MAX_LENGTH(QUERY_STRING, (1024 * 10)); DEF_MAX_LENGTH(HEADER, (1024 * (80 + 32))); +struct common_field { + const signed long len; + const char *name; + VALUE value; +}; + +/* + * A list of common HTTP headers we expect to receive. + * This allows us to avoid repeatedly creating identical string + * objects to be used with rb_hash_aset(). + */ +static struct common_field common_http_fields[] = { +# define f(N) { (sizeof(N) - 1), N, Qnil } + f("ACCEPT"), + f("ACCEPT_CHARSET"), + f("ACCEPT_ENCODING"), + f("ACCEPT_LANGUAGE"), + f("ALLOW"), + f("AUTHORIZATION"), + f("CACHE_CONTROL"), + f("CONNECTION"), + f("CONTENT_ENCODING"), + f("CONTENT_LENGTH"), + f("CONTENT_TYPE"), + f("COOKIE"), + f("DATE"), + f("EXPECT"), + f("FROM"), + f("HOST"), + f("IF_MATCH"), + f("IF_MODIFIED_SINCE"), + f("IF_NONE_MATCH"), + f("IF_RANGE"), + f("IF_UNMODIFIED_SINCE"), + f("KEEP_ALIVE"), /* Firefox sends this */ + f("MAX_FORWARDS"), + f("PRAGMA"), + f("PROXY_AUTHORIZATION"), + f("RANGE"), + f("REFERER"), + f("TE"), + f("TRAILER"), + f("TRANSFER_ENCODING"), + f("UPGRADE"), + f("USER_AGENT"), + f("VIA"), + f("X_FORWARDED_FOR"), /* common for proxies */ + f("X_REAL_IP"), /* common for proxies */ + f("WARNING") +# undef f +}; + +/* + * qsort(3) and bsearch(3) improve average performance slightly, but may + * not be worth it for lack of portability to certain platforms... + */ +#if defined(HAVE_QSORT_BSEARCH) +/* sort by length, then by name if there's a tie */ +static int common_field_cmp(const void *a, const void *b) +{ + struct common_field *cfa = (struct common_field *)a; + struct common_field *cfb = (struct common_field *)b; + signed long diff = cfa->len - cfb->len; + return diff ? diff : memcmp(cfa->name, cfb->name, cfa->len); +} +#endif /* HAVE_QSORT_BSEARCH */ + +static void init_common_fields(void) +{ + int i; + struct common_field *cf = common_http_fields; + char tmp[256]; /* MAX_FIELD_NAME_LENGTH */ + memcpy(tmp, HTTP_PREFIX, HTTP_PREFIX_LEN); + + for(i = 0; i < ARRAY_SIZE(common_http_fields); cf++, i++) { + memcpy(tmp + HTTP_PREFIX_LEN, cf->name, cf->len + 1); + cf->value = rb_obj_freeze(rb_str_new(tmp, HTTP_PREFIX_LEN + cf->len)); + rb_global_variable(&cf->value); + } + +#if defined(HAVE_QSORT_BSEARCH) + qsort(common_http_fields, + ARRAY_SIZE(common_http_fields), + sizeof(struct common_field), + common_field_cmp); +#endif /* HAVE_QSORT_BSEARCH */ +} + +static VALUE find_common_field_value(const char *field, size_t flen) +{ +#if defined(HAVE_QSORT_BSEARCH) + struct common_field key; + struct common_field *found; + key.name = field; + key.len = (signed long)flen; + found = (struct common_field *)bsearch(&key, common_http_fields, + ARRAY_SIZE(common_http_fields), + sizeof(struct common_field), + common_field_cmp); + return found ? found->value : Qnil; +#else /* !HAVE_QSORT_BSEARCH */ + int i; + struct common_field *cf = common_http_fields; + for(i = 0; i < ARRAY_SIZE(common_http_fields); i++, cf++) { + if (cf->len == flen && !memcmp(cf->name, field, flen)) + return cf->value; + } + return Qnil; +#endif /* !HAVE_QSORT_BSEARCH */ +} void http_field(void *data, const char *field, size_t flen, const char *value, size_t vlen) { - char *ch, *end; VALUE req = (VALUE)data; VALUE v = Qnil; VALUE f = Qnil; @@ -71,15 +187,25 @@ void http_field(void *data, const char *field, size_t flen, const char *value, s VALIDATE_MAX_LENGTH(vlen, FIELD_VALUE); v = rb_str_new(value, vlen); - f = rb_str_dup(global_http_prefix); - f = rb_str_buf_cat(f, field, flen); - for(ch = RSTRING(f)->ptr, end = ch + RSTRING(f)->len; ch < end; ch++) { - if(*ch == '-') { - *ch = '_'; - } else { - *ch = toupper(*ch); - } + f = find_common_field_value(field, flen); + + if (f == Qnil) { + /* + * We got a strange header that we don't have a memoized value for. + * Fallback to creating a new string to use as a hash key. + * + * using rb_str_new(NULL, len) here is faster than rb_str_buf_new(len) + * in my testing, because: there's no minimum allocation length (and + * no check for it, either), RSTRING_LEN(f) does not need to be + * written twice, and and RSTRING_PTR(f) will already be + * null-terminated for us. + */ + f = rb_str_new(NULL, HTTP_PREFIX_LEN + flen); + memcpy(RSTRING_PTR(f), HTTP_PREFIX, HTTP_PREFIX_LEN); + memcpy(RSTRING_PTR(f) + HTTP_PREFIX_LEN, field, flen); + assert(*(RSTRING_PTR(f) + RSTRING_LEN(f)) == '\0'); /* paranoia */ + /* fprintf(stderr, "UNKNOWN HEADER <%s>\n", RSTRING_PTR(f)); */ } rb_hash_aset(req, f, v); @@ -168,13 +294,12 @@ void header_done(void *data, const char *at, size_t length) rb_hash_aset(req, global_gateway_interface, global_gateway_interface_value); if((temp = rb_hash_aref(req, global_http_host)) != Qnil) { - /* ruby better close strings off with a '\0' dammit */ - colon = strchr(RSTRING(temp)->ptr, ':'); + colon = memchr(RSTRING_PTR(temp), ':', RSTRING_LEN(temp)); if(colon != NULL) { - rb_hash_aset(req, global_server_name, rb_str_substr(temp, 0, colon - RSTRING(temp)->ptr)); + rb_hash_aset(req, global_server_name, rb_str_substr(temp, 0, colon - RSTRING_PTR(temp))); rb_hash_aset(req, global_server_port, - rb_str_substr(temp, colon - RSTRING(temp)->ptr+1, - RSTRING(temp)->len)); + rb_str_substr(temp, colon - RSTRING_PTR(temp)+1, + RSTRING_LEN(temp))); } else { rb_hash_aset(req, global_server_name, temp); rb_hash_aset(req, global_server_port, global_port_80); @@ -295,8 +420,8 @@ VALUE HttpParser_execute(VALUE self, VALUE req_hash, VALUE data, VALUE start) DATA_GET(self, http_parser, http); from = FIX2INT(start); - dptr = RSTRING(data)->ptr; - dlen = RSTRING(data)->len; + dptr = RSTRING_PTR(data); + dlen = RSTRING_LEN(data); if(from >= dlen) { rb_raise(eHttpParserError, "Requested start is after data buffer end."); @@ -366,7 +491,6 @@ void Init_http11() mMongrel = rb_define_module("Mongrel"); - DEF_GLOBAL(http_prefix, "HTTP_"); DEF_GLOBAL(request_method, "REQUEST_METHOD"); DEF_GLOBAL(request_uri, "REQUEST_URI"); DEF_GLOBAL(fragment, "FRAGMENT"); @@ -384,7 +508,7 @@ void Init_http11() DEF_GLOBAL(server_protocol, "SERVER_PROTOCOL"); DEF_GLOBAL(server_protocol_value, "HTTP/1.1"); DEF_GLOBAL(http_host, "HTTP_HOST"); - DEF_GLOBAL(mongrel_version, "Mongrel 1.2.0"); /* XXX Why is this defined here? */ + DEF_GLOBAL(mongrel_version, "Mongrel 1.2"); /* XXX Why is this defined here? */ DEF_GLOBAL(server_software, "SERVER_SOFTWARE"); DEF_GLOBAL(port_80, "80"); @@ -399,4 +523,5 @@ void Init_http11() rb_define_method(cHttpParser, "error?", HttpParser_has_error,0); rb_define_method(cHttpParser, "finished?", HttpParser_is_finished,0); rb_define_method(cHttpParser, "nread", HttpParser_nread,0); + init_common_fields(); } diff --git a/ext/http11/http11_parser.c b/ext/http11/http11_parser.c index 1712d29..c2143de 100644 --- a/ext/http11/http11_parser.c +++ b/ext/http11/http11_parser.c @@ -10,34 +10,46 @@ #include #include +/* + * capitalizes all lower-case ASCII characters, + * converts dashes to underscores. + */ +static void snake_upcase_char(char *c) +{ + if (*c >= 'a' && *c <= 'z') + *c &= ~0x20; + else if (*c == '-') + *c = '_'; +} + #define LEN(AT, FPC) (FPC - buffer - parser->AT) #define MARK(M,FPC) (parser->M = (FPC) - buffer) #define PTR_TO(F) (buffer + parser->F) /** Machine **/ -#line 74 "http11_parser.rl" +#line 87 "http11_parser.rl" /** Data **/ -#line 25 "http11_parser.c" +#line 37 "http11_parser.c" static const int http_parser_start = 1; static const int http_parser_first_final = 57; static const int http_parser_error = 0; static const int http_parser_en_main = 1; -#line 78 "http11_parser.rl" +#line 91 "http11_parser.rl" int http_parser_init(http_parser *parser) { int cs = 0; -#line 37 "http11_parser.c" +#line 49 "http11_parser.c" { cs = http_parser_start; } -#line 82 "http11_parser.rl" +#line 95 "http11_parser.rl" parser->cs = cs; parser->body_start = 0; parser->content_len = 0; @@ -60,15 +72,15 @@ size_t http_parser_execute(http_parser *parser, const char *buffer, size_t len, p = buffer+off; pe = buffer+len; - assert(*pe == '\0' && "pointer does not end on NUL"); + /* assert(*pe == '\0' && "pointer does not end on NUL"); */ assert(pe - p == len - off && "pointers aren't same distance"); -#line 69 "http11_parser.c" +#line 81 "http11_parser.c" { if ( p == pe ) - goto _out; + goto _test_eof; switch ( cs ) { case 1: @@ -86,16 +98,17 @@ case 1: goto tr0; goto st0; st0: - goto _out0; +cs = 0; + goto _out; tr0: -#line 22 "http11_parser.rl" +#line 34 "http11_parser.rl" {MARK(mark, p); } goto st2; st2: if ( ++p == pe ) - goto _out2; + goto _test_eof2; case 2: -#line 99 "http11_parser.c" +#line 112 "http11_parser.c" switch( (*p) ) { case 32: goto tr2; case 36: goto st38; @@ -111,7 +124,7 @@ case 2: goto st38; goto st0; tr2: -#line 36 "http11_parser.rl" +#line 49 "http11_parser.rl" { if(parser->request_method != NULL) parser->request_method(parser->data, PTR_TO(mark), LEN(mark, p)); @@ -119,9 +132,9 @@ tr2: goto st3; st3: if ( ++p == pe ) - goto _out3; + goto _test_eof3; case 3: -#line 125 "http11_parser.c" +#line 138 "http11_parser.c" switch( (*p) ) { case 42: goto tr4; case 43: goto tr5; @@ -138,66 +151,75 @@ case 3: goto tr5; goto st0; tr4: -#line 22 "http11_parser.rl" +#line 34 "http11_parser.rl" {MARK(mark, p); } goto st4; st4: if ( ++p == pe ) - goto _out4; + goto _test_eof4; case 4: -#line 149 "http11_parser.c" +#line 162 "http11_parser.c" switch( (*p) ) { case 32: goto tr8; case 35: goto tr9; } goto st0; tr8: -#line 40 "http11_parser.rl" +#line 53 "http11_parser.rl" { if(parser->request_uri != NULL) parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p)); } goto st5; -tr30: -#line 44 "http11_parser.rl" +tr31: +#line 34 "http11_parser.rl" + {MARK(mark, p); } +#line 57 "http11_parser.rl" + { + if(parser->fragment != NULL) + parser->fragment(parser->data, PTR_TO(mark), LEN(mark, p)); + } + goto st5; +tr34: +#line 57 "http11_parser.rl" { if(parser->fragment != NULL) parser->fragment(parser->data, PTR_TO(mark), LEN(mark, p)); } goto st5; -tr40: -#line 60 "http11_parser.rl" +tr42: +#line 73 "http11_parser.rl" { if(parser->request_path != NULL) parser->request_path(parser->data, PTR_TO(mark), LEN(mark,p)); } -#line 40 "http11_parser.rl" +#line 53 "http11_parser.rl" { if(parser->request_uri != NULL) parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p)); } goto st5; -tr51: -#line 49 "http11_parser.rl" +tr53: +#line 62 "http11_parser.rl" {MARK(query_start, p); } -#line 50 "http11_parser.rl" +#line 63 "http11_parser.rl" { if(parser->query_string != NULL) parser->query_string(parser->data, PTR_TO(query_start), LEN(query_start, p)); } -#line 40 "http11_parser.rl" +#line 53 "http11_parser.rl" { if(parser->request_uri != NULL) parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p)); } goto st5; -tr55: -#line 50 "http11_parser.rl" +tr57: +#line 63 "http11_parser.rl" { if(parser->query_string != NULL) parser->query_string(parser->data, PTR_TO(query_start), LEN(query_start, p)); } -#line 40 "http11_parser.rl" +#line 53 "http11_parser.rl" { if(parser->request_uri != NULL) parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p)); @@ -205,55 +227,55 @@ tr55: goto st5; st5: if ( ++p == pe ) - goto _out5; + goto _test_eof5; case 5: -#line 211 "http11_parser.c" +#line 233 "http11_parser.c" if ( (*p) == 72 ) goto tr10; goto st0; tr10: -#line 22 "http11_parser.rl" +#line 34 "http11_parser.rl" {MARK(mark, p); } goto st6; st6: if ( ++p == pe ) - goto _out6; + goto _test_eof6; case 6: -#line 223 "http11_parser.c" +#line 245 "http11_parser.c" if ( (*p) == 84 ) goto st7; goto st0; st7: if ( ++p == pe ) - goto _out7; + goto _test_eof7; case 7: if ( (*p) == 84 ) goto st8; goto st0; st8: if ( ++p == pe ) - goto _out8; + goto _test_eof8; case 8: if ( (*p) == 80 ) goto st9; goto st0; st9: if ( ++p == pe ) - goto _out9; + goto _test_eof9; case 9: if ( (*p) == 47 ) goto st10; goto st0; st10: if ( ++p == pe ) - goto _out10; + goto _test_eof10; case 10: if ( 48 <= (*p) && (*p) <= 57 ) goto st11; goto st0; st11: if ( ++p == pe ) - goto _out11; + goto _test_eof11; case 11: if ( (*p) == 46 ) goto st12; @@ -262,14 +284,14 @@ case 11: goto st0; st12: if ( ++p == pe ) - goto _out12; + goto _test_eof12; case 12: if ( 48 <= (*p) && (*p) <= 57 ) goto st13; goto st0; st13: if ( ++p == pe ) - goto _out13; + goto _test_eof13; case 13: if ( (*p) == 13 ) goto tr18; @@ -277,14 +299,24 @@ case 13: goto st13; goto st0; tr18: -#line 55 "http11_parser.rl" +#line 68 "http11_parser.rl" { if(parser->http_version != NULL) parser->http_version(parser->data, PTR_TO(mark), LEN(mark, p)); } goto st14; tr26: -#line 31 "http11_parser.rl" +#line 43 "http11_parser.rl" + { MARK(mark, p); } +#line 44 "http11_parser.rl" + { + if(parser->http_field != NULL) { + parser->http_field(parser->data, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, p)); + } + } + goto st14; +tr29: +#line 44 "http11_parser.rl" { if(parser->http_field != NULL) { parser->http_field(parser->data, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, p)); @@ -293,15 +325,15 @@ tr26: goto st14; st14: if ( ++p == pe ) - goto _out14; + goto _test_eof14; case 14: -#line 299 "http11_parser.c" +#line 331 "http11_parser.c" if ( (*p) == 10 ) goto st15; goto st0; st15: if ( ++p == pe ) - goto _out15; + goto _test_eof15; case 15: switch( (*p) ) { case 13: goto st16; @@ -329,131 +361,137 @@ case 15: goto st0; st16: if ( ++p == pe ) - goto _out16; + goto _test_eof16; case 16: if ( (*p) == 10 ) goto tr22; goto st0; tr22: -#line 65 "http11_parser.rl" +#line 78 "http11_parser.rl" { parser->body_start = p - buffer + 1; if(parser->header_done != NULL) parser->header_done(parser->data, p + 1, pe - p - 1); - goto _out57; + {p++; cs = 57; goto _out;} } goto st57; st57: if ( ++p == pe ) - goto _out57; + goto _test_eof57; case 57: -#line 351 "http11_parser.c" +#line 383 "http11_parser.c" goto st0; tr21: -#line 25 "http11_parser.rl" +#line 37 "http11_parser.rl" { MARK(field_start, p); } +#line 38 "http11_parser.rl" + { snake_upcase_char((char *)p); } + goto st17; +tr23: +#line 38 "http11_parser.rl" + { snake_upcase_char((char *)p); } goto st17; st17: if ( ++p == pe ) - goto _out17; + goto _test_eof17; case 17: -#line 361 "http11_parser.c" +#line 399 "http11_parser.c" switch( (*p) ) { - case 33: goto st17; + case 33: goto tr23; case 58: goto tr24; - case 124: goto st17; - case 126: goto st17; + case 124: goto tr23; + case 126: goto tr23; } if ( (*p) < 45 ) { if ( (*p) > 39 ) { if ( 42 <= (*p) && (*p) <= 43 ) - goto st17; + goto tr23; } else if ( (*p) >= 35 ) - goto st17; + goto tr23; } else if ( (*p) > 46 ) { if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) - goto st17; + goto tr23; } else if ( (*p) > 90 ) { if ( 94 <= (*p) && (*p) <= 122 ) - goto st17; + goto tr23; } else - goto st17; + goto tr23; } else - goto st17; + goto tr23; goto st0; tr24: -#line 26 "http11_parser.rl" +#line 39 "http11_parser.rl" { parser->field_len = LEN(field_start, p); } goto st18; tr27: -#line 30 "http11_parser.rl" +#line 43 "http11_parser.rl" { MARK(mark, p); } goto st18; st18: if ( ++p == pe ) - goto _out18; + goto _test_eof18; case 18: -#line 400 "http11_parser.c" +#line 438 "http11_parser.c" switch( (*p) ) { case 13: goto tr26; case 32: goto tr27; } goto tr25; tr25: -#line 30 "http11_parser.rl" +#line 43 "http11_parser.rl" { MARK(mark, p); } goto st19; st19: if ( ++p == pe ) - goto _out19; + goto _test_eof19; case 19: -#line 414 "http11_parser.c" +#line 452 "http11_parser.c" if ( (*p) == 13 ) - goto tr26; + goto tr29; goto st19; tr9: -#line 40 "http11_parser.rl" +#line 53 "http11_parser.rl" { if(parser->request_uri != NULL) parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p)); } goto st20; -tr41: -#line 60 "http11_parser.rl" +tr43: +#line 73 "http11_parser.rl" { if(parser->request_path != NULL) parser->request_path(parser->data, PTR_TO(mark), LEN(mark,p)); } -#line 40 "http11_parser.rl" +#line 53 "http11_parser.rl" { if(parser->request_uri != NULL) parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p)); } goto st20; -tr52: -#line 49 "http11_parser.rl" +tr54: +#line 62 "http11_parser.rl" {MARK(query_start, p); } -#line 50 "http11_parser.rl" +#line 63 "http11_parser.rl" { if(parser->query_string != NULL) parser->query_string(parser->data, PTR_TO(query_start), LEN(query_start, p)); } -#line 40 "http11_parser.rl" +#line 53 "http11_parser.rl" { if(parser->request_uri != NULL) parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p)); } goto st20; -tr56: -#line 50 "http11_parser.rl" +tr58: +#line 63 "http11_parser.rl" { if(parser->query_string != NULL) parser->query_string(parser->data, PTR_TO(query_start), LEN(query_start, p)); } -#line 40 "http11_parser.rl" +#line 53 "http11_parser.rl" { if(parser->request_uri != NULL) parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p)); @@ -461,12 +499,12 @@ tr56: goto st20; st20: if ( ++p == pe ) - goto _out20; + goto _test_eof20; case 20: -#line 467 "http11_parser.c" +#line 505 "http11_parser.c" switch( (*p) ) { - case 32: goto tr30; - case 37: goto tr31; + case 32: goto tr31; + case 37: goto tr32; case 60: goto st0; case 62: goto st0; case 127: goto st0; @@ -476,18 +514,18 @@ case 20: goto st0; } else if ( (*p) >= 0 ) goto st0; - goto tr29; -tr29: -#line 22 "http11_parser.rl" + goto tr30; +tr30: +#line 34 "http11_parser.rl" {MARK(mark, p); } goto st21; st21: if ( ++p == pe ) - goto _out21; + goto _test_eof21; case 21: -#line 489 "http11_parser.c" +#line 527 "http11_parser.c" switch( (*p) ) { - case 32: goto tr30; + case 32: goto tr34; case 37: goto st22; case 60: goto st0; case 62: goto st0; @@ -499,15 +537,15 @@ case 21: } else if ( (*p) >= 0 ) goto st0; goto st21; -tr31: -#line 22 "http11_parser.rl" +tr32: +#line 34 "http11_parser.rl" {MARK(mark, p); } goto st22; st22: if ( ++p == pe ) - goto _out22; + goto _test_eof22; case 22: -#line 511 "http11_parser.c" +#line 549 "http11_parser.c" if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) goto st23; @@ -519,7 +557,7 @@ case 22: goto st0; st23: if ( ++p == pe ) - goto _out23; + goto _test_eof23; case 23: if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) @@ -531,14 +569,14 @@ case 23: goto st21; goto st0; tr5: -#line 22 "http11_parser.rl" +#line 34 "http11_parser.rl" {MARK(mark, p); } goto st24; st24: if ( ++p == pe ) - goto _out24; + goto _test_eof24; case 24: -#line 542 "http11_parser.c" +#line 580 "http11_parser.c" switch( (*p) ) { case 43: goto st24; case 58: goto st25; @@ -556,14 +594,14 @@ case 24: goto st24; goto st0; tr7: -#line 22 "http11_parser.rl" +#line 34 "http11_parser.rl" {MARK(mark, p); } goto st25; st25: if ( ++p == pe ) - goto _out25; + goto _test_eof25; case 25: -#line 567 "http11_parser.c" +#line 605 "http11_parser.c" switch( (*p) ) { case 32: goto tr8; case 34: goto st0; @@ -578,7 +616,7 @@ case 25: goto st25; st26: if ( ++p == pe ) - goto _out26; + goto _test_eof26; case 26: if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) @@ -591,7 +629,7 @@ case 26: goto st0; st27: if ( ++p == pe ) - goto _out27; + goto _test_eof27; case 27: if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) @@ -603,23 +641,23 @@ case 27: goto st25; goto st0; tr6: -#line 22 "http11_parser.rl" +#line 34 "http11_parser.rl" {MARK(mark, p); } goto st28; st28: if ( ++p == pe ) - goto _out28; + goto _test_eof28; case 28: -#line 614 "http11_parser.c" +#line 652 "http11_parser.c" switch( (*p) ) { - case 32: goto tr40; + case 32: goto tr42; case 34: goto st0; - case 35: goto tr41; + case 35: goto tr43; case 37: goto st29; - case 59: goto tr43; + case 59: goto tr45; case 60: goto st0; case 62: goto st0; - case 63: goto tr44; + case 63: goto tr46; case 127: goto st0; } if ( 0 <= (*p) && (*p) <= 31 ) @@ -627,7 +665,7 @@ case 28: goto st28; st29: if ( ++p == pe ) - goto _out29; + goto _test_eof29; case 29: if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) @@ -640,7 +678,7 @@ case 29: goto st0; st30: if ( ++p == pe ) - goto _out30; + goto _test_eof30; case 30: if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) @@ -651,8 +689,8 @@ case 30: } else goto st28; goto st0; -tr43: -#line 60 "http11_parser.rl" +tr45: +#line 73 "http11_parser.rl" { if(parser->request_path != NULL) parser->request_path(parser->data, PTR_TO(mark), LEN(mark,p)); @@ -660,9 +698,9 @@ tr43: goto st31; st31: if ( ++p == pe ) - goto _out31; + goto _test_eof31; case 31: -#line 666 "http11_parser.c" +#line 704 "http11_parser.c" switch( (*p) ) { case 32: goto tr8; case 34: goto st0; @@ -678,7 +716,7 @@ case 31: goto st31; st32: if ( ++p == pe ) - goto _out32; + goto _test_eof32; case 32: if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) @@ -691,7 +729,7 @@ case 32: goto st0; st33: if ( ++p == pe ) - goto _out33; + goto _test_eof33; case 33: if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) @@ -702,8 +740,8 @@ case 33: } else goto st31; goto st0; -tr44: -#line 60 "http11_parser.rl" +tr46: +#line 73 "http11_parser.rl" { if(parser->request_path != NULL) parser->request_path(parser->data, PTR_TO(mark), LEN(mark,p)); @@ -711,34 +749,34 @@ tr44: goto st34; st34: if ( ++p == pe ) - goto _out34; + goto _test_eof34; case 34: -#line 717 "http11_parser.c" +#line 755 "http11_parser.c" switch( (*p) ) { - case 32: goto tr51; + case 32: goto tr53; case 34: goto st0; - case 35: goto tr52; - case 37: goto tr53; + case 35: goto tr54; + case 37: goto tr55; case 60: goto st0; case 62: goto st0; case 127: goto st0; } if ( 0 <= (*p) && (*p) <= 31 ) goto st0; - goto tr50; -tr50: -#line 49 "http11_parser.rl" + goto tr52; +tr52: +#line 62 "http11_parser.rl" {MARK(query_start, p); } goto st35; st35: if ( ++p == pe ) - goto _out35; + goto _test_eof35; case 35: -#line 738 "http11_parser.c" +#line 776 "http11_parser.c" switch( (*p) ) { - case 32: goto tr55; + case 32: goto tr57; case 34: goto st0; - case 35: goto tr56; + case 35: goto tr58; case 37: goto st36; case 60: goto st0; case 62: goto st0; @@ -747,15 +785,15 @@ case 35: if ( 0 <= (*p) && (*p) <= 31 ) goto st0; goto st35; -tr53: -#line 49 "http11_parser.rl" +tr55: +#line 62 "http11_parser.rl" {MARK(query_start, p); } goto st36; st36: if ( ++p == pe ) - goto _out36; + goto _test_eof36; case 36: -#line 759 "http11_parser.c" +#line 797 "http11_parser.c" if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) goto st37; @@ -767,7 +805,7 @@ case 36: goto st0; st37: if ( ++p == pe ) - goto _out37; + goto _test_eof37; case 37: if ( (*p) < 65 ) { if ( 48 <= (*p) && (*p) <= 57 ) @@ -780,7 +818,7 @@ case 37: goto st0; st38: if ( ++p == pe ) - goto _out38; + goto _test_eof38; case 38: switch( (*p) ) { case 32: goto tr2; @@ -798,7 +836,7 @@ case 38: goto st0; st39: if ( ++p == pe ) - goto _out39; + goto _test_eof39; case 39: switch( (*p) ) { case 32: goto tr2; @@ -816,7 +854,7 @@ case 39: goto st0; st40: if ( ++p == pe ) - goto _out40; + goto _test_eof40; case 40: switch( (*p) ) { case 32: goto tr2; @@ -834,7 +872,7 @@ case 40: goto st0; st41: if ( ++p == pe ) - goto _out41; + goto _test_eof41; case 41: switch( (*p) ) { case 32: goto tr2; @@ -852,7 +890,7 @@ case 41: goto st0; st42: if ( ++p == pe ) - goto _out42; + goto _test_eof42; case 42: switch( (*p) ) { case 32: goto tr2; @@ -870,7 +908,7 @@ case 42: goto st0; st43: if ( ++p == pe ) - goto _out43; + goto _test_eof43; case 43: switch( (*p) ) { case 32: goto tr2; @@ -888,7 +926,7 @@ case 43: goto st0; st44: if ( ++p == pe ) - goto _out44; + goto _test_eof44; case 44: switch( (*p) ) { case 32: goto tr2; @@ -906,7 +944,7 @@ case 44: goto st0; st45: if ( ++p == pe ) - goto _out45; + goto _test_eof45; case 45: switch( (*p) ) { case 32: goto tr2; @@ -924,7 +962,7 @@ case 45: goto st0; st46: if ( ++p == pe ) - goto _out46; + goto _test_eof46; case 46: switch( (*p) ) { case 32: goto tr2; @@ -942,7 +980,7 @@ case 46: goto st0; st47: if ( ++p == pe ) - goto _out47; + goto _test_eof47; case 47: switch( (*p) ) { case 32: goto tr2; @@ -960,7 +998,7 @@ case 47: goto st0; st48: if ( ++p == pe ) - goto _out48; + goto _test_eof48; case 48: switch( (*p) ) { case 32: goto tr2; @@ -978,7 +1016,7 @@ case 48: goto st0; st49: if ( ++p == pe ) - goto _out49; + goto _test_eof49; case 49: switch( (*p) ) { case 32: goto tr2; @@ -996,7 +1034,7 @@ case 49: goto st0; st50: if ( ++p == pe ) - goto _out50; + goto _test_eof50; case 50: switch( (*p) ) { case 32: goto tr2; @@ -1014,7 +1052,7 @@ case 50: goto st0; st51: if ( ++p == pe ) - goto _out51; + goto _test_eof51; case 51: switch( (*p) ) { case 32: goto tr2; @@ -1032,7 +1070,7 @@ case 51: goto st0; st52: if ( ++p == pe ) - goto _out52; + goto _test_eof52; case 52: switch( (*p) ) { case 32: goto tr2; @@ -1050,7 +1088,7 @@ case 52: goto st0; st53: if ( ++p == pe ) - goto _out53; + goto _test_eof53; case 53: switch( (*p) ) { case 32: goto tr2; @@ -1068,7 +1106,7 @@ case 53: goto st0; st54: if ( ++p == pe ) - goto _out54; + goto _test_eof54; case 54: switch( (*p) ) { case 32: goto tr2; @@ -1086,7 +1124,7 @@ case 54: goto st0; st55: if ( ++p == pe ) - goto _out55; + goto _test_eof55; case 55: switch( (*p) ) { case 32: goto tr2; @@ -1104,73 +1142,73 @@ case 55: goto st0; st56: if ( ++p == pe ) - goto _out56; + goto _test_eof56; case 56: if ( (*p) == 32 ) goto tr2; goto st0; } - _out0: cs = 0; goto _out; - _out2: cs = 2; goto _out; - _out3: cs = 3; goto _out; - _out4: cs = 4; goto _out; - _out5: cs = 5; goto _out; - _out6: cs = 6; goto _out; - _out7: cs = 7; goto _out; - _out8: cs = 8; goto _out; - _out9: cs = 9; goto _out; - _out10: cs = 10; goto _out; - _out11: cs = 11; goto _out; - _out12: cs = 12; goto _out; - _out13: cs = 13; goto _out; - _out14: cs = 14; goto _out; - _out15: cs = 15; goto _out; - _out16: cs = 16; goto _out; - _out57: cs = 57; goto _out; - _out17: cs = 17; goto _out; - _out18: cs = 18; goto _out; - _out19: cs = 19; goto _out; - _out20: cs = 20; goto _out; - _out21: cs = 21; goto _out; - _out22: cs = 22; goto _out; - _out23: cs = 23; goto _out; - _out24: cs = 24; goto _out; - _out25: cs = 25; goto _out; - _out26: cs = 26; goto _out; - _out27: cs = 27; goto _out; - _out28: cs = 28; goto _out; - _out29: cs = 29; goto _out; - _out30: cs = 30; goto _out; - _out31: cs = 31; goto _out; - _out32: cs = 32; goto _out; - _out33: cs = 33; goto _out; - _out34: cs = 34; goto _out; - _out35: cs = 35; goto _out; - _out36: cs = 36; goto _out; - _out37: cs = 37; goto _out; - _out38: cs = 38; goto _out; - _out39: cs = 39; goto _out; - _out40: cs = 40; goto _out; - _out41: cs = 41; goto _out; - _out42: cs = 42; goto _out; - _out43: cs = 43; goto _out; - _out44: cs = 44; goto _out; - _out45: cs = 45; goto _out; - _out46: cs = 46; goto _out; - _out47: cs = 47; goto _out; - _out48: cs = 48; goto _out; - _out49: cs = 49; goto _out; - _out50: cs = 50; goto _out; - _out51: cs = 51; goto _out; - _out52: cs = 52; goto _out; - _out53: cs = 53; goto _out; - _out54: cs = 54; goto _out; - _out55: cs = 55; goto _out; - _out56: cs = 56; goto _out; + _test_eof2: cs = 2; goto _test_eof; + _test_eof3: cs = 3; goto _test_eof; + _test_eof4: cs = 4; goto _test_eof; + _test_eof5: cs = 5; goto _test_eof; + _test_eof6: cs = 6; goto _test_eof; + _test_eof7: cs = 7; goto _test_eof; + _test_eof8: cs = 8; goto _test_eof; + _test_eof9: cs = 9; goto _test_eof; + _test_eof10: cs = 10; goto _test_eof; + _test_eof11: cs = 11; goto _test_eof; + _test_eof12: cs = 12; goto _test_eof; + _test_eof13: cs = 13; goto _test_eof; + _test_eof14: cs = 14; goto _test_eof; + _test_eof15: cs = 15; goto _test_eof; + _test_eof16: cs = 16; goto _test_eof; + _test_eof57: cs = 57; goto _test_eof; + _test_eof17: cs = 17; goto _test_eof; + _test_eof18: cs = 18; goto _test_eof; + _test_eof19: cs = 19; goto _test_eof; + _test_eof20: cs = 20; goto _test_eof; + _test_eof21: cs = 21; goto _test_eof; + _test_eof22: cs = 22; goto _test_eof; + _test_eof23: cs = 23; goto _test_eof; + _test_eof24: cs = 24; goto _test_eof; + _test_eof25: cs = 25; goto _test_eof; + _test_eof26: cs = 26; goto _test_eof; + _test_eof27: cs = 27; goto _test_eof; + _test_eof28: cs = 28; goto _test_eof; + _test_eof29: cs = 29; goto _test_eof; + _test_eof30: cs = 30; goto _test_eof; + _test_eof31: cs = 31; goto _test_eof; + _test_eof32: cs = 32; goto _test_eof; + _test_eof33: cs = 33; goto _test_eof; + _test_eof34: cs = 34; goto _test_eof; + _test_eof35: cs = 35; goto _test_eof; + _test_eof36: cs = 36; goto _test_eof; + _test_eof37: cs = 37; goto _test_eof; + _test_eof38: cs = 38; goto _test_eof; + _test_eof39: cs = 39; goto _test_eof; + _test_eof40: cs = 40; goto _test_eof; + _test_eof41: cs = 41; goto _test_eof; + _test_eof42: cs = 42; goto _test_eof; + _test_eof43: cs = 43; goto _test_eof; + _test_eof44: cs = 44; goto _test_eof; + _test_eof45: cs = 45; goto _test_eof; + _test_eof46: cs = 46; goto _test_eof; + _test_eof47: cs = 47; goto _test_eof; + _test_eof48: cs = 48; goto _test_eof; + _test_eof49: cs = 49; goto _test_eof; + _test_eof50: cs = 50; goto _test_eof; + _test_eof51: cs = 51; goto _test_eof; + _test_eof52: cs = 52; goto _test_eof; + _test_eof53: cs = 53; goto _test_eof; + _test_eof54: cs = 54; goto _test_eof; + _test_eof55: cs = 55; goto _test_eof; + _test_eof56: cs = 56; goto _test_eof; + _test_eof: {} _out: {} } -#line 109 "http11_parser.rl" +#line 122 "http11_parser.rl" parser->cs = cs; parser->nread += p - (buffer + off); @@ -1182,27 +1220,11 @@ case 56: assert(parser->field_len <= len && "field has length longer than whole buffer"); assert(parser->field_start < len && "field starts after buffer end"); - if(parser->body_start) { - /* final \r\n combo encountered so stop right here */ - -#line 1189 "http11_parser.c" -#line 123 "http11_parser.rl" - parser->nread++; - } - return(parser->nread); } int http_parser_finish(http_parser *parser) { - int cs = parser->cs; - - -#line 1202 "http11_parser.c" -#line 134 "http11_parser.rl" - - parser->cs = cs; - if (http_parser_has_error(parser) ) { return -1; } else if (http_parser_is_finished(parser) ) { @@ -1217,5 +1239,5 @@ int http_parser_has_error(http_parser *parser) { } int http_parser_is_finished(http_parser *parser) { - return parser->cs == http_parser_first_final; + return parser->cs >= http_parser_first_final; } diff --git a/ext/http11/http11_parser.java.rl b/ext/http11/http11_parser.java.rl index 71f8d3c..c9be22e 100644 --- a/ext/http11/http11_parser.java.rl +++ b/ext/http11/http11_parser.java.rl @@ -13,6 +13,7 @@ public class Http11Parser { action mark {parser.mark = fpc; } action start_field { parser.field_start = fpc; } + action snake_upcase_field { /* FIXME stub */ } action write_field { parser.field_len = fpc-parser.field_start; } diff --git a/ext/http11/http11_parser.rl b/ext/http11/http11_parser.rl index fffe57a..5e551a3 100644 --- a/ext/http11/http11_parser.rl +++ b/ext/http11/http11_parser.rl @@ -9,6 +9,18 @@ #include #include +/* + * capitalizes all lower-case ASCII characters, + * converts dashes to underscores. + */ +static void snake_upcase_char(char *c) +{ + if (*c >= 'a' && *c <= 'z') + *c &= ~0x20; + else if (*c == '-') + *c = '_'; +} + #define LEN(AT, FPC) (FPC - buffer - parser->AT) #define MARK(M,FPC) (parser->M = (FPC) - buffer) #define PTR_TO(F) (buffer + parser->F) @@ -23,6 +35,7 @@ action start_field { MARK(field_start, fpc); } + action snake_upcase_field { snake_upcase_char((char *)fpc); } action write_field { parser->field_len = LEN(field_start, fpc); } @@ -101,10 +114,9 @@ size_t http_parser_execute(http_parser *parser, const char *buffer, size_t len, p = buffer+off; pe = buffer+len; - assert(*pe == '\0' && "pointer does not end on NUL"); + /* assert(*pe == '\0' && "pointer does not end on NUL"); */ assert(pe - p == len - off && "pointers aren't same distance"); - %% write exec; parser->cs = cs; @@ -117,23 +129,11 @@ size_t http_parser_execute(http_parser *parser, const char *buffer, size_t len, assert(parser->field_len <= len && "field has length longer than whole buffer"); assert(parser->field_start < len && "field starts after buffer end"); - if(parser->body_start) { - /* final \r\n combo encountered so stop right here */ - %%write eof; - parser->nread++; - } - return(parser->nread); } int http_parser_finish(http_parser *parser) { - int cs = parser->cs; - - %%write eof; - - parser->cs = cs; - if (http_parser_has_error(parser) ) { return -1; } else if (http_parser_is_finished(parser) ) { @@ -148,5 +148,5 @@ int http_parser_has_error(http_parser *parser) { } int http_parser_is_finished(http_parser *parser) { - return parser->cs == http_parser_first_final; + return parser->cs >= http_parser_first_final; } diff --git a/ext/http11/http11_parser_common.rl b/ext/http11/http11_parser_common.rl index a70d4da..53c805f 100644 --- a/ext/http11/http11_parser_common.rl +++ b/ext/http11/http11_parser_common.rl @@ -41,7 +41,7 @@ HTTP_Version = ( "HTTP/" http_number ) >mark %http_version ; Request_Line = ( Method " " Request_URI ("#" Fragment){0,1} " " HTTP_Version CRLF ) ; - field_name = ( token -- ":" )+ >start_field %write_field; + field_name = ( token -- ":" )+ >start_field $snake_upcase_field %write_field; field_value = any* >start_value %write_value; diff --git a/ext/http11_java/org/jruby/mongrel/Http11Parser.java b/ext/http11_java/org/jruby/mongrel/Http11Parser.java index 30f188d..2dd0078 100644 --- a/ext/http11_java/org/jruby/mongrel/Http11Parser.java +++ b/ext/http11_java/org/jruby/mongrel/Http11Parser.java @@ -1,287 +1,215 @@ -// line 1 "http11_parser.java.rl" -package org.jruby.mongrel; - -import org.jruby.util.ByteList; +// line 1 "http11_parser.rl" +/** + * Copyright (c) 2005 Zed A. Shaw + * You can redistribute it and/or modify it under the same terms as Ruby. + */ +#include "http11_parser.h" +#include +#include +#include +#include +#include + +/* + * capitalizes all lower-case ASCII characters, + * converts dashes to underscores. + */ +static void snake_upcase_char(char *c) +{ + if (*c >= 'a' && *c <= 'z') + *c &= ~0x20; + else if (*c == '-') + *c = '_'; +} -public class Http11Parser { +#define LEN(AT, FPC) (FPC - buffer - parser->AT) +#define MARK(M,FPC) (parser->M = (FPC) - buffer) +#define PTR_TO(F) (buffer + parser->F) /** Machine **/ -// line 64 "http11_parser.java.rl" +// line 87 "http11_parser.rl" /** Data **/ -// line 16 "../../ext/http11_java/org/jruby/mongrel/Http11Parser.java" -private static void init__http_parser_actions_0( byte[] r ) -{ - r[0]=0; r[1]=1; r[2]=0; r[3]=1; r[4]=1; r[5]=1; r[6]=2; r[7]=1; - r[8]=3; r[9]=1; r[10]=4; r[11]=1; r[12]=5; r[13]=1; r[14]=6; r[15]=1; - r[16]=7; r[17]=1; r[18]=8; r[19]=1; r[20]=10; r[21]=1; r[22]=11; r[23]=1; - r[24]=12; r[25]=2; r[26]=9; r[27]=6; r[28]=2; r[29]=11; r[30]=6; r[31]=3; - r[32]=8; r[33]=9; r[34]=6; -} - -private static byte[] create__http_parser_actions( ) +// line 37 "../../ext/http11_java/org/jruby/mongrel/Http11Parser.java" +private static byte[] init__http_parser_actions_0() { - byte[] r = new byte[35]; - init__http_parser_actions_0( r ); - return r; + return new byte [] { + 0, 1, 0, 1, 2, 1, 3, 1, 4, 1, 5, 1, + 6, 1, 7, 1, 8, 1, 9, 1, 11, 1, 12, 1, + 13, 2, 0, 8, 2, 1, 2, 2, 4, 5, 2, 10, + 7, 2, 12, 7, 3, 9, 10, 7 + }; } -private static final byte _http_parser_actions[] = create__http_parser_actions(); +private static final byte _http_parser_actions[] = init__http_parser_actions_0(); -private static void init__http_parser_key_offsets_0( short[] r ) +private static short[] init__http_parser_key_offsets_0() { - r[0]=0; r[1]=0; r[2]=8; r[3]=17; r[4]=27; r[5]=29; r[6]=30; r[7]=31; - r[8]=32; r[9]=33; r[10]=34; r[11]=36; r[12]=39; r[13]=41; r[14]=44; r[15]=45; - r[16]=61; r[17]=62; r[18]=78; r[19]=80; r[20]=81; r[21]=90; r[22]=99; r[23]=105; - r[24]=111; r[25]=121; r[26]=130; r[27]=136; r[28]=142; r[29]=153; r[30]=159; r[31]=165; - r[32]=175; r[33]=181; r[34]=187; r[35]=196; r[36]=205; r[37]=211; r[38]=217; r[39]=226; - r[40]=235; r[41]=244; r[42]=253; r[43]=262; r[44]=271; r[45]=280; r[46]=289; r[47]=298; - r[48]=307; r[49]=316; r[50]=325; r[51]=334; r[52]=343; r[53]=352; r[54]=361; r[55]=370; - r[56]=379; r[57]=380; + return new short [] { + 0, 0, 8, 17, 27, 29, 30, 31, 32, 33, 34, 36, + 39, 41, 44, 45, 61, 62, 78, 80, 81, 90, 99, 105, + 111, 121, 130, 136, 142, 153, 159, 165, 175, 181, 187, 196, + 205, 211, 217, 226, 235, 244, 253, 262, 271, 280, 289, 298, + 307, 316, 325, 334, 343, 352, 361, 370, 379, 380 + }; } -private static short[] create__http_parser_key_offsets( ) -{ - short[] r = new short[58]; - init__http_parser_key_offsets_0( r ); - return r; -} +private static final short _http_parser_key_offsets[] = init__http_parser_key_offsets_0(); -private static final short _http_parser_key_offsets[] = create__http_parser_key_offsets(); - -private static void init__http_parser_trans_keys_0( char[] r ) +private static char[] init__http_parser_trans_keys_0() { - r[0]=36; r[1]=95; r[2]=45; r[3]=46; r[4]=48; r[5]=57; r[6]=65; r[7]=90; - r[8]=32; r[9]=36; r[10]=95; r[11]=45; r[12]=46; r[13]=48; r[14]=57; r[15]=65; - r[16]=90; r[17]=42; r[18]=43; r[19]=47; r[20]=58; r[21]=45; r[22]=57; r[23]=65; - r[24]=90; r[25]=97; r[26]=122; r[27]=32; r[28]=35; r[29]=72; r[30]=84; r[31]=84; - r[32]=80; r[33]=47; r[34]=48; r[35]=57; r[36]=46; r[37]=48; r[38]=57; r[39]=48; - r[40]=57; r[41]=13; r[42]=48; r[43]=57; r[44]=10; r[45]=13; r[46]=33; r[47]=124; - r[48]=126; r[49]=35; r[50]=39; r[51]=42; r[52]=43; r[53]=45; r[54]=46; r[55]=48; - r[56]=57; r[57]=65; r[58]=90; r[59]=94; r[60]=122; r[61]=10; r[62]=33; r[63]=58; - r[64]=124; r[65]=126; r[66]=35; r[67]=39; r[68]=42; r[69]=43; r[70]=45; r[71]=46; - r[72]=48; r[73]=57; r[74]=65; r[75]=90; r[76]=94; r[77]=122; r[78]=13; r[79]=32; - r[80]=13; r[81]=32; r[82]=37; r[83]=60; r[84]=62; r[85]=127; r[86]=0; r[87]=31; - r[88]=34; r[89]=35; r[90]=32; r[91]=37; r[92]=60; r[93]=62; r[94]=127; r[95]=0; - r[96]=31; r[97]=34; r[98]=35; r[99]=48; r[100]=57; r[101]=65; r[102]=70; r[103]=97; - r[104]=102; r[105]=48; r[106]=57; r[107]=65; r[108]=70; r[109]=97; r[110]=102; r[111]=43; - r[112]=58; r[113]=45; r[114]=46; r[115]=48; r[116]=57; r[117]=65; r[118]=90; r[119]=97; - r[120]=122; r[121]=32; r[122]=34; r[123]=35; r[124]=37; r[125]=60; r[126]=62; r[127]=127; - r[128]=0; r[129]=31; r[130]=48; r[131]=57; r[132]=65; r[133]=70; r[134]=97; r[135]=102; - r[136]=48; r[137]=57; r[138]=65; r[139]=70; r[140]=97; r[141]=102; r[142]=32; r[143]=34; - r[144]=35; r[145]=37; r[146]=59; r[147]=60; r[148]=62; r[149]=63; r[150]=127; r[151]=0; - r[152]=31; r[153]=48; r[154]=57; r[155]=65; r[156]=70; r[157]=97; r[158]=102; r[159]=48; - r[160]=57; r[161]=65; r[162]=70; r[163]=97; r[164]=102; r[165]=32; r[166]=34; r[167]=35; - r[168]=37; r[169]=60; r[170]=62; r[171]=63; r[172]=127; r[173]=0; r[174]=31; r[175]=48; - r[176]=57; r[177]=65; r[178]=70; r[179]=97; r[180]=102; r[181]=48; r[182]=57; r[183]=65; - r[184]=70; r[185]=97; r[186]=102; r[187]=32; r[188]=34; r[189]=35; r[190]=37; r[191]=60; - r[192]=62; r[193]=127; r[194]=0; r[195]=31; r[196]=32; r[197]=34; r[198]=35; r[199]=37; - r[200]=60; r[201]=62; r[202]=127; r[203]=0; r[204]=31; r[205]=48; r[206]=57; r[207]=65; - r[208]=70; r[209]=97; r[210]=102; r[211]=48; r[212]=57; r[213]=65; r[214]=70; r[215]=97; - r[216]=102; r[217]=32; r[218]=36; r[219]=95; r[220]=45; r[221]=46; r[222]=48; r[223]=57; - r[224]=65; r[225]=90; r[226]=32; r[227]=36; r[228]=95; r[229]=45; r[230]=46; r[231]=48; - r[232]=57; r[233]=65; r[234]=90; r[235]=32; r[236]=36; r[237]=95; r[238]=45; r[239]=46; - r[240]=48; r[241]=57; r[242]=65; r[243]=90; r[244]=32; r[245]=36; r[246]=95; r[247]=45; - r[248]=46; r[249]=48; r[250]=57; r[251]=65; r[252]=90; r[253]=32; r[254]=36; r[255]=95; - r[256]=45; r[257]=46; r[258]=48; r[259]=57; r[260]=65; r[261]=90; r[262]=32; r[263]=36; - r[264]=95; r[265]=45; r[266]=46; r[267]=48; r[268]=57; r[269]=65; r[270]=90; r[271]=32; - r[272]=36; r[273]=95; r[274]=45; r[275]=46; r[276]=48; r[277]=57; r[278]=65; r[279]=90; - r[280]=32; r[281]=36; r[282]=95; r[283]=45; r[284]=46; r[285]=48; r[286]=57; r[287]=65; - r[288]=90; r[289]=32; r[290]=36; r[291]=95; r[292]=45; r[293]=46; r[294]=48; r[295]=57; - r[296]=65; r[297]=90; r[298]=32; r[299]=36; r[300]=95; r[301]=45; r[302]=46; r[303]=48; - r[304]=57; r[305]=65; r[306]=90; r[307]=32; r[308]=36; r[309]=95; r[310]=45; r[311]=46; - r[312]=48; r[313]=57; r[314]=65; r[315]=90; r[316]=32; r[317]=36; r[318]=95; r[319]=45; - r[320]=46; r[321]=48; r[322]=57; r[323]=65; r[324]=90; r[325]=32; r[326]=36; r[327]=95; - r[328]=45; r[329]=46; r[330]=48; r[331]=57; r[332]=65; r[333]=90; r[334]=32; r[335]=36; - r[336]=95; r[337]=45; r[338]=46; r[339]=48; r[340]=57; r[341]=65; r[342]=90; r[343]=32; - r[344]=36; r[345]=95; r[346]=45; r[347]=46; r[348]=48; r[349]=57; r[350]=65; r[351]=90; - r[352]=32; r[353]=36; r[354]=95; r[355]=45; r[356]=46; r[357]=48; r[358]=57; r[359]=65; - r[360]=90; r[361]=32; r[362]=36; r[363]=95; r[364]=45; r[365]=46; r[366]=48; r[367]=57; - r[368]=65; r[369]=90; r[370]=32; r[371]=36; r[372]=95; r[373]=45; r[374]=46; r[375]=48; - r[376]=57; r[377]=65; r[378]=90; r[379]=32; r[380]=0; + return new char [] { + 36, 95, 45, 46, 48, 57, 65, 90, 32, 36, 95, 45, + 46, 48, 57, 65, 90, 42, 43, 47, 58, 45, 57, 65, + 90, 97, 122, 32, 35, 72, 84, 84, 80, 47, 48, 57, + 46, 48, 57, 48, 57, 13, 48, 57, 10, 13, 33, 124, + 126, 35, 39, 42, 43, 45, 46, 48, 57, 65, 90, 94, + 122, 10, 33, 58, 124, 126, 35, 39, 42, 43, 45, 46, + 48, 57, 65, 90, 94, 122, 13, 32, 13, 32, 37, 60, + 62, 127, 0, 31, 34, 35, 32, 37, 60, 62, 127, 0, + 31, 34, 35, 48, 57, 65, 70, 97, 102, 48, 57, 65, + 70, 97, 102, 43, 58, 45, 46, 48, 57, 65, 90, 97, + 122, 32, 34, 35, 37, 60, 62, 127, 0, 31, 48, 57, + 65, 70, 97, 102, 48, 57, 65, 70, 97, 102, 32, 34, + 35, 37, 59, 60, 62, 63, 127, 0, 31, 48, 57, 65, + 70, 97, 102, 48, 57, 65, 70, 97, 102, 32, 34, 35, + 37, 60, 62, 63, 127, 0, 31, 48, 57, 65, 70, 97, + 102, 48, 57, 65, 70, 97, 102, 32, 34, 35, 37, 60, + 62, 127, 0, 31, 32, 34, 35, 37, 60, 62, 127, 0, + 31, 48, 57, 65, 70, 97, 102, 48, 57, 65, 70, 97, + 102, 32, 36, 95, 45, 46, 48, 57, 65, 90, 32, 36, + 95, 45, 46, 48, 57, 65, 90, 32, 36, 95, 45, 46, + 48, 57, 65, 90, 32, 36, 95, 45, 46, 48, 57, 65, + 90, 32, 36, 95, 45, 46, 48, 57, 65, 90, 32, 36, + 95, 45, 46, 48, 57, 65, 90, 32, 36, 95, 45, 46, + 48, 57, 65, 90, 32, 36, 95, 45, 46, 48, 57, 65, + 90, 32, 36, 95, 45, 46, 48, 57, 65, 90, 32, 36, + 95, 45, 46, 48, 57, 65, 90, 32, 36, 95, 45, 46, + 48, 57, 65, 90, 32, 36, 95, 45, 46, 48, 57, 65, + 90, 32, 36, 95, 45, 46, 48, 57, 65, 90, 32, 36, + 95, 45, 46, 48, 57, 65, 90, 32, 36, 95, 45, 46, + 48, 57, 65, 90, 32, 36, 95, 45, 46, 48, 57, 65, + 90, 32, 36, 95, 45, 46, 48, 57, 65, 90, 32, 36, + 95, 45, 46, 48, 57, 65, 90, 32, 0 + }; } -private static char[] create__http_parser_trans_keys( ) -{ - char[] r = new char[381]; - init__http_parser_trans_keys_0( r ); - return r; -} - -private static final char _http_parser_trans_keys[] = create__http_parser_trans_keys(); - +private static final char _http_parser_trans_keys[] = init__http_parser_trans_keys_0(); -private static void init__http_parser_single_lengths_0( byte[] r ) -{ - r[0]=0; r[1]=2; r[2]=3; r[3]=4; r[4]=2; r[5]=1; r[6]=1; r[7]=1; - r[8]=1; r[9]=1; r[10]=0; r[11]=1; r[12]=0; r[13]=1; r[14]=1; r[15]=4; - r[16]=1; r[17]=4; r[18]=2; r[19]=1; r[20]=5; r[21]=5; r[22]=0; r[23]=0; - r[24]=2; r[25]=7; r[26]=0; r[27]=0; r[28]=9; r[29]=0; r[30]=0; r[31]=8; - r[32]=0; r[33]=0; r[34]=7; r[35]=7; r[36]=0; r[37]=0; r[38]=3; r[39]=3; - r[40]=3; r[41]=3; r[42]=3; r[43]=3; r[44]=3; r[45]=3; r[46]=3; r[47]=3; - r[48]=3; r[49]=3; r[50]=3; r[51]=3; r[52]=3; r[53]=3; r[54]=3; r[55]=3; - r[56]=1; r[57]=0; -} -private static byte[] create__http_parser_single_lengths( ) +private static byte[] init__http_parser_single_lengths_0() { - byte[] r = new byte[58]; - init__http_parser_single_lengths_0( r ); - return r; + return new byte [] { + 0, 2, 3, 4, 2, 1, 1, 1, 1, 1, 0, 1, + 0, 1, 1, 4, 1, 4, 2, 1, 5, 5, 0, 0, + 2, 7, 0, 0, 9, 0, 0, 8, 0, 0, 7, 7, + 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 1, 0 + }; } -private static final byte _http_parser_single_lengths[] = create__http_parser_single_lengths(); +private static final byte _http_parser_single_lengths[] = init__http_parser_single_lengths_0(); -private static void init__http_parser_range_lengths_0( byte[] r ) +private static byte[] init__http_parser_range_lengths_0() { - r[0]=0; r[1]=3; r[2]=3; r[3]=3; r[4]=0; r[5]=0; r[6]=0; r[7]=0; - r[8]=0; r[9]=0; r[10]=1; r[11]=1; r[12]=1; r[13]=1; r[14]=0; r[15]=6; - r[16]=0; r[17]=6; r[18]=0; r[19]=0; r[20]=2; r[21]=2; r[22]=3; r[23]=3; - r[24]=4; r[25]=1; r[26]=3; r[27]=3; r[28]=1; r[29]=3; r[30]=3; r[31]=1; - r[32]=3; r[33]=3; r[34]=1; r[35]=1; r[36]=3; r[37]=3; r[38]=3; r[39]=3; - r[40]=3; r[41]=3; r[42]=3; r[43]=3; r[44]=3; r[45]=3; r[46]=3; r[47]=3; - r[48]=3; r[49]=3; r[50]=3; r[51]=3; r[52]=3; r[53]=3; r[54]=3; r[55]=3; - r[56]=0; r[57]=0; + return new byte [] { + 0, 3, 3, 3, 0, 0, 0, 0, 0, 0, 1, 1, + 1, 1, 0, 6, 0, 6, 0, 0, 2, 2, 3, 3, + 4, 1, 3, 3, 1, 3, 3, 1, 3, 3, 1, 1, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 0, 0 + }; } -private static byte[] create__http_parser_range_lengths( ) -{ - byte[] r = new byte[58]; - init__http_parser_range_lengths_0( r ); - return r; -} - -private static final byte _http_parser_range_lengths[] = create__http_parser_range_lengths(); - +private static final byte _http_parser_range_lengths[] = init__http_parser_range_lengths_0(); -private static void init__http_parser_index_offsets_0( short[] r ) -{ - r[0]=0; r[1]=0; r[2]=6; r[3]=13; r[4]=21; r[5]=24; r[6]=26; r[7]=28; - r[8]=30; r[9]=32; r[10]=34; r[11]=36; r[12]=39; r[13]=41; r[14]=44; r[15]=46; - r[16]=57; r[17]=59; r[18]=70; r[19]=73; r[20]=75; r[21]=83; r[22]=91; r[23]=95; - r[24]=99; r[25]=106; r[26]=115; r[27]=119; r[28]=123; r[29]=134; r[30]=138; r[31]=142; - r[32]=152; r[33]=156; r[34]=160; r[35]=169; r[36]=178; r[37]=182; r[38]=186; r[39]=193; - r[40]=200; r[41]=207; r[42]=214; r[43]=221; r[44]=228; r[45]=235; r[46]=242; r[47]=249; - r[48]=256; r[49]=263; r[50]=270; r[51]=277; r[52]=284; r[53]=291; r[54]=298; r[55]=305; - r[56]=312; r[57]=314; -} -private static short[] create__http_parser_index_offsets( ) +private static short[] init__http_parser_index_offsets_0() { - short[] r = new short[58]; - init__http_parser_index_offsets_0( r ); - return r; + return new short [] { + 0, 0, 6, 13, 21, 24, 26, 28, 30, 32, 34, 36, + 39, 41, 44, 46, 57, 59, 70, 73, 75, 83, 91, 95, + 99, 106, 115, 119, 123, 134, 138, 142, 152, 156, 160, 169, + 178, 182, 186, 193, 200, 207, 214, 221, 228, 235, 242, 249, + 256, 263, 270, 277, 284, 291, 298, 305, 312, 314 + }; } -private static final short _http_parser_index_offsets[] = create__http_parser_index_offsets(); - +private static final short _http_parser_index_offsets[] = init__http_parser_index_offsets_0(); -private static void init__http_parser_indicies_0( byte[] r ) -{ - r[0]=0; r[1]=0; r[2]=0; r[3]=0; r[4]=0; r[5]=1; r[6]=2; r[7]=3; - r[8]=3; r[9]=3; r[10]=3; r[11]=3; r[12]=1; r[13]=4; r[14]=5; r[15]=6; - r[16]=7; r[17]=5; r[18]=5; r[19]=5; r[20]=1; r[21]=8; r[22]=9; r[23]=1; - r[24]=10; r[25]=1; r[26]=11; r[27]=1; r[28]=12; r[29]=1; r[30]=13; r[31]=1; - r[32]=14; r[33]=1; r[34]=15; r[35]=1; r[36]=16; r[37]=15; r[38]=1; r[39]=17; - r[40]=1; r[41]=18; r[42]=17; r[43]=1; r[44]=19; r[45]=1; r[46]=20; r[47]=21; - r[48]=21; r[49]=21; r[50]=21; r[51]=21; r[52]=21; r[53]=21; r[54]=21; r[55]=21; - r[56]=1; r[57]=22; r[58]=1; r[59]=23; r[60]=24; r[61]=23; r[62]=23; r[63]=23; - r[64]=23; r[65]=23; r[66]=23; r[67]=23; r[68]=23; r[69]=1; r[70]=26; r[71]=27; - r[72]=25; r[73]=26; r[74]=28; r[75]=29; r[76]=31; r[77]=1; r[78]=1; r[79]=1; - r[80]=1; r[81]=1; r[82]=30; r[83]=29; r[84]=33; r[85]=1; r[86]=1; r[87]=1; - r[88]=1; r[89]=1; r[90]=32; r[91]=34; r[92]=34; r[93]=34; r[94]=1; r[95]=32; - r[96]=32; r[97]=32; r[98]=1; r[99]=35; r[100]=36; r[101]=35; r[102]=35; r[103]=35; - r[104]=35; r[105]=1; r[106]=8; r[107]=1; r[108]=9; r[109]=37; r[110]=1; r[111]=1; - r[112]=1; r[113]=1; r[114]=36; r[115]=38; r[116]=38; r[117]=38; r[118]=1; r[119]=36; - r[120]=36; r[121]=36; r[122]=1; r[123]=39; r[124]=1; r[125]=41; r[126]=42; r[127]=43; - r[128]=1; r[129]=1; r[130]=44; r[131]=1; r[132]=1; r[133]=40; r[134]=45; r[135]=45; - r[136]=45; r[137]=1; r[138]=40; r[139]=40; r[140]=40; r[141]=1; r[142]=8; r[143]=1; - r[144]=9; r[145]=47; r[146]=1; r[147]=1; r[148]=48; r[149]=1; r[150]=1; r[151]=46; - r[152]=49; r[153]=49; r[154]=49; r[155]=1; r[156]=46; r[157]=46; r[158]=46; r[159]=1; - r[160]=50; r[161]=1; r[162]=52; r[163]=53; r[164]=1; r[165]=1; r[166]=1; r[167]=1; - r[168]=51; r[169]=54; r[170]=1; r[171]=56; r[172]=57; r[173]=1; r[174]=1; r[175]=1; - r[176]=1; r[177]=55; r[178]=58; r[179]=58; r[180]=58; r[181]=1; r[182]=55; r[183]=55; - r[184]=55; r[185]=1; r[186]=2; r[187]=59; r[188]=59; r[189]=59; r[190]=59; r[191]=59; - r[192]=1; r[193]=2; r[194]=60; r[195]=60; r[196]=60; r[197]=60; r[198]=60; r[199]=1; - r[200]=2; r[201]=61; r[202]=61; r[203]=61; r[204]=61; r[205]=61; r[206]=1; r[207]=2; - r[208]=62; r[209]=62; r[210]=62; r[211]=62; r[212]=62; r[213]=1; r[214]=2; r[215]=63; - r[216]=63; r[217]=63; r[218]=63; r[219]=63; r[220]=1; r[221]=2; r[222]=64; r[223]=64; - r[224]=64; r[225]=64; r[226]=64; r[227]=1; r[228]=2; r[229]=65; r[230]=65; r[231]=65; - r[232]=65; r[233]=65; r[234]=1; r[235]=2; r[236]=66; r[237]=66; r[238]=66; r[239]=66; - r[240]=66; r[241]=1; r[242]=2; r[243]=67; r[244]=67; r[245]=67; r[246]=67; r[247]=67; - r[248]=1; r[249]=2; r[250]=68; r[251]=68; r[252]=68; r[253]=68; r[254]=68; r[255]=1; - r[256]=2; r[257]=69; r[258]=69; r[259]=69; r[260]=69; r[261]=69; r[262]=1; r[263]=2; - r[264]=70; r[265]=70; r[266]=70; r[267]=70; r[268]=70; r[269]=1; r[270]=2; r[271]=71; - r[272]=71; r[273]=71; r[274]=71; r[275]=71; r[276]=1; r[277]=2; r[278]=72; r[279]=72; - r[280]=72; r[281]=72; r[282]=72; r[283]=1; r[284]=2; r[285]=73; r[286]=73; r[287]=73; - r[288]=73; r[289]=73; r[290]=1; r[291]=2; r[292]=74; r[293]=74; r[294]=74; r[295]=74; - r[296]=74; r[297]=1; r[298]=2; r[299]=75; r[300]=75; r[301]=75; r[302]=75; r[303]=75; - r[304]=1; r[305]=2; r[306]=76; r[307]=76; r[308]=76; r[309]=76; r[310]=76; r[311]=1; - r[312]=2; r[313]=1; r[314]=1; r[315]=0; -} -private static byte[] create__http_parser_indicies( ) +private static byte[] init__http_parser_indicies_0() { - byte[] r = new byte[316]; - init__http_parser_indicies_0( r ); - return r; + return new byte [] { + 0, 0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 3, + 1, 4, 5, 6, 7, 5, 5, 5, 1, 8, 9, 1, + 10, 1, 11, 1, 12, 1, 13, 1, 14, 1, 15, 1, + 16, 15, 1, 17, 1, 18, 17, 1, 19, 1, 20, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 1, 22, 1, 23, + 24, 23, 23, 23, 23, 23, 23, 23, 23, 1, 26, 27, + 25, 29, 28, 30, 32, 1, 1, 1, 1, 1, 31, 33, + 35, 1, 1, 1, 1, 1, 34, 36, 36, 36, 1, 34, + 34, 34, 1, 37, 38, 37, 37, 37, 37, 1, 8, 1, + 9, 39, 1, 1, 1, 1, 38, 40, 40, 40, 1, 38, + 38, 38, 1, 41, 1, 43, 44, 45, 1, 1, 46, 1, + 1, 42, 47, 47, 47, 1, 42, 42, 42, 1, 8, 1, + 9, 49, 1, 1, 50, 1, 1, 48, 51, 51, 51, 1, + 48, 48, 48, 1, 52, 1, 54, 55, 1, 1, 1, 1, + 53, 56, 1, 58, 59, 1, 1, 1, 1, 57, 60, 60, + 60, 1, 57, 57, 57, 1, 2, 61, 61, 61, 61, 61, + 1, 2, 62, 62, 62, 62, 62, 1, 2, 63, 63, 63, + 63, 63, 1, 2, 64, 64, 64, 64, 64, 1, 2, 65, + 65, 65, 65, 65, 1, 2, 66, 66, 66, 66, 66, 1, + 2, 67, 67, 67, 67, 67, 1, 2, 68, 68, 68, 68, + 68, 1, 2, 69, 69, 69, 69, 69, 1, 2, 70, 70, + 70, 70, 70, 1, 2, 71, 71, 71, 71, 71, 1, 2, + 72, 72, 72, 72, 72, 1, 2, 73, 73, 73, 73, 73, + 1, 2, 74, 74, 74, 74, 74, 1, 2, 75, 75, 75, + 75, 75, 1, 2, 76, 76, 76, 76, 76, 1, 2, 77, + 77, 77, 77, 77, 1, 2, 78, 78, 78, 78, 78, 1, + 2, 1, 1, 0 + }; } -private static final byte _http_parser_indicies[] = create__http_parser_indicies(); +private static final byte _http_parser_indicies[] = init__http_parser_indicies_0(); -private static void init__http_parser_trans_targs_wi_0( byte[] r ) +private static byte[] init__http_parser_trans_targs_wi_0() { - r[0]=2; r[1]=0; r[2]=3; r[3]=38; r[4]=4; r[5]=24; r[6]=28; r[7]=25; - r[8]=5; r[9]=20; r[10]=6; r[11]=7; r[12]=8; r[13]=9; r[14]=10; r[15]=11; - r[16]=12; r[17]=13; r[18]=14; r[19]=15; r[20]=16; r[21]=17; r[22]=57; r[23]=17; - r[24]=18; r[25]=19; r[26]=14; r[27]=18; r[28]=19; r[29]=5; r[30]=21; r[31]=22; - r[32]=21; r[33]=22; r[34]=23; r[35]=24; r[36]=25; r[37]=26; r[38]=27; r[39]=5; - r[40]=28; r[41]=20; r[42]=29; r[43]=31; r[44]=34; r[45]=30; r[46]=31; r[47]=32; - r[48]=34; r[49]=33; r[50]=5; r[51]=35; r[52]=20; r[53]=36; r[54]=5; r[55]=35; - r[56]=20; r[57]=36; r[58]=37; r[59]=39; r[60]=40; r[61]=41; r[62]=42; r[63]=43; - r[64]=44; r[65]=45; r[66]=46; r[67]=47; r[68]=48; r[69]=49; r[70]=50; r[71]=51; - r[72]=52; r[73]=53; r[74]=54; r[75]=55; r[76]=56; + return new byte [] { + 2, 0, 3, 38, 4, 24, 28, 25, 5, 20, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 57, 17, + 18, 19, 14, 18, 19, 14, 5, 21, 22, 5, 21, 22, + 23, 24, 25, 26, 27, 5, 28, 20, 29, 31, 34, 30, + 31, 32, 34, 33, 5, 35, 20, 36, 5, 35, 20, 36, + 37, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, + 50, 51, 52, 53, 54, 55, 56 + }; } -private static byte[] create__http_parser_trans_targs_wi( ) -{ - byte[] r = new byte[77]; - init__http_parser_trans_targs_wi_0( r ); - return r; -} - -private static final byte _http_parser_trans_targs_wi[] = create__http_parser_trans_targs_wi(); +private static final byte _http_parser_trans_targs_wi[] = init__http_parser_trans_targs_wi_0(); -private static void init__http_parser_trans_actions_wi_0( byte[] r ) +private static byte[] init__http_parser_trans_actions_wi_0() { - r[0]=1; r[1]=0; r[2]=11; r[3]=0; r[4]=1; r[5]=1; r[6]=1; r[7]=1; - r[8]=13; r[9]=13; r[10]=1; r[11]=0; r[12]=0; r[13]=0; r[14]=0; r[15]=0; - r[16]=0; r[17]=0; r[18]=19; r[19]=0; r[20]=0; r[21]=3; r[22]=23; r[23]=0; - r[24]=5; r[25]=7; r[26]=9; r[27]=7; r[28]=0; r[29]=15; r[30]=1; r[31]=1; - r[32]=0; r[33]=0; r[34]=0; r[35]=0; r[36]=0; r[37]=0; r[38]=0; r[39]=28; - r[40]=0; r[41]=28; r[42]=0; r[43]=21; r[44]=21; r[45]=0; r[46]=0; r[47]=0; - r[48]=0; r[49]=0; r[50]=31; r[51]=17; r[52]=31; r[53]=17; r[54]=25; r[55]=0; - r[56]=25; r[57]=0; r[58]=0; r[59]=0; r[60]=0; r[61]=0; r[62]=0; r[63]=0; - r[64]=0; r[65]=0; r[66]=0; r[67]=0; r[68]=0; r[69]=0; r[70]=0; r[71]=0; - r[72]=0; r[73]=0; r[74]=0; r[75]=0; r[76]=0; + return new byte [] { + 1, 0, 11, 0, 1, 1, 1, 1, 13, 13, 1, 0, + 0, 0, 0, 0, 0, 0, 19, 0, 0, 28, 23, 3, + 5, 7, 31, 7, 0, 9, 25, 1, 1, 15, 0, 0, + 0, 0, 0, 0, 0, 37, 0, 37, 0, 21, 21, 0, + 0, 0, 0, 0, 40, 17, 40, 17, 34, 0, 34, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0 + }; } -private static byte[] create__http_parser_trans_actions_wi( ) -{ - byte[] r = new byte[77]; - init__http_parser_trans_actions_wi_0( r ); - return r; -} - -private static final byte _http_parser_trans_actions_wi[] = create__http_parser_trans_actions_wi(); +private static final byte _http_parser_trans_actions_wi[] = init__http_parser_trans_actions_wi_0(); static final int http_parser_start = 1; @@ -290,83 +218,64 @@ static final int http_parser_error = 0; static final int http_parser_en_main = 1; -// line 68 "http11_parser.java.rl" - - public static interface ElementCB { - public void call(Object data, int at, int length); - } - - public static interface FieldCB { - public void call(Object data, int field, int flen, int value, int vlen); - } - - public static class HttpParser { - int cs; - int body_start; - int content_len; - int nread; - int mark; - int field_start; - int field_len; - int query_start; - - Object data; - ByteList buffer; - - public FieldCB http_field; - public ElementCB request_method; - public ElementCB request_uri; - public ElementCB fragment; - public ElementCB request_path; - public ElementCB query_string; - public ElementCB http_version; - public ElementCB header_done; - - public void init() { - cs = 0; - - -// line 330 "../../ext/http11_java/org/jruby/mongrel/Http11Parser.java" +// line 91 "http11_parser.rl" + +int http_parser_init(http_parser *parser) { + int cs = 0; + +// line 227 "../../ext/http11_java/org/jruby/mongrel/Http11Parser.java" { cs = http_parser_start; } -// line 103 "http11_parser.java.rl" - - body_start = 0; - content_len = 0; - mark = 0; - nread = 0; - field_len = 0; - field_start = 0; - } - } - - public final HttpParser parser = new HttpParser(); - - public int execute(ByteList buffer, int off) { - int p, pe; - int cs = parser.cs; - int len = buffer.realSize; - assert off<=len : "offset past end of buffer"; - - p = off; - pe = len; - byte[] data = buffer.bytes; - parser.buffer = buffer; - - -// line 359 "../../ext/http11_java/org/jruby/mongrel/Http11Parser.java" +// line 95 "http11_parser.rl" + parser->cs = cs; + parser->body_start = 0; + parser->content_len = 0; + parser->mark = 0; + parser->nread = 0; + parser->field_len = 0; + parser->field_start = 0; + + return(1); +} + + +/** exec **/ +size_t http_parser_execute(http_parser *parser, const char *buffer, size_t len, size_t off) { + const char *p, *pe; + int cs = parser->cs; + + assert(off <= len && "offset past end of buffer"); + + p = buffer+off; + pe = buffer+len; + + /* assert(*pe == '\0' && "pointer does not end on NUL"); */ + assert(pe - p == len - off && "pointers aren't same distance"); + + + +// line 259 "../../ext/http11_java/org/jruby/mongrel/Http11Parser.java" { int _klen; - int _trans; + int _trans = 0; int _acts; int _nacts; int _keys; + int _goto_targ = 0; - if ( p != pe ) { - if ( cs != 0 ) { - _resume: while ( true ) { - _again: do { + _goto: while (true) { + switch ( _goto_targ ) { + case 0: + if ( p == pe ) { + _goto_targ = 4; + continue _goto; + } + if ( cs == 0 ) { + _goto_targ = 5; + continue _goto; + } +case 1: _match: do { _keys = _http_parser_key_offsets[cs]; _trans = _http_parser_index_offsets[cs]; @@ -419,154 +328,147 @@ static final int http_parser_en_main = 1; _trans = _http_parser_indicies[_trans]; cs = _http_parser_trans_targs_wi[_trans]; - if ( _http_parser_trans_actions_wi[_trans] == 0 ) - break _again; - - _acts = _http_parser_trans_actions_wi[_trans]; - _nacts = (int) _http_parser_actions[_acts++]; - while ( _nacts-- > 0 ) + if ( _http_parser_trans_actions_wi[_trans] != 0 ) { + _acts = _http_parser_trans_actions_wi[_trans]; + _nacts = (int) _http_parser_actions[_acts++]; + while ( _nacts-- > 0 ) { - switch ( _http_parser_actions[_acts++] ) - { + switch ( _http_parser_actions[_acts++] ) + { case 0: -// line 13 "http11_parser.java.rl" - {parser.mark = p; } +// line 34 "http11_parser.rl" + {MARK(mark, p); } break; case 1: -// line 15 "http11_parser.java.rl" - { parser.field_start = p; } +// line 37 "http11_parser.rl" + { MARK(field_start, p); } break; case 2: -// line 16 "http11_parser.java.rl" - { - parser.field_len = p-parser.field_start; - } +// line 38 "http11_parser.rl" + { snake_upcase_char((char *)p); } break; case 3: -// line 20 "http11_parser.java.rl" - { parser.mark = p; } - break; - case 4: -// line 21 "http11_parser.java.rl" +// line 39 "http11_parser.rl" { - if(parser.http_field != null) { - parser.http_field.call(parser.data, parser.field_start, parser.field_len, parser.mark, p-parser.mark); - } + parser->field_len = LEN(field_start, p); } + break; + case 4: +// line 43 "http11_parser.rl" + { MARK(mark, p); } break; case 5: -// line 26 "http11_parser.java.rl" +// line 44 "http11_parser.rl" { - if(parser.request_method != null) - parser.request_method.call(parser.data, parser.mark, p-parser.mark); + if(parser->http_field != NULL) { + parser->http_field(parser->data, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, p)); + } } break; case 6: -// line 30 "http11_parser.java.rl" +// line 49 "http11_parser.rl" { - if(parser.request_uri != null) - parser.request_uri.call(parser.data, parser.mark, p-parser.mark); + if(parser->request_method != NULL) + parser->request_method(parser->data, PTR_TO(mark), LEN(mark, p)); } break; case 7: -// line 34 "http11_parser.java.rl" +// line 53 "http11_parser.rl" { - if(parser.fragment != null) - parser.fragment.call(parser.data, parser.mark, p-parser.mark); + if(parser->request_uri != NULL) + parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, p)); } break; case 8: -// line 39 "http11_parser.java.rl" - {parser.query_start = p; } +// line 57 "http11_parser.rl" + { + if(parser->fragment != NULL) + parser->fragment(parser->data, PTR_TO(mark), LEN(mark, p)); + } break; case 9: -// line 40 "http11_parser.java.rl" +// line 62 "http11_parser.rl" + {MARK(query_start, p); } + break; + case 10: +// line 63 "http11_parser.rl" { - if(parser.query_string != null) - parser.query_string.call(parser.data, parser.query_start, p-parser.query_start); + if(parser->query_string != NULL) + parser->query_string(parser->data, PTR_TO(query_start), LEN(query_start, p)); } break; - case 10: -// line 45 "http11_parser.java.rl" + case 11: +// line 68 "http11_parser.rl" { - if(parser.http_version != null) - parser.http_version.call(parser.data, parser.mark, p-parser.mark); + if(parser->http_version != NULL) + parser->http_version(parser->data, PTR_TO(mark), LEN(mark, p)); } break; - case 11: -// line 50 "http11_parser.java.rl" + case 12: +// line 73 "http11_parser.rl" { - if(parser.request_path != null) - parser.request_path.call(parser.data, parser.mark, p-parser.mark); + if(parser->request_path != NULL) + parser->request_path(parser->data, PTR_TO(mark), LEN(mark,p)); } break; - case 12: -// line 55 "http11_parser.java.rl" + case 13: +// line 78 "http11_parser.rl" { - parser.body_start = p + 1; - if(parser.header_done != null) - parser.header_done.call(parser.data, p + 1, pe - p - 1); - if (true) break _resume; + parser->body_start = p - buffer + 1; + if(parser->header_done != NULL) + parser->header_done(parser->data, p + 1, pe - p - 1); + { p += 1; _goto_targ = 5; if (true) continue _goto;} } break; -// line 513 "../../ext/http11_java/org/jruby/mongrel/Http11Parser.java" +// line 424 "../../ext/http11_java/org/jruby/mongrel/Http11Parser.java" + } } } - } while (false); - if ( cs == 0 ) - break _resume; - if ( ++p == pe ) - break _resume; +case 2: + if ( cs == 0 ) { + _goto_targ = 5; + continue _goto; } - } } + if ( ++p != pe ) { + _goto_targ = 1; + continue _goto; } -// line 127 "http11_parser.java.rl" - - parser.cs = cs; - parser.nread += (p - off); - - assert p <= pe : "buffer overflow after parsing execute"; - assert parser.nread <= len : "nread longer than length"; - assert parser.body_start <= len : "body starts after buffer end"; - assert parser.mark < len : "mark is after buffer end"; - assert parser.field_len <= len : "field has length longer than whole buffer"; - assert parser.field_start < len : "field starts after buffer end"; - - if(parser.body_start>0) { - /* final \r\n combo encountered so stop right here */ - -// line 540 "../../ext/http11_java/org/jruby/mongrel/Http11Parser.java" -// line 141 "http11_parser.java.rl" - parser.nread++; - } - - return parser.nread; - } - - public int finish() { - int cs = parser.cs; - - -// line 552 "../../ext/http11_java/org/jruby/mongrel/Http11Parser.java" -// line 151 "http11_parser.java.rl" - - parser.cs = cs; - - if(has_error()) { - return -1; - } else if(is_finished()) { - return 1; - } else { - return 0; - } - } +case 4: +case 5: + } + break; } + } +// line 122 "http11_parser.rl" - public boolean has_error() { - return parser.cs == http_parser_error; - } + parser->cs = cs; + parser->nread += p - (buffer + off); + + assert(p <= pe && "buffer overflow after parsing execute"); + assert(parser->nread <= len && "nread longer than length"); + assert(parser->body_start <= len && "body starts after buffer end"); + assert(parser->mark < len && "mark is after buffer end"); + assert(parser->field_len <= len && "field has length longer than whole buffer"); + assert(parser->field_start < len && "field starts after buffer end"); - public boolean is_finished() { - return parser.cs == http_parser_first_final; + return(parser->nread); +} + +int http_parser_finish(http_parser *parser) +{ + if (http_parser_has_error(parser) ) { + return -1; + } else if (http_parser_is_finished(parser) ) { + return 1; + } else { + return 0; } } + +int http_parser_has_error(http_parser *parser) { + return parser->cs == http_parser_error; +} + +int http_parser_is_finished(http_parser *parser) { + return parser->cs >= http_parser_first_final; +} diff --git a/lib/mongrel.rb b/lib/mongrel.rb index d99c56d..1963322 100644 --- a/lib/mongrel.rb +++ b/lib/mongrel.rb @@ -200,7 +200,7 @@ module Mongrel STDERR.puts "#{Time.now}: Client error: #{e.inspect}" STDERR.puts e.backtrace.join("\n") end - request.body.delete if request and request.body.class == Tempfile + request.body.close! if request and request.body.class == Tempfile end end @@ -320,10 +320,15 @@ module Mongrel def register(uri, handler, in_front=false) begin @classifier.register(uri, [handler]) - rescue URIClassifier::RegistrationError + rescue URIClassifier::RegistrationError => e handlers = @classifier.resolve(uri)[2] - method_name = in_front ? 'unshift' : 'push' - handlers.send(method_name, handler) + if handlers + # Already registered + method_name = in_front ? 'unshift' : 'push' + handlers.send(method_name, handler) + else + raise + end end handler.listener = self end diff --git a/lib/mongrel/cgi.rb b/lib/mongrel/cgi.rb index 4173bde..3957611 100644 --- a/lib/mongrel/cgi.rb +++ b/lib/mongrel/cgi.rb @@ -26,7 +26,7 @@ module Mongrel # Refer to DirHandler#can_serve for more information on this. class CGIWrapper < ::CGI public :env_table - attr_reader :options + attr_reader :head attr_accessor :handler # Set this to false if you want calls to CGIWrapper.out to not actually send # the response until you force it. @@ -105,7 +105,7 @@ module Mongrel when Hash cookie.each_value {|c| to['Set-Cookie'] = c.to_s} else - to['Set-Cookie'] = options['cookie'].to_s + to['Set-Cookie'] = head['cookie'].to_s end @head.delete('cookie') diff --git a/lib/mongrel/http_request.rb b/lib/mongrel/http_request.rb index 82ffe42..c8d4ce4 100644 --- a/lib/mongrel/http_request.rb +++ b/lib/mongrel/http_request.rb @@ -93,7 +93,7 @@ module Mongrel STDERR.puts e.backtrace.join("\n") # any errors means we should delete the file, including if the file is dumped @socket.close rescue nil - @body.delete if @body.class == Tempfile + @body.close! if @body.class == Tempfile @body = nil # signals that there was a problem end end diff --git a/lib/mongrel/http_response.rb b/lib/mongrel/http_response.rb index 32e433e..3076712 100644 --- a/lib/mongrel/http_response.rb +++ b/lib/mongrel/http_response.rb @@ -75,7 +75,10 @@ module Mongrel elsif @header_sent raise "You have already sent the request headers." else - @header.out.truncate(0) + # XXX Dubious ( http://mongrel.rubyforge.org/ticket/19 ) + @header.out.close + @header = HeaderOut.new(StringIO.new) + @body.close @body = StringIO.new end diff --git a/projects/gem_plugin/CHANGELOG b/projects/gem_plugin/CHANGELOG index 7e1103d..cf39b5b 100644 --- a/projects/gem_plugin/CHANGELOG +++ b/projects/gem_plugin/CHANGELOG @@ -1,2 +1,4 @@ +v0.3. Use Gem.path, not Gem.dir, so that local gem repositories work (rooster). + v0.2.3. Signed gem. diff --git a/projects/gem_plugin/lib/gem_plugin.rb b/projects/gem_plugin/lib/gem_plugin.rb index 1996a61..4664aa1 100644 --- a/projects/gem_plugin/lib/gem_plugin.rb +++ b/projects/gem_plugin/lib/gem_plugin.rb @@ -105,8 +105,8 @@ module GemPlugin # To prevent this load requires the full path to the "init.rb" file, which # avoids the RubyGems autorequire magic. def load(needs = {}) - sdir = File.join(Gem.dir, "specifications") - gems = Gem::SourceIndex.from_installed_gems(sdir) + sdirs = Gem::SourceIndex.installed_spec_directories + gems = Gem::SourceIndex.from_gems_in(sdirs) needs = needs.merge({"gem_plugin" => INCLUDE}) gems.each do |path, gem| @@ -128,8 +128,11 @@ module GemPlugin # looks like no needs were set to false, so it's good # Previously was set wrong, we already have the correct gem path! - #gem_dir = File.join(Gem.dir, "gems", "#{gem.name}-#{gem.version}") - gem_dir = File.join(Gem.dir, "gems", path) + gem_dir = "" + Gem.path.each do |gem_path| + gem_dir = File.join(gem_path, "gems", path) + break if File.exists?(gem_dir) + end require File.join(gem_dir, "lib", gem.name, "init.rb") @gems[gem.name] = gem_dir diff --git a/projects/mongrel_cluster/lib/mongrel_cluster/init.rb b/projects/mongrel_cluster/lib/mongrel_cluster/init.rb index 1c3a613..0f18fe9 100644 --- a/projects/mongrel_cluster/lib/mongrel_cluster/init.rb +++ b/projects/mongrel_cluster/lib/mongrel_cluster/init.rb @@ -59,7 +59,7 @@ module Cluster def start read_options - argv = [ "mongrel_rails" ] + argv = @options['mongrel_rails'] argv << "start" argv << "-d" argv << "-e #{@options['environment']}" if @options['environment'] @@ -103,7 +103,7 @@ module Cluster def stop read_options - argv = [ "mongrel_rails" ] + argv = @options['mongrel_rails'] argv << "stop" argv << "-c #{@options["cwd"]}" if @options["cwd"] argv << "-f" if @force @@ -300,6 +300,7 @@ module Cluster ['-C', '--config PATH', "Path to cluster configuration file", :@config_file, "config/mongrel_cluster.yml"], ['', '--user USER', "User to run as", :@user, nil], ['', '--group GROUP', "Group to run as", :@group, nil], + ['', '--mongrel_rails PATH', "Full path to mongrel_rails script", :@mongrel_rails, "mongrel_rails"], ['', '--prefix PREFIX', "Rails prefix to use", :@prefix, nil] ] end @@ -334,6 +335,7 @@ module Cluster @options["user"] = @user if @user @options["group"] = @group if @group @options["prefix"] = @prefix if @prefix + @options["mongrel_rails"] = @mongrel_rails if @mongrel_rails log "Writing configuration file to #{@config_file}." File.open(@config_file,"w") {|f| f.write(@options.to_yaml)} diff --git a/projects/mongrel_cluster/lib/mongrel_cluster/recipes_2.rb b/projects/mongrel_cluster/lib/mongrel_cluster/recipes_2.rb index a82c424..312ef5c 100644 --- a/projects/mongrel_cluster/lib/mongrel_cluster/recipes_2.rb +++ b/projects/mongrel_cluster/lib/mongrel_cluster/recipes_2.rb @@ -7,7 +7,7 @@ Capistrano::Configuration.instance.load do set :mongrel_user, nil set :mongrel_group, nil set :mongrel_prefix, nil - set :mongrel_rails, 'mongrel_rails' + set :mongrel_rails, "mongrel_rails" set :mongrel_clean, false set :mongrel_pid_file, nil set :mongrel_log_file, nil @@ -37,6 +37,7 @@ Capistrano::Configuration.instance.load do argv << "--group #{mongrel_group}" if mongrel_group argv << "--prefix #{mongrel_prefix}" if mongrel_prefix argv << "-S #{mongrel_config_script}" if mongrel_config_script + argv << "--mongrel_rails #{mongrel_rails}" if mongrel_rails cmd = argv.join " " send(run_method, cmd) end diff --git a/test/unit/test_handlers.rb b/test/unit/test_handlers.rb index 1d316e5..27c0c08 100644 --- a/test/unit/test_handlers.rb +++ b/test/unit/test_handlers.rb @@ -61,6 +61,16 @@ class HandlersTest < Test::Unit::TestCase @config.stop(false, true) File.delete "/tmp/testfile" end + + def test_registration_exception_is_not_lost + assert_raises(Mongrel::URIClassifier::RegistrationError) do + @config = Mongrel::Configurator.new do + listener do + uri "bogus", :handler => SimpleHandler.new + end + end + end + end def test_more_web_server res = hit([ "http://localhost:9998/test", diff --git a/test/unit/test_http11.rb b/test/unit/test_http11.rb deleted file mode 100644 index e083abf..0000000 --- a/test/unit/test_http11.rb +++ /dev/null @@ -1,156 +0,0 @@ -# Copyright (c) 2005 Zed A. Shaw -# You can redistribute it and/or modify it under the same terms as Ruby. -# -# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html -# for more information. - -require 'test/test_helper' - -include Mongrel - -class HttpParserTest < Test::Unit::TestCase - - def test_parse_simple - parser = HttpParser.new - req = {} - http = "GET / HTTP/1.1\r\n\r\n" - nread = parser.execute(req, http, 0) - - assert nread == http.length, "Failed to parse the full HTTP request" - assert parser.finished?, "Parser didn't finish" - assert !parser.error?, "Parser had error" - assert nread == parser.nread, "Number read returned from execute does not match" - - assert_equal 'HTTP/1.1', req['SERVER_PROTOCOL'] - assert_equal '/', req['REQUEST_PATH'] - assert_equal 'HTTP/1.1', req['HTTP_VERSION'] - assert_equal '/', req['REQUEST_URI'] - assert_equal 'CGI/1.2', req['GATEWAY_INTERFACE'] - assert_equal 'GET', req['REQUEST_METHOD'] - assert_nil req['FRAGMENT'] - assert_nil req['QUERY_STRING'] - - parser.reset - assert parser.nread == 0, "Number read after reset should be 0" - end - - def test_parse_dumbfuck_headers - parser = HttpParser.new - req = {} - should_be_good = "GET / HTTP/1.1\r\naaaaaaaaaaaaa:++++++++++\r\n\r\n" - nread = parser.execute(req, should_be_good, 0) - assert_equal should_be_good.length, nread - assert parser.finished? - assert !parser.error? - - nasty_pound_header = "GET / HTTP/1.1\r\nX-SSL-Bullshit: -----BEGIN CERTIFICATE-----\r\n\tMIIFbTCCBFWgAwIBAgICH4cwDQYJKoZIhvcNAQEFBQAwcDELMAkGA1UEBhMCVUsx\r\n\tETAPBgNVBAoTCGVTY2llbmNlMRIwEAYDVQQLEwlBdXRob3JpdHkxCzAJBgNVBAMT\r\n\tAkNBMS0wKwYJKoZIhvcNAQkBFh5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMu\r\n\tdWswHhcNMDYwNzI3MTQxMzI4WhcNMDcwNzI3MTQxMzI4WjBbMQswCQYDVQQGEwJV\r\n\tSzERMA8GA1UEChMIZVNjaWVuY2UxEzARBgNVBAsTCk1hbmNoZXN0ZXIxCzAJBgNV\r\n\tBAcTmrsogriqMWLAk1DMRcwFQYDVQQDEw5taWNoYWVsIHBhcmQYJKoZIhvcNAQEB\r\n\tBQADggEPADCCAQoCggEBANPEQBgl1IaKdSS1TbhF3hEXSl72G9J+WC/1R64fAcEF\r\n\tW51rEyFYiIeZGx/BVzwXbeBoNUK41OK65sxGuflMo5gLflbwJtHBRIEKAfVVp3YR\r\n\tgW7cMA/s/XKgL1GEC7rQw8lIZT8RApukCGqOVHSi/F1SiFlPDxuDfmdiNzL31+sL\r\n\t0iwHDdNkGjy5pyBSB8Y79dsSJtCW/iaLB0/n8Sj7HgvvZJ7x0fr+RQjYOUUfrePP\r\n\tu2MSpFyf+9BbC/aXgaZuiCvSR+8Snv3xApQY+fULK/xY8h8Ua51iXoQ5jrgu2SqR\r\n\twgA7BUi3G8LFzMBl8FRCDYGUDy7M6QaHXx1ZWIPWNKsCAwEAAaOCAiQwggIgMAwG\r\n\tA1UdEwEB/wQCMAAwEQYJYIZIAYb4QgEBBAQDAgWgMA4GA1UdDwEB/wQEAwID6DAs\r\n\tBglghkgBhvhCAQ0EHxYdVUsgZS1TY2llbmNlIFVzZXIgQ2VydGlmaWNhdGUwHQYD\r\n\tVR0OBBYEFDTt/sf9PeMaZDHkUIldrDYMNTBZMIGaBgNVHSMEgZIwgY+AFAI4qxGj\r\n\tloCLDdMVKwiljjDastqooXSkcjBwMQswCQYDVQQGEwJVSzERMA8GA1UEChMIZVNj\r\n\taWVuY2UxEjAQBgNVBAsTCUF1dGhvcml0eTELMAkGA1UEAxMCQ0ExLTArBgkqhkiG\r\n\t9w0BCQEWHmNhLW9wZXJhdG9yQGdyaWQtc3VwcG9ydC5hYy51a4IBADApBgNVHRIE\r\n\tIjAggR5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMudWswGQYDVR0gBBIwEDAO\r\n\tBgwrBgEEAdkvAQEBAQYwPQYJYIZIAYb4QgEEBDAWLmh0dHA6Ly9jYS5ncmlkLXN1\r\n\tcHBvcnQuYWMudmT4sopwqlBWsvcHViL2NybC9jYWNybC5jcmwwPQYJYIZIAYb4QgEDBDAWLmh0\r\n\tdHA6Ly9jYS5ncmlkLXN1cHBvcnQuYWMudWsvcHViL2NybC9jYWNybC5jcmwwPwYD\r\n\tVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NhLmdyaWQt5hYy51ay9wdWIv\r\n\tY3JsL2NhY3JsLmNybDANBgkqhkiG9w0BAQUFAAOCAQEAS/U4iiooBENGW/Hwmmd3\r\n\tXCy6Zrt08YjKCzGNjorT98g8uGsqYjSxv/hmi0qlnlHs+k/3Iobc3LjS5AMYr5L8\r\n\tUO7OSkgFFlLHQyC9JzPfmLCAugvzEbyv4Olnsr8hbxF1MbKZoQxUZtMVu29wjfXk\r\n\thTeApBv7eaKCWpSp7MCbvgzm74izKhu3vlDk9w6qVrxePfGgpKPqfHiOoGhFnbTK\r\n\twTC6o2xq5y0qZ03JonF7OJspEd3I5zKY3E+ov7/ZhW6DqT8UFvsAdjvQbXyhV8Eu\r\n\tYhixw1aKEPzNjNowuIseVogKOLXxWI5vAi5HgXdS0/ES5gDGsABo4fqovUKlgop3\r\n\tRA==\r\n\t-----END CERTIFICATE-----\r\n\r\n" - parser = HttpParser.new - req = {} - #nread = parser.execute(req, nasty_pound_header, 0) - #assert_equal nasty_pound_header.length, nread - #assert parser.finished? - #assert !parser.error? - end - - def test_parse_error - parser = HttpParser.new - req = {} - bad_http = "GET / SsUTF/1.1" - - error = false - begin - nread = parser.execute(req, bad_http, 0) - rescue => details - error = true - end - - assert error, "failed to throw exception" - assert !parser.finished?, "Parser shouldn't be finished" - assert parser.error?, "Parser SHOULD have error" - end - - def test_fragment_in_uri - parser = HttpParser.new - req = {} - get = "GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.1\r\n\r\n" - assert_nothing_raised do - parser.execute(req, get, 0) - end - assert parser.finished? - assert_equal '/forums/1/topics/2375?page=1', req['REQUEST_URI'] - assert_equal 'posts-17408', req['FRAGMENT'] - end - - # lame random garbage maker - def rand_data(min, max, readable=true) - count = min + ((rand(max)+1) *10).to_i - res = count.to_s + "/" - - if readable - res << Digest::SHA1.hexdigest(rand(count * 100).to_s) * (count / 40) - else - res << Digest::SHA1.digest(rand(count * 100).to_s) * (count / 20) - end - - return res - end - - - def test_horrible_queries - parser = HttpParser.new - - # then that large header names are caught - 10.times do |c| - get = "GET /#{rand_data(10,120)} HTTP/1.1\r\nX-#{rand_data(1024, 1024+(c*1024))}: Test\r\n\r\n" - assert_raises Mongrel::HttpParserError do - parser.execute({}, get, 0) - parser.reset - end - end - - # then that large mangled field values are caught - 10.times do |c| - get = "GET /#{rand_data(10,120)} HTTP/1.1\r\nX-Test: #{rand_data(1024, 1024+(c*1024), false)}\r\n\r\n" - assert_raises Mongrel::HttpParserError do - parser.execute({}, get, 0) - parser.reset - end - end - - # then large headers are rejected too - get = "GET /#{rand_data(10,120)} HTTP/1.1\r\n" - get << "X-Test: test\r\n" * (80 * 1024) - assert_raises Mongrel::HttpParserError do - parser.execute({}, get, 0) - parser.reset - end - - # finally just that random garbage gets blocked all the time - 10.times do |c| - get = "GET #{rand_data(1024, 1024+(c*1024), false)} #{rand_data(1024, 1024+(c*1024), false)}\r\n\r\n" - assert_raises Mongrel::HttpParserError do - parser.execute({}, get, 0) - parser.reset - end - end - - end - - - - def test_query_parse - res = HttpRequest.query_parse("zed=1&frank=#{HttpRequest.escape('&&& ')}") - assert res["zed"], "didn't get the request right" - assert res["frank"], "no frank" - assert_equal "1", res["zed"], "wrong result" - assert_equal "&&& ", HttpRequest.unescape(res["frank"]), "wrong result" - - res = HttpRequest.query_parse("zed=1&zed=2&zed=3&frank=11;zed=45") - assert res["zed"], "didn't get the request right" - assert res["frank"], "no frank" - assert_equal 4,res["zed"].length, "wrong number for zed" - assert_equal "11",res["frank"], "wrong number for frank" - end - -end - diff --git a/test/unit/test_http_parser.rb b/test/unit/test_http_parser.rb new file mode 100644 index 0000000..d8f3fe8 --- /dev/null +++ b/test/unit/test_http_parser.rb @@ -0,0 +1,156 @@ +# Copyright (c) 2005 Zed A. Shaw +# You can redistribute it and/or modify it under the same terms as Ruby. +# +# Additional work donated by contributors. See http://mongrel.rubyforge.org/attributions.html +# for more information. + +require 'test/test_helper' + +include Mongrel + +class HttpParserTest < Test::Unit::TestCase + + def test_parse_simple + parser = HttpParser.new + req = {} + http = "GET / HTTP/1.1\r\n\r\n" + nread = parser.execute(req, http, 0) + + assert nread == http.length, "Failed to parse the full HTTP request" + assert parser.finished?, "Parser didn't finish" + assert !parser.error?, "Parser had error" + assert nread == parser.nread, "Number read returned from execute does not match" + + assert_equal 'HTTP/1.1', req['SERVER_PROTOCOL'] + assert_equal '/', req['REQUEST_PATH'] + assert_equal 'HTTP/1.1', req['HTTP_VERSION'] + assert_equal '/', req['REQUEST_URI'] + assert_equal 'CGI/1.2', req['GATEWAY_INTERFACE'] + assert_equal 'GET', req['REQUEST_METHOD'] + assert_nil req['FRAGMENT'] + assert_nil req['QUERY_STRING'] + + parser.reset + assert parser.nread == 0, "Number read after reset should be 0" + end + + def test_parse_strange_headers + parser = HttpParser.new + req = {} + should_be_good = "GET / HTTP/1.1\r\naaaaaaaaaaaaa:++++++++++\r\n\r\n" + nread = parser.execute(req, should_be_good, 0) + assert_equal should_be_good.length, nread + assert parser.finished? + assert !parser.error? + + nasty_pound_header = "GET / HTTP/1.1\r\nX-SSL-Bullshit: -----BEGIN CERTIFICATE-----\r\n\tMIIFbTCCBFWgAwIBAgICH4cwDQYJKoZIhvcNAQEFBQAwcDELMAkGA1UEBhMCVUsx\r\n\tETAPBgNVBAoTCGVTY2llbmNlMRIwEAYDVQQLEwlBdXRob3JpdHkxCzAJBgNVBAMT\r\n\tAkNBMS0wKwYJKoZIhvcNAQkBFh5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMu\r\n\tdWswHhcNMDYwNzI3MTQxMzI4WhcNMDcwNzI3MTQxMzI4WjBbMQswCQYDVQQGEwJV\r\n\tSzERMA8GA1UEChMIZVNjaWVuY2UxEzARBgNVBAsTCk1hbmNoZXN0ZXIxCzAJBgNV\r\n\tBAcTmrsogriqMWLAk1DMRcwFQYDVQQDEw5taWNoYWVsIHBhcmQYJKoZIhvcNAQEB\r\n\tBQADggEPADCCAQoCggEBANPEQBgl1IaKdSS1TbhF3hEXSl72G9J+WC/1R64fAcEF\r\n\tW51rEyFYiIeZGx/BVzwXbeBoNUK41OK65sxGuflMo5gLflbwJtHBRIEKAfVVp3YR\r\n\tgW7cMA/s/XKgL1GEC7rQw8lIZT8RApukCGqOVHSi/F1SiFlPDxuDfmdiNzL31+sL\r\n\t0iwHDdNkGjy5pyBSB8Y79dsSJtCW/iaLB0/n8Sj7HgvvZJ7x0fr+RQjYOUUfrePP\r\n\tu2MSpFyf+9BbC/aXgaZuiCvSR+8Snv3xApQY+fULK/xY8h8Ua51iXoQ5jrgu2SqR\r\n\twgA7BUi3G8LFzMBl8FRCDYGUDy7M6QaHXx1ZWIPWNKsCAwEAAaOCAiQwggIgMAwG\r\n\tA1UdEwEB/wQCMAAwEQYJYIZIAYb4QgEBBAQDAgWgMA4GA1UdDwEB/wQEAwID6DAs\r\n\tBglghkgBhvhCAQ0EHxYdVUsgZS1TY2llbmNlIFVzZXIgQ2VydGlmaWNhdGUwHQYD\r\n\tVR0OBBYEFDTt/sf9PeMaZDHkUIldrDYMNTBZMIGaBgNVHSMEgZIwgY+AFAI4qxGj\r\n\tloCLDdMVKwiljjDastqooXSkcjBwMQswCQYDVQQGEwJVSzERMA8GA1UEChMIZVNj\r\n\taWVuY2UxEjAQBgNVBAsTCUF1dGhvcml0eTELMAkGA1UEAxMCQ0ExLTArBgkqhkiG\r\n\t9w0BCQEWHmNhLW9wZXJhdG9yQGdyaWQtc3VwcG9ydC5hYy51a4IBADApBgNVHRIE\r\n\tIjAggR5jYS1vcGVyYXRvckBncmlkLXN1cHBvcnQuYWMudWswGQYDVR0gBBIwEDAO\r\n\tBgwrBgEEAdkvAQEBAQYwPQYJYIZIAYb4QgEEBDAWLmh0dHA6Ly9jYS5ncmlkLXN1\r\n\tcHBvcnQuYWMudmT4sopwqlBWsvcHViL2NybC9jYWNybC5jcmwwPQYJYIZIAYb4QgEDBDAWLmh0\r\n\tdHA6Ly9jYS5ncmlkLXN1cHBvcnQuYWMudWsvcHViL2NybC9jYWNybC5jcmwwPwYD\r\n\tVR0fBDgwNjA0oDKgMIYuaHR0cDovL2NhLmdyaWQt5hYy51ay9wdWIv\r\n\tY3JsL2NhY3JsLmNybDANBgkqhkiG9w0BAQUFAAOCAQEAS/U4iiooBENGW/Hwmmd3\r\n\tXCy6Zrt08YjKCzGNjorT98g8uGsqYjSxv/hmi0qlnlHs+k/3Iobc3LjS5AMYr5L8\r\n\tUO7OSkgFFlLHQyC9JzPfmLCAugvzEbyv4Olnsr8hbxF1MbKZoQxUZtMVu29wjfXk\r\n\thTeApBv7eaKCWpSp7MCbvgzm74izKhu3vlDk9w6qVrxePfGgpKPqfHiOoGhFnbTK\r\n\twTC6o2xq5y0qZ03JonF7OJspEd3I5zKY3E+ov7/ZhW6DqT8UFvsAdjvQbXyhV8Eu\r\n\tYhixw1aKEPzNjNowuIseVogKOLXxWI5vAi5HgXdS0/ES5gDGsABo4fqovUKlgop3\r\n\tRA==\r\n\t-----END CERTIFICATE-----\r\n\r\n" + parser = HttpParser.new + req = {} + nread = parser.execute(req, nasty_pound_header, 0) + assert_equal nasty_pound_header.length, nread + assert parser.finished? + assert !parser.error? + end + + def test_parse_error + parser = HttpParser.new + req = {} + bad_http = "GET / SsUTF/1.1" + + error = false + begin + nread = parser.execute(req, bad_http, 0) + rescue => details + error = true + end + + assert error, "failed to throw exception" + assert !parser.finished?, "Parser shouldn't be finished" + assert parser.error?, "Parser SHOULD have error" + end + + def test_fragment_in_uri + parser = HttpParser.new + req = {} + get = "GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.1\r\n\r\n" + assert_nothing_raised do + parser.execute(req, get, 0) + end + assert parser.finished? + assert_equal '/forums/1/topics/2375?page=1', req['REQUEST_URI'] + assert_equal 'posts-17408', req['FRAGMENT'] + end + + # lame random garbage maker + def rand_data(min, max, readable=true) + count = min + ((rand(max)+1) *10).to_i + res = count.to_s + "/" + + if readable + res << Digest::SHA1.hexdigest(rand(count * 100).to_s) * (count / 40) + else + res << Digest::SHA1.digest(rand(count * 100).to_s) * (count / 20) + end + + return res + end + + + def test_horrible_queries + parser = HttpParser.new + + # then that large header names are caught + 10.times do |c| + get = "GET /#{rand_data(10,120)} HTTP/1.1\r\nX-#{rand_data(1024, 1024+(c*1024))}: Test\r\n\r\n" + assert_raises Mongrel::HttpParserError do + parser.execute({}, get, 0) + parser.reset + end + end + + # then that large mangled field values are caught + 10.times do |c| + get = "GET /#{rand_data(10,120)} HTTP/1.1\r\nX-Test: #{rand_data(1024, 1024+(c*1024), false)}\r\n\r\n" + assert_raises Mongrel::HttpParserError do + parser.execute({}, get, 0) + parser.reset + end + end + + # then large headers are rejected too + get = "GET /#{rand_data(10,120)} HTTP/1.1\r\n" + get << "X-Test: test\r\n" * (80 * 1024) + assert_raises Mongrel::HttpParserError do + parser.execute({}, get, 0) + parser.reset + end + + # finally just that random garbage gets blocked all the time + 10.times do |c| + get = "GET #{rand_data(1024, 1024+(c*1024), false)} #{rand_data(1024, 1024+(c*1024), false)}\r\n\r\n" + assert_raises Mongrel::HttpParserError do + parser.execute({}, get, 0) + parser.reset + end + end + + end + + + + def test_query_parse + res = HttpRequest.query_parse("zed=1&frank=#{HttpRequest.escape('&&& ')}") + assert res["zed"], "didn't get the request right" + assert res["frank"], "no frank" + assert_equal "1", res["zed"], "wrong result" + assert_equal "&&& ", HttpRequest.unescape(res["frank"]), "wrong result" + + res = HttpRequest.query_parse("zed=1&zed=2&zed=3&frank=11;zed=45") + assert res["zed"], "didn't get the request right" + assert res["frank"], "no frank" + assert_equal 4,res["zed"].length, "wrong number for zed" + assert_equal "11",res["frank"], "wrong number for frank" + end + +end + -- cgit v1.2.3-24-ge0c7 From eda1ea00904dcf4b4e7ed533b327a842713ac11a Mon Sep 17 00:00:00 2001 From: luislavena Date: Mon, 31 Mar 2008 08:19:11 +0000 Subject: Remove fixed port numbers used in tests, make tests more friendly to CI tools. Use of #process_based_port as port number. Exclude DirHandler(nil) with absolute paths on Windows. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-2@999 19e92222-5c0b-0410-8929-a290d50e31e9 --- test/test_helper.rb | 13 +++++++++++++ test/unit/test_conditional.rb | 2 +- test/unit/test_configurator.rb | 11 ++++++----- test/unit/test_handlers.rb | 39 ++++++++++++++++++++------------------ test/unit/test_redirect_handler.rb | 5 +++-- test/unit/test_request_progress.rb | 9 +++++---- test/unit/test_ws.rb | 7 ++++--- 7 files changed, 53 insertions(+), 33 deletions(-) diff --git a/test/test_helper.rb b/test/test_helper.rb index 42ead2c..7615fdd 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -64,3 +64,16 @@ def hit(uris) return results end + +# process_based_port provides a port number, usable for TCP and UDP +# connections based on $$ and with a 5000 as base. +# this is required if you perform several builds of mongrel in parallel +# (like continuous integration systems) +def process_based_port + 5000 + $$ % 1000 +end + +# Platform check helper ;-) +def windows? + result = RUBY_PLATFORM =~ /djgpp|(cyg|ms|bcc)win|mingw/ +end \ No newline at end of file diff --git a/test/unit/test_conditional.rb b/test/unit/test_conditional.rb index 769dd91..64517db 100644 --- a/test/unit/test_conditional.rb +++ b/test/unit/test_conditional.rb @@ -10,7 +10,7 @@ include Mongrel class ConditionalResponseTest < Test::Unit::TestCase def setup - @server = HttpServer.new('127.0.0.1', 3501) + @server = HttpServer.new('127.0.0.1', process_based_port) @server.register('/', Mongrel::DirHandler.new('.')) @server.run diff --git a/test/unit/test_configurator.rb b/test/unit/test_configurator.rb index f55a8ae..dc9713a 100644 --- a/test/unit/test_configurator.rb +++ b/test/unit/test_configurator.rb @@ -29,11 +29,12 @@ end class ConfiguratorTest < Test::Unit::TestCase def test_base_handler_config + @port = process_based_port @config = nil redirect_test_io do @config = Mongrel::Configurator.new :host => "localhost" do - listener :port => 4501 do + listener :port => process_based_port do # 2 in front should run, but the sentinel shouldn't since dirhandler processes the request uri "/", :handler => plugin("/handlers/testplugin") uri "/", :handler => plugin("/handlers/testplugin") @@ -55,7 +56,7 @@ class ConfiguratorTest < Test::Unit::TestCase end end end - + # pp @config.listeners.values.first.classifier.routes @config.listeners.each do |host,listener| @@ -64,12 +65,12 @@ class ConfiguratorTest < Test::Unit::TestCase assert listener.classifier.uris.include?("/test"), "/test not registered" end - res = Net::HTTP.get(URI.parse('http://localhost:4501/test')) + res = Net::HTTP.get(URI.parse("http://localhost:#{@port}/test")) assert res != nil, "Didn't get a response" assert $test_plugin_fired == 3, "Test filter plugin didn't run 3 times." redirect_test_io do - res = Net::HTTP.get(URI.parse('http://localhost:4501/')) + res = Net::HTTP.get(URI.parse("http://localhost:#{@port}/")) assert res != nil, "Didn't get a response" assert $test_plugin_fired == 6, "Test filter plugin didn't run 6 times." @@ -80,7 +81,7 @@ class ConfiguratorTest < Test::Unit::TestCase end assert_raise Errno::EBADF, Errno::ECONNREFUSED do - res = Net::HTTP.get(URI.parse("http://localhost:4501/")) + res = Net::HTTP.get(URI.parse("http://localhost:#{@port}/")) end end diff --git a/test/unit/test_handlers.rb b/test/unit/test_handlers.rb index 27c0c08..66bf010 100644 --- a/test/unit/test_handlers.rb +++ b/test/unit/test_handlers.rb @@ -34,10 +34,11 @@ end class HandlersTest < Test::Unit::TestCase def setup + @port = process_based_port stats = Mongrel::StatisticsFilter.new(:sample_rate => 1) - @config = Mongrel::Configurator.new :host => '127.0.0.1', :port => 9998 do - listener do + @config = Mongrel::Configurator.new :host => '127.0.0.1' do + listener :port => process_based_port do uri "/", :handler => SimpleHandler.new uri "/", :handler => stats uri "/404", :handler => Mongrel::Error404Handler.new("Not found") @@ -50,8 +51,10 @@ class HandlersTest < Test::Unit::TestCase end end - File.open("/tmp/testfile", 'w') do - # Do nothing + unless windows? + File.open('/tmp/testfile', 'w') do + # Do nothing + end end @config.run @@ -59,7 +62,7 @@ class HandlersTest < Test::Unit::TestCase def teardown @config.stop(false, true) - File.delete "/tmp/testfile" + File.delete '/tmp/testfile' unless windows? end def test_registration_exception_is_not_lost @@ -73,19 +76,20 @@ class HandlersTest < Test::Unit::TestCase end def test_more_web_server - res = hit([ "http://localhost:9998/test", - "http://localhost:9998/dumb", - "http://localhost:9998/404", - "http://localhost:9998/files/rdoc/index.html", - "http://localhost:9998/files/rdoc/nothere.html", - "http://localhost:9998/files/rdoc/", - "http://localhost:9998/files_nodir/rdoc/", - "http://localhost:9998/status", + res = hit([ "http://localhost:#{@port}/test", + "http://localhost:#{@port}/dumb", + "http://localhost:#{@port}/404", + "http://localhost:#{@port}/files/rdoc/index.html", + "http://localhost:#{@port}/files/rdoc/nothere.html", + "http://localhost:#{@port}/files/rdoc/", + "http://localhost:#{@port}/files_nodir/rdoc/", + "http://localhost:#{@port}/status", ]) check_status res, String end def test_nil_dirhandler + return if windows? # Camping uses this internally handler = Mongrel::DirHandler.new(nil, false) assert handler.can_serve("/tmp/testfile") @@ -102,7 +106,7 @@ class HandlersTest < Test::Unit::TestCase end def test_deflate - Net::HTTP.start("localhost", 9998) do |h| + Net::HTTP.start("localhost", @port) do |h| # Test that no accept-encoding returns a non-deflated response req = h.get("/dumb") assert( @@ -120,14 +124,13 @@ class HandlersTest < Test::Unit::TestCase # TODO: find out why this fails on win32 but nowhere else #def test_posting_fails_dirhandler - # req = Net::HTTP::Post.new("http://localhost:9998/files/rdoc/") + # req = Net::HTTP::Post.new("http://localhost:#{@port}/files/rdoc/") # req.set_form_data({'from'=>'2005-01-01', 'to'=>'2005-03-31'}, ';') - # res = hit [["http://localhost:9998/files/rdoc/",req]] + # res = hit [["http://localhost:#{@port}/files/rdoc/",req]] # check_status res, Net::HTTPNotFound #end def test_unregister - @config.listeners["127.0.0.1:9998"].unregister("/") + @config.listeners["127.0.0.1:#{@port}"].unregister("/") end end - diff --git a/test/unit/test_redirect_handler.rb b/test/unit/test_redirect_handler.rb index 3207b46..e990427 100644 --- a/test/unit/test_redirect_handler.rb +++ b/test/unit/test_redirect_handler.rb @@ -9,11 +9,12 @@ require 'test/test_helper' class RedirectHandlerTest < Test::Unit::TestCase def setup + @port = process_based_port redirect_test_io do - @server = Mongrel::HttpServer.new('127.0.0.1', 9998) + @server = Mongrel::HttpServer.new('127.0.0.1', @port) end @server.run - @client = Net::HTTP.new('127.0.0.1', 9998) + @client = Net::HTTP.new('127.0.0.1', @port) end def teardown diff --git a/test/unit/test_request_progress.rb b/test/unit/test_request_progress.rb index da9374e..a100426 100644 --- a/test/unit/test_request_progress.rb +++ b/test/unit/test_request_progress.rb @@ -38,8 +38,9 @@ end class RequestProgressTest < Test::Unit::TestCase def setup + @port = process_based_port redirect_test_io do - @server = Mongrel::HttpServer.new("127.0.0.1", 9998) + @server = Mongrel::HttpServer.new("127.0.0.1", @port) end @handler = UploadBeginHandler.new @server.register("/upload", @handler) @@ -51,7 +52,7 @@ class RequestProgressTest < Test::Unit::TestCase end def test_begin_end_progress - Net::HTTP.get("localhost", "/upload", 9998) + Net::HTTP.get("localhost", "/upload", @port) assert @handler.request_began assert @handler.request_progressed assert @handler.request_processed @@ -62,7 +63,7 @@ class RequestProgressTest < Test::Unit::TestCase handlers.each { |h| h.reset } # make the call - Net::HTTP.get("localhost", "/upload", 9998) + Net::HTTP.get("localhost", "/upload", @port) # assert that each one was fired handlers.each { |h| @@ -88,7 +89,7 @@ class RequestProgressTest < Test::Unit::TestCase # remove handlers to make sure they've all gone away @server.unregister("/upload") handlers.each { |h| h.reset } - Net::HTTP.get("localhost", "/upload", 9998) + Net::HTTP.get("localhost", "/upload", @port) handlers.each { |h| assert !h.request_began && !h.request_progressed && !h.request_processed } diff --git a/test/unit/test_ws.rb b/test/unit/test_ws.rb index 68a79a8..9de8a45 100644 --- a/test/unit/test_ws.rb +++ b/test/unit/test_ws.rb @@ -22,10 +22,11 @@ class WebServerTest < Test::Unit::TestCase def setup @valid_request = "GET / HTTP/1.1\r\nHost: www.zedshaw.com\r\nContent-Type: text/plain\r\n\r\n" + @port = process_based_port redirect_test_io do # We set num_processors=1 so that we can test the reaping code - @server = HttpServer.new("127.0.0.1", 9998, num_processors=1) + @server = HttpServer.new("127.0.0.1", @port, num_processors=1) end @tester = TestHandler.new @@ -42,14 +43,14 @@ class WebServerTest < Test::Unit::TestCase end def test_simple_server - hit(['http://localhost:9998/test']) + hit(["http://localhost:#{@port}/test"]) assert @tester.ran_test, "Handler didn't really run" end def do_test(string, chunk, close_after=nil, shutdown_delay=0) # Do not use instance variables here, because it needs to be thread safe - socket = TCPSocket.new("127.0.0.1", 9998); + socket = TCPSocket.new("127.0.0.1", @port); request = StringIO.new(string) chunks_out = 0 -- cgit v1.2.3-24-ge0c7 From 9ed23d6b1be6f24a5ac43ff77db20ac77dbf176d Mon Sep 17 00:00:00 2001 From: luislavena Date: Mon, 31 Mar 2008 08:19:14 +0000 Subject: Somehow the RUBY_PLATFORM regexp got lost between branches... great! Added shebang to mongrel_rails (makes latest RubyGem happier). git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-2@1000 19e92222-5c0b-0410-8929-a290d50e31e9 --- bin/mongrel_rails | 4 +++- lib/mongrel/configurator.rb | 6 +++--- lib/mongrel/rails.rb | 2 +- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/bin/mongrel_rails b/bin/mongrel_rails index c32b818..5d17466 100644 --- a/bin/mongrel_rails +++ b/bin/mongrel_rails @@ -1,3 +1,5 @@ +#!/usr/bin/env ruby +# # Copyright (c) 2005 Zed A. Shaw # You can redistribute it and/or modify it under the same terms as Ruby. # @@ -137,7 +139,7 @@ module Mongrel config.join if config.needs_restart - if RUBY_PLATFORM !~ /mswin/ + if RUBY_PLATFORM !~ /djgpp|(cyg|ms|bcc)win|mingw/ cmd = "ruby #{__FILE__} start #{original_args.join(' ')}" config.log "Restarting with arguments: #{cmd}" config.stop(false, true) diff --git a/lib/mongrel/configurator.rb b/lib/mongrel/configurator.rb index bbb88ba..439b44c 100644 --- a/lib/mongrel/configurator.rb +++ b/lib/mongrel/configurator.rb @@ -81,7 +81,7 @@ module Mongrel # Writes the PID file if we're not on Windows. def write_pid_file - if RUBY_PLATFORM !~ /mswin/ + if RUBY_PLATFORM !~ /djgpp|(cyg|ms|bcc)win|mingw/ log "Writing PID file to #{@pid_file}" open(@pid_file,"w") {|f| f.write(Process.pid) } open(@pid_file,"w") do |f| @@ -185,7 +185,7 @@ module Mongrel def daemonize(options={}) ops = resolve_defaults(options) # save this for later since daemonize will hose it - if RUBY_PLATFORM !~ /mswin/ + if RUBY_PLATFORM !~ /djgpp|(cyg|ms|bcc)win|mingw/ require 'daemons/daemonize' logfile = ops[:log_file] @@ -366,7 +366,7 @@ module Mongrel # clean up the pid file always at_exit { remove_pid_file } - if RUBY_PLATFORM !~ /mswin/ + if RUBY_PLATFORM !~ /djgpp|(cyg|ms|bcc)win|mingw/ # graceful shutdown trap("TERM") { log "TERM signal received."; stop } trap("USR1") { log "USR1 received, toggling $mongrel_debug_client to #{!$mongrel_debug_client}"; $mongrel_debug_client = !$mongrel_debug_client } diff --git a/lib/mongrel/rails.rb b/lib/mongrel/rails.rb index 853ae4e..7f66a5e 100644 --- a/lib/mongrel/rails.rb +++ b/lib/mongrel/rails.rb @@ -173,7 +173,7 @@ module Mongrel ops = resolve_defaults(options) setup_signals(options) - if RUBY_PLATFORM !~ /mswin/ + if RUBY_PLATFORM !~ /djgpp|(cyg|ms|bcc)win|mingw/ # rails reload trap("HUP") { log "HUP signal received."; reload! } -- cgit v1.2.3-24-ge0c7 From 74edc38c9d3702a6fafbb67e190564b7f1422a28 Mon Sep 17 00:00:00 2001 From: luislavena Date: Mon, 31 Mar 2008 08:19:17 +0000 Subject: A bunch of corrections to the Rakefiles and the Manifest. Almost nirvana for CI. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-2@1001 19e92222-5c0b-0410-8929-a290d50e31e9 --- Manifest | 3 +-- Rakefile | 51 ++++++++++++++++++++------------------- projects/fastthread/Rakefile | 11 ++++++--- projects/gem_plugin/Rakefile | 7 ++++-- projects/mongrel_service/Rakefile | 10 +++++--- 5 files changed, 46 insertions(+), 36 deletions(-) diff --git a/Manifest b/Manifest index 2896ec6..9819ba8 100644 --- a/Manifest +++ b/Manifest @@ -44,7 +44,6 @@ lib/mongrel/stats.rb lib/mongrel/tcphack.rb lib/mongrel/uri_classifier.rb lib/mongrel.rb -lib/mongrel.rb.rej LICENSE Manifest mongrel-public_cert.pem @@ -63,7 +62,7 @@ test/unit/test_conditional.rb test/unit/test_configurator.rb test/unit/test_debug.rb test/unit/test_handlers.rb -test/unit/test_http11.rb +test/unit/test_http_parser.rb test/unit/test_redirect_handler.rb test/unit/test_request_progress.rb test/unit/test_response.rb diff --git a/Rakefile b/Rakefile index 9ea061c..fbe8801 100644 --- a/Rakefile +++ b/Rakefile @@ -1,11 +1,12 @@ require 'rubygems' -gem 'echoe', '>=2.7.5' +gem 'echoe', '>=2.7.11' require 'echoe' e = Echoe.new("mongrel") do |p| p.summary = "A small fast HTTP library and server that runs Rails, Camping, Nitro and Iowa apps." - p.author ="Zed A. Shaw" + p.author = "Zed A. Shaw" + p.email = "mongrel-development@rubyforge.org" p.clean_pattern = ['ext/http11/*.{bundle,so,o,obj,pdb,lib,def,exp}', 'lib/*.{bundle,so,o,obj,pdb,lib,def,exp}', 'ext/http11/Makefile', 'pkg', 'lib/*.bundle', '*.gem', 'site/output', '.config', 'lib/http11.jar', 'ext/http11_java/classes', 'coverage', 'test_*.log', 'log', 'doc'] p.url = "http://mongrel.rubyforge.org" p.rdoc_pattern = ['README', 'LICENSE', 'CONTRIBUTORS', 'CHANGELOG', 'COPYING', 'lib/**/*.rb', 'doc/**/*.rdoc'] @@ -15,28 +16,27 @@ e = Echoe.new("mongrel") do |p| p.dependencies = ['gem_plugin >=0.2.3'] p.extension_pattern = nil - p.certificate_chain = case ENV['USER'] + p.certificate_chain = case (ENV['USER'] || ENV['USERNAME']).downcase when 'eweaver' ['~/p/configuration/gem_certificates/mongrel/mongrel-public_cert.pem', '~/p/configuration/gem_certificates/evan_weaver-mongrel-public_cert.pem'] - when 'luislavena' - ['~/gem_certificates/mongrel-public_cert.pem', - '~/gem_certificates/luislavena-mongrel-public_cert.pem'] + when 'luislavena', 'luis' + ['~/projects/gem_certificates/mongrel-public_cert.pem', + '~/projects/gem_certificates/luislavena-mongrel-public_cert.pem'] end p.need_tar_gz = false p.need_tgz = true - if RUBY_PLATFORM !~ /mswin|java/ + unless Platform.windows? or Platform.java? p.extension_pattern = ["ext/**/extconf.rb"] end p.eval = proc do - case RUBY_PLATFORM - when /mswin/ + if Platform.windows? self.files += ['lib/http11.so'] self.platform = Gem::Platform::CURRENT - when /java/ + elsif Platform.java? self.files += ['lib/http11.jar'] self.platform = 'jruby' # XXX Is this right? else @@ -82,19 +82,18 @@ def java_classpath_arg classpath ? "-cp #{classpath}" : "" end -case RUBY_PLATFORM -when /mswin/ +if Platform.windows? filename = "lib/http11.so" file filename do Dir.chdir("ext/http11") do ruby "extconf.rb" - system(PLATFORM =~ /mswin/ ? 'nmake' : 'make') + system(Platform.make) end move_extensions end task :compile => [filename] -when /java/ +elsif Platform.java? # Avoid JRuby in-process launching problem begin @@ -121,13 +120,17 @@ end def sub_project(project, *targets) targets.each do |target| Dir.chdir "projects/#{project}" do - unless RUBY_PLATFORM =~ /mswin/ - sh("rake #{target.to_s}") # --trace - end + sh("#{Platform.rake} #{target.to_s}") # --trace end end end +desc "Compile all the projects" +task :compile_all => [:compile] do + sub_project("fastthread", :compile) + sub_project("mongrel_service", :compile) +end + desc "Package Mongrel and all subprojects" task :package_all => [:package] do sub_project("gem_plugin", :package) @@ -139,11 +142,9 @@ task :package_all => [:package] do sub_project("mongrel_cluster", :package) sub_project("mongrel_experimental", :package) - sh("rake java package") unless RUBY_PLATFORM =~ /java/ + sh("rake java package") unless Platform.windows? - # XXX Broken by RubyGems 0.9.5 - # sub_project("mongrel_service", :package) if RUBY_PLATFORM =~ /mswin/ - # sh("rake mswin package") unless RUBY_PLATFORM =~ /mswin/ + sub_project("mongrel_service", :package) if Platform.windows? end task :install_requirements do @@ -161,7 +162,7 @@ task :install => [:install_requirements] do sub_project("mongrel_console", :install) sub_project("mongrel_cluster", :install) # sub_project("mongrel_experimental", :install) - sub_project("mongrel_service", :install) if RUBY_PLATFORM =~ /mswin/ + sub_project("mongrel_service", :install) if Platform.windows? end desc "for Mongrel and all its subprojects" @@ -173,11 +174,11 @@ task :uninstall => [:clean] do sub_project("gem_plugin", :uninstall) sub_project("fastthread", :uninstall) # sub_project("mongrel_experimental", :uninstall) - sub_project("mongrel_service", :uninstall) if RUBY_PLATFORM =~ /mswin/ + sub_project("mongrel_service", :uninstall) if Platform.windows? end desc "for Mongrel and all its subprojects" -task :clean do +task :clean_all => [:clean] do sub_project("gem_plugin", :clean) sub_project("cgi_multipart_eof_fix", :clean) sub_project("fastthread", :clean) @@ -186,7 +187,7 @@ task :clean do sub_project("mongrel_console", :clean) sub_project("mongrel_cluster", :clean) sub_project("mongrel_experimental", :clean) - sub_project("mongrel_service", :clean) if RUBY_PLATFORM =~ /mswin/ + sub_project("mongrel_service", :clean) if Platform.windows? end #### Site upload tasks diff --git a/projects/fastthread/Rakefile b/projects/fastthread/Rakefile index aadf9f8..e418a5a 100644 --- a/projects/fastthread/Rakefile +++ b/projects/fastthread/Rakefile @@ -1,9 +1,12 @@ +require 'rubygems' +gem 'echoe', '>=2.7.11' require 'echoe' Echoe.new("fastthread") do |p| p.project = "mongrel" p.author = "MenTaLguY " + p.email = "mental@rydia.net" p.summary = "Optimized replacement for thread.rb primitives" p.extensions = "ext/fastthread/extconf.rb" p.clean_pattern = ['build/*', '**/*.o', '**/*.so', '**/*.a', 'lib/*-*', '**/*.log', "ext/fastthread/*.{bundle,so,obj,pdb,lib,def,exp}", "ext/fastthread/Makefile", "pkg", "lib/*.bundle", "*.gem", ".config"] @@ -14,10 +17,10 @@ Echoe.new("fastthread") do |p| '/Users/eweaver/p/configuration/gem_certificates/evan_weaver-mongrel-public_cert.pem'] p.require_signed = true - p.eval = proc do - if RUBY_PLATFORM.match("win32") - platform = Gem::Platform::WIN32 - files += ['lib/fastthread.so'] + p.eval = proc do + if Platform.windows? + self.platform = Gem::Platform::CURRENT + self.files += ['lib/fastthread.so'] task :package => [:clean, :compile] end end diff --git a/projects/gem_plugin/Rakefile b/projects/gem_plugin/Rakefile index f1bd428..b312bfe 100644 --- a/projects/gem_plugin/Rakefile +++ b/projects/gem_plugin/Rakefile @@ -1,8 +1,11 @@ +require 'rubygems' +gem 'echoe', '>=2.7.11' require 'echoe' Echoe.new("gem_plugin") do |p| - p.author="Zed A. Shaw" + p.author= "Zed A. Shaw" + p.email = "mongrel-development@rubyforge.org" p.project = "mongrel" p.summary = "A plugin system based on rubygems that uses dependencies only" @@ -15,7 +18,7 @@ Echoe.new("gem_plugin") do |p| p.test_pattern = "test/test_plugins.rb" p.clean_pattern += ["pkg", "lib/*.bundle", "*.gem", ".config"] p.rdoc_pattern = ['README', 'LICENSE', 'COPYING', 'lib/**/*.rb', 'doc/**/*.rdoc'] - p.rdoc_template = `allison --path`.chomp + p.rdoc_template = `#{Platform.windows? ? 'allison.bat' : 'allison'} --path`.chomp end namespace :site do diff --git a/projects/mongrel_service/Rakefile b/projects/mongrel_service/Rakefile index f9c74a3..1d04826 100644 --- a/projects/mongrel_service/Rakefile +++ b/projects/mongrel_service/Rakefile @@ -1,3 +1,6 @@ + +require 'rubygems' +gem 'echoe', '>=2.7.11' require 'echoe' require 'tools/freebasic' @@ -10,15 +13,16 @@ echoe_spec = Echoe.new("mongrel_service") do |p| p.summary += " (debug build)" unless ENV['RELEASE'] p.description = "This plugin offer native win32 services for rails, powered by Mongrel." p.author = "Luis Lavena" - p.platform = Gem::Platform::WIN32 + p.email = "luislavena@gmail.com" + p.platform = Gem::Platform::CURRENT p.dependencies = ['gem_plugin >=0.2.3', 'mongrel >=1.0.2', 'win32-service >=0.5.0'] p.executable_pattern = "" p.need_tar_gz = false p.need_zip = true - p.certificate_chain = ['~/gem_certificates/mongrel-public_cert.pem', - '~/gem_certificates/luislavena-mongrel-public_cert.pem'] + p.certificate_chain = ['~/projects/gem_certificates/mongrel-public_cert.pem', + '~/projects/gem_certificates/luislavena-mongrel-public_cert.pem'] p.require_signed = true end -- cgit v1.2.3-24-ge0c7 From 34d44f3b9cc76974315ca3e5e1800c4771bb7729 Mon Sep 17 00:00:00 2001 From: luislavena Date: Sun, 6 Apr 2008 00:14:45 +0000 Subject: GemPlugin was looking for 'init.rb' on every gem, that's nasty. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-2@1002 19e92222-5c0b-0410-8929-a290d50e31e9 --- projects/gem_plugin/lib/gem_plugin.rb | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/projects/gem_plugin/lib/gem_plugin.rb b/projects/gem_plugin/lib/gem_plugin.rb index 4664aa1..782a990 100644 --- a/projects/gem_plugin/lib/gem_plugin.rb +++ b/projects/gem_plugin/lib/gem_plugin.rb @@ -131,11 +131,14 @@ module GemPlugin gem_dir = "" Gem.path.each do |gem_path| gem_dir = File.join(gem_path, "gems", path) - break if File.exists?(gem_dir) + break if File.exist?(gem_dir) end - require File.join(gem_dir, "lib", gem.name, "init.rb") - @gems[gem.name] = gem_dir + gem_init = File.join(gem_dir, "lib", gem.name, "init.rb") + if File.exist?(gem_init) + require gem_init + @gems[gem.name] = gem_dir + end end end -- cgit v1.2.3-24-ge0c7 From 3129a8ad22810744d426151d56591d933240094f Mon Sep 17 00:00:00 2001 From: evanweaver Date: Thu, 17 Apr 2008 04:29:44 +0000 Subject: Apply r1003 to stable. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-2@1004 19e92222-5c0b-0410-8929-a290d50e31e9 --- bin/mongrel_rails | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/bin/mongrel_rails b/bin/mongrel_rails index 5d17466..151a19c 100644 --- a/bin/mongrel_rails +++ b/bin/mongrel_rails @@ -92,6 +92,7 @@ module Mongrel end daemonize + write_pid_file log "Daemonized, any open files are closed. Look at #{defaults[:pid_file]} and #{defaults[:log_file]} for info." log "Settings loaded from #{@config_file} (they override command line)." if @config_file end @@ -130,9 +131,7 @@ module Mongrel config.run config.log "Mongrel #{Mongrel::Const::MONGREL_VERSION} available at #{@address}:#{@port}" - if config.defaults[:daemon] - config.write_pid_file - else + unless config.defaults[:daemon] config.log "Use CTRL-C to stop." end -- cgit v1.2.3-24-ge0c7 From 375b8b742a2745c821d2bd14fc288f4373ee8c76 Mon Sep 17 00:00:00 2001 From: evanweaver Date: Thu, 17 Apr 2008 04:32:11 +0000 Subject: Document issue with soft restart pid file setting (closes #29). git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-2@1005 19e92222-5c0b-0410-8929-a290d50e31e9 --- bin/mongrel_rails | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/mongrel_rails b/bin/mongrel_rails index 151a19c..ba601c5 100644 --- a/bin/mongrel_rails +++ b/bin/mongrel_rails @@ -215,7 +215,7 @@ module Mongrel ['-c', '--chdir PATH', "Change to dir before starting (will be expanded).", :@cwd, "."], ['-f', '--force', "Force the shutdown (kill -9).", :@force, false], ['-w', '--wait SECONDS', "Wait SECONDS before forcing shutdown", :@wait, "0"], - ['-P', '--pid FILE', "Where the PID file is located.", :@pid_file, "log/mongrel.pid"] + ['-P', '--pid FILE', "Where the PID file is located (cannot be changed via soft restart).", :@pid_file, "log/mongrel.pid"] ] end -- cgit v1.2.3-24-ge0c7 From 201f1e72325a0513c7f56d20b7d5163164d5c2cd Mon Sep 17 00:00:00 2001 From: luislavena Date: Thu, 17 Apr 2008 18:59:55 +0000 Subject: mongrel_service: updated ServiceFB library (pistoned). git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-2@1006 19e92222-5c0b-0410-8929-a290d50e31e9 --- .../mongrel_service/lib/ServiceFB/ServiceFB_Utils.bas | 17 +++++++++++++++-- .../mongrel_service/lib/ServiceFB/_utils_internals.bi | 2 ++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/projects/mongrel_service/lib/ServiceFB/ServiceFB_Utils.bas b/projects/mongrel_service/lib/ServiceFB/ServiceFB_Utils.bas index c5150ea..c8a77a3 100644 --- a/projects/mongrel_service/lib/ServiceFB/ServiceFB_Utils.bas +++ b/projects/mongrel_service/lib/ServiceFB/ServiceFB_Utils.bas @@ -15,6 +15,8 @@ namespace svc namespace utils '# fb.svc.utils '# private (internals) for ServiceProcess.Console() dim shared _svc_stop_signal as any ptr + dim shared _svc_stop_mutex as any ptr + dim shared _svc_stopped as BOOL dim shared _svc_in_console as ServiceProcess ptr dim shared _svc_in_console_stop_flag as BOOL @@ -168,6 +170,7 @@ namespace utils '# fb.svc.utils '# create the signal used to stop the service thread. _svc_stop_signal = condcreate() + _svc_stop_mutex = mutexcreate() '# register the Console Handler SetConsoleCtrlHandler(@_console_handler, TRUE) @@ -189,6 +192,9 @@ namespace utils '# fb.svc.utils if not (service->onStart = 0) then '# create the thread working_thread = threadcreate(@ServiceProcess.call_onStart, service) + if (working_thread = 0) then + print "Failed to create working thread." + end if end if print "Service is in running state." @@ -197,7 +203,11 @@ namespace utils '# fb.svc.utils '# now that onStart is running, must monitor the stop_signal '# in case it arrives, the service state must change to exit the '# working thread. - condwait(_svc_stop_signal) + mutexlock(_svc_stop_mutex) + do while (_svc_stopped = FALSE) + condwait(_svc_stop_signal, _svc_stop_mutex) + loop + mutexunlock(_svc_stop_mutex) print "Stop signal received, stopping..." @@ -222,7 +232,7 @@ namespace utils '# fb.svc.utils '# now that service was stopped, destroy the references. conddestroy(_svc_stop_signal) - + mutexdestroy(_svc_stop_mutex) print "Done." end if else @@ -287,9 +297,12 @@ namespace utils '# fb.svc.utils '# now fire the signal _dprint("fire stop signal") + mutexlock(_svc_stop_mutex) condsignal(_svc_stop_signal) result = TRUE _svc_in_console_stop_flag = FALSE + _svc_stopped = TRUE + mutexunlock(_svc_stop_mutex) case else: _dprint("unsupported CTRL EVENT") diff --git a/projects/mongrel_service/lib/ServiceFB/_utils_internals.bi b/projects/mongrel_service/lib/ServiceFB/_utils_internals.bi index 67acc87..fab00f0 100644 --- a/projects/mongrel_service/lib/ServiceFB/_utils_internals.bi +++ b/projects/mongrel_service/lib/ServiceFB/_utils_internals.bi @@ -42,6 +42,8 @@ namespace utils '# fb.svc.utils '# will raise in case Ctrl+C / Ctrl+Break or other events are '# received. extern _svc_stop_signal as any ptr + extern _svc_stop_mutex as any ptr + extern _svc_stopped as BOOL extern _svc_in_console as ServiceProcess ptr extern _svc_in_console_stop_flag as BOOL end namespace '# fb.svc.utils -- cgit v1.2.3-24-ge0c7 From af50f84c5533e89760820ff90a3b6acccd2c50ae Mon Sep 17 00:00:00 2001 From: luislavena Date: Thu, 17 Apr 2008 23:20:50 +0000 Subject: mongrel_service: Merged changes from trunk. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-2@1007 19e92222-5c0b-0410-8929-a290d50e31e9 --- projects/mongrel_service/CHANGELOG | 10 ++++++++-- projects/mongrel_service/Rakefile | 10 +++++++--- projects/mongrel_service/lib/mongrel_service/init.rb | 14 +++++++++++++- 3 files changed, 28 insertions(+), 6 deletions(-) diff --git a/projects/mongrel_service/CHANGELOG b/projects/mongrel_service/CHANGELOG index d8ca92e..67f5086 100644 --- a/projects/mongrel_service/CHANGELOG +++ b/projects/mongrel_service/CHANGELOG @@ -1,6 +1,12 @@ -* SVN * - +* 0.3.4 * + + * Strict Gem dependencies for mongrel_service. This version is compatible + only with mongrel 1.0.x, 1.1.x and with win32-service 0.5.x. + + * Fixed issues realted to Win32::Service and gem_plugin being registered with + different names due win32-service changes. + * 0.3.3 * * Properly display package/gem version for mongrel_service. Closes #13823. diff --git a/projects/mongrel_service/Rakefile b/projects/mongrel_service/Rakefile index 1d04826..9fb0ae9 100644 --- a/projects/mongrel_service/Rakefile +++ b/projects/mongrel_service/Rakefile @@ -15,14 +15,18 @@ echoe_spec = Echoe.new("mongrel_service") do |p| p.author = "Luis Lavena" p.email = "luislavena@gmail.com" p.platform = Gem::Platform::CURRENT - p.dependencies = ['gem_plugin >=0.2.3', 'mongrel >=1.0.2', 'win32-service >=0.5.0'] + p.dependencies = [['gem_plugin', '>=0.2.3', '<0.3.0'], + ['mongrel', '>=1.0.2', '<1.2.0'], + ['win32-service', '>=0.5.2', '<0.6.0']] p.executable_pattern = "" p.need_tar_gz = false p.need_zip = true - p.certificate_chain = ['~/projects/gem_certificates/mongrel-public_cert.pem', - '~/projects/gem_certificates/luislavena-mongrel-public_cert.pem'] + p.certificate_chain = [ + '~/projects/gem_certificates/mongrel-public_cert.pem', + '~/projects/gem_certificates/luislavena-mongrel-public_cert.pem' + ] p.require_signed = true end diff --git a/projects/mongrel_service/lib/mongrel_service/init.rb b/projects/mongrel_service/lib/mongrel_service/init.rb index c6fea0e..f1475f0 100644 --- a/projects/mongrel_service/lib/mongrel_service/init.rb +++ b/projects/mongrel_service/lib/mongrel_service/init.rb @@ -2,7 +2,6 @@ require 'gem_plugin' require 'mongrel' require 'mongrel/rails' require 'rbconfig' -require 'win32/service' require 'fileutils' module Service @@ -34,6 +33,10 @@ module Service # of the rails application we wanted to serve, because later "as service" no error # show to trace this. def validate + # TODO: investigate why Win32::Service interfere with gem_plugin + gem 'win32-service', '>= 0.5.2', '< 0.6.0' + require 'win32/service' + @cwd = File.expand_path(@cwd) valid_dir? @cwd, "Invalid path to change to: #@cwd" @@ -74,6 +77,9 @@ module Service end def run + gem 'win32-service', '>= 0.5.2', '< 0.6.0' + require 'win32/service' + # check if mongrel_service.exe is in ruby bindir. gem_root = File.join(File.dirname(__FILE__), "..", "..") gem_executable = File.join(gem_root, "bin/mongrel_service.exe") @@ -164,6 +170,9 @@ module Service def validate valid? @svc_name != nil, "A service name is mandatory." + + gem 'win32-service', '>= 0.5.2', '< 0.6.0' + require 'win32/service' # Validate that the service exists begin @@ -183,6 +192,9 @@ module Service include ServiceValidation def run + gem 'win32-service', '>= 0.5.2', '< 0.6.0' + require 'win32/service' + display_name = Win32::Service.getdisplayname(@svc_name) begin -- cgit v1.2.3-24-ge0c7 From 931818a14a959c9279154ce2edb50f44eecc4e25 Mon Sep 17 00:00:00 2001 From: luislavena Date: Fri, 18 Apr 2008 07:09:33 +0000 Subject: Updated FreeBASIC compilation tools. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-2@1008 19e92222-5c0b-0410-8929-a290d50e31e9 --- projects/mongrel_service/tools/freebasic.rb | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/projects/mongrel_service/tools/freebasic.rb b/projects/mongrel_service/tools/freebasic.rb index 8902059..0b3e445 100644 --- a/projects/mongrel_service/tools/freebasic.rb +++ b/projects/mongrel_service/tools/freebasic.rb @@ -63,7 +63,7 @@ module FreeBASIC @libraries_path = [] @options = {} - instance_eval &block + instance_eval(&block) if block_given? do_cleanup @@ -90,7 +90,7 @@ module FreeBASIC # as output_name for the project def lib(lib_name) @type = :lib - @output_name = lib_name + @output_name = "#{lib_name}" @real_file_name = "lib#{lib_name}.a" end @@ -197,7 +197,9 @@ module FreeBASIC # return the compiled name version of the passed source file (src) # compiled_form("test.bas") => "test.o" def compiled_form(src) - src.ext({ ".bas" => "o", ".rc" => "obj" }[File.extname(src)]) + unless src.nil? + src.ext({ ".bas" => "o", ".rc" => "obj" }[File.extname(src)]) + end end def compiled_project_file @@ -207,11 +209,11 @@ module FreeBASIC def fbc_compile(source, target, main = nil) cmdline = [] cmdline << "fbc" + cmdline << "-w pedantic" if (@options.has_key?(:pedantic) && @options[:pedantic] == true) cmdline << "-g" if (@options.has_key?(:debug) && @options[:debug] == true) cmdline << "-#{@options[:errorchecking].to_s}" if @options.has_key?(:errorchecking) - cmdline << "-profile" if (@options.has_key?(:profile) && @options[:profile] == true) cmdline << "-mt" if (@options.has_key?(:mt) && @options[:mt] == true) - cmdline << "-w pedantic" if (@options.has_key?(:pedantic) && @options[:pedantic] == true) + cmdline << "-profile" if (@options.has_key?(:profile) && @options[:profile] == true) cmdline << "-c #{source}" cmdline << "-o #{target}" cmdline << "-m #{main}" unless main.nil? @@ -224,8 +226,8 @@ module FreeBASIC cmdline = [] cmdline << "fbc" cmdline << "-g" if (@options.has_key?(:debug) && @options[:debug] == true) - cmdline << "-profile" if (@options.has_key?(:profile) && @options[:profile] == true) cmdline << "-mt" if (@options.has_key?(:mt) && @options[:mt] == true) + cmdline << "-profile" if (@options.has_key?(:profile) && @options[:profile] == true) cmdline << "-#{@type.to_s}" unless @type == :executable cmdline << "-x #{target}" cmdline << files << extra_files @@ -241,11 +243,15 @@ module FreeBASIC desc "Remove all compiled files for #{@name}" task :clobber do # remove compiled and linked file - rm compiled_project_file rescue nil #unless @type == :lib - rm File.join(@build_path, @complement_file) rescue nil if @type == :dylib + rm compiled_project_file rescue nil if File.exist?(compiled_project_file) + if @type == :dylib + rm File.join(@build_path, @complement_file) rescue nil if File.exist?(File.join(@build_path, @complement_file)) + end # remove main file - rm compiled_form(@main_file) rescue nil + unless @main_file.nil? || !File.exists?(compiled_form(@main_file)) + rm compiled_form(@main_file) rescue nil + end # now the sources files # avoid attempt to remove the file two times (this is a bug in Rake) @@ -255,7 +261,7 @@ module FreeBASIC target = compiled_form(src) unless CLOBBER.include?(target) CLOBBER.include(target) - rm target rescue nil + rm target rescue nil if File.exist?(target) end end end -- cgit v1.2.3-24-ge0c7 From 043f49fbeaa9b347b9d7c500334f05a84dd11c51 Mon Sep 17 00:00:00 2001 From: luislavena Date: Fri, 18 Apr 2008 07:09:36 +0000 Subject: Ported ConsoleProcess tests from RubyServices. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-2@1009 19e92222-5c0b-0410-8929-a290d50e31e9 --- projects/mongrel_service/tests/all_tests.bas | 18 + .../tests/fixtures/mock_process.bas | 56 ++++ .../mongrel_service/tests/test_console_process.bas | 373 +++++++++++++++++++++ projects/mongrel_service/tests/test_helpers.bas | 37 ++ projects/mongrel_service/tests/test_helpers.bi | 8 + 5 files changed, 492 insertions(+) create mode 100644 projects/mongrel_service/tests/all_tests.bas create mode 100644 projects/mongrel_service/tests/fixtures/mock_process.bas create mode 100644 projects/mongrel_service/tests/test_console_process.bas create mode 100644 projects/mongrel_service/tests/test_helpers.bas create mode 100644 projects/mongrel_service/tests/test_helpers.bi diff --git a/projects/mongrel_service/tests/all_tests.bas b/projects/mongrel_service/tests/all_tests.bas new file mode 100644 index 0000000..0a8864f --- /dev/null +++ b/projects/mongrel_service/tests/all_tests.bas @@ -0,0 +1,18 @@ +'#-- +'# Copyright (c) 2006-2007 Luis Lavena, Multimedia systems +'# +'# This source code is released under the MIT License. +'# See MIT-LICENSE file for details +'#++ + +#include once "testly.bi" + +'# the code in this module runs after all +'# the other modules have "registered" their suites. + +'# evaluate the result from run_tests() to +'# return a error to the OS or not. +if (run_tests() = false) then + end 1 +end if + diff --git a/projects/mongrel_service/tests/fixtures/mock_process.bas b/projects/mongrel_service/tests/fixtures/mock_process.bas new file mode 100644 index 0000000..833967c --- /dev/null +++ b/projects/mongrel_service/tests/fixtures/mock_process.bas @@ -0,0 +1,56 @@ +'#-- +'# Copyright (c) 2006-2007 Luis Lavena, Multimedia systems +'# +'# This source code is released under the MIT License. +'# See MIT-LICENSE file for details +'#++ + +'# this program mock a common process that will: +'# output some text to stdout +'# output some error messages to stderr +'# will wait until Ctrl-C is hit (only if commandline contains "wait") +'# or drop an error if commandline contains "error" + +#include once "crt.bi" +#include once "windows.bi" + +dim shared stop_hit as BOOL + +function _console_handler(byval dwCtrlType as DWORD) as BOOL + dim result as BOOL + + if (dwCtrlType = CTRL_C_EVENT) then + '# slow response, take 10 seconds... + fprintf(stdout, !"out: slow stop\r\n") + sleep (10*1000) + result = 1 + stop_hit = TRUE + end if + + return result +end function + +sub main() + fprintf(stdout, !"out: message\r\n") + fprintf(stderr, !"err: error\r\n") + + select case lcase(command(1)) + case "wait": + sleep + + case "error": + '# terminate with error code + end 1 + + case "slow": + stop_hit = FALSE + SetConsoleCtrlHandler(@_console_handler, 1) + do while (stop_hit = FALSE) + sleep 15 + loop + SetConsoleCtrlHandler(@_console_handler, 0) + end 10 + end select +end sub + +main() diff --git a/projects/mongrel_service/tests/test_console_process.bas b/projects/mongrel_service/tests/test_console_process.bas new file mode 100644 index 0000000..02cb5f9 --- /dev/null +++ b/projects/mongrel_service/tests/test_console_process.bas @@ -0,0 +1,373 @@ +'#-- +'# Copyright (c) 2006-2007 Luis Lavena, Multimedia systems +'# +'# This source code is released under the MIT License. +'# See MIT-LICENSE file for details +'#++ + +#include once "console_process.bi" +#include once "file.bi" +#include once "testly.bi" +#include once "test_helpers.bi" + +namespace Suite_Test_Console_Process + '# test helpers + declare function process_cleanup() as boolean + + dim shared child as ConsoleProcess ptr + + sub before_all() + kill("out.log") + kill("err.log") + kill("both.log") + kill("both_slow.log") + kill("both_forced.log") + end sub + + sub after_each() + process_cleanup() + end sub + + sub test_process_create() + child = new ConsoleProcess() + assert_not_equal_error(0, child) + assert_equal("", child->filename) + assert_equal("", child->arguments) + assert_false(child->running) + delete child + end sub + + sub test_process_create_args() + child = new ConsoleProcess("mock_process.exe", "some params") + assert_equal("mock_process.exe", child->filename) + assert_equal("some params", child->arguments) + delete child + end sub + + sub test_properly_quoted_filename() + child = new ConsoleProcess("C:\path with spaces\my_executable.exe", "some params") + assert_not_equal(0, instr(child->filename, !"\"")) + delete child + end sub + + sub test_failed_unexistant_process() + child = new ConsoleProcess("no_valid_file.exe", "some params") + assert_false(child->start()) + assert_equal(0, child->pid) + assert_false(child->running) + delete child + end sub + + sub test_process_spawn_exit_code() + child = new ConsoleProcess("mock_process.exe", "error") + + '# start() should return true since it started, no matter if was terminated + '# improperly + assert_true(child->start()) + sleep 150 + + '# should not be running, but pid should be != than 0 + assert_not_equal(0, child->pid) + + '# we need to wait a bit prior asking for state + '# the process could be still running + assert_false(child->running) + + '# get exit code, should be 1 + assert_equal(1, child->exit_code) + + delete child + end sub + + sub test_redirected_output() + '# redirected output is used with logging files. + child = new ConsoleProcess("mock_process.exe") + + '# redirect stdout + assert_true(child->redirect(ProcessStdOut, "out.log")) + assert_string_equal("out.log", child->redirected_stdout) + + '# redirect stderr + assert_true(child->redirect(ProcessStdErr, "err.log")) + assert_string_equal("err.log", child->redirected_stderr) + + '# start() will be true since process terminated nicely + assert_true(child->start()) + sleep 150 + + '# running should be false + assert_false(child->running) + + '# exit_code should be 0 + assert_equal(0, child->exit_code) + + '# now out.log and err.log must exist and content must be valid. + assert_true(fileexists("out.log")) + assert_string_equal("out: message", content_of_file("out.log")) + + assert_true(fileexists("err.log")) + assert_string_equal("err: error", content_of_file("err.log")) + + '# cleanup + process_cleanup() + assert_equal_error(0, kill("out.log")) + assert_equal_error(0, kill("err.log")) + + assert_true_error(fileexists("err.log")) + + delete child + end sub + + sub test_redirected_merged_output() + dim content as string + + '# redirected output is used with logging files. + child = new ConsoleProcess("mock_process.exe") + + '# redirect both stdout and stderr + child->redirect(ProcessStdBoth, "both.log") + assert_equal("both.log", child->redirected_stdout) + assert_equal("both.log", child->redirected_stderr) + + '# start() will be true since process terminated nicely + assert_true(child->start()) + sleep 150 + + '# running should be false + assert_false(child->running) + + '# exit_code should be 0 + assert_equal(0, child->exit_code) + + '# file must exists + assert_true(fileexists("both.log")) + + '# contents must match + content = content_of_file("both.log") + + assert_not_equal(0, instr(content, "out: message")) + assert_not_equal(0, instr(content, "err: error")) + + '# cleanup + process_cleanup() + assert_equal_error(0, kill("both.log")) + + delete child + end sub + + sub test_redirected_output_append() + dim content as string + + child = new ConsoleProcess("mock_process.exe") + + '# redirect both stdout and stderr + child->redirect(ProcessStdBoth, "both.log") + + '# start() will be true since process terminated nicely + assert_true(child->start()) + sleep 150 + + content = content_of_file("both.log") + + '# start() again + assert_true(child->start()) + sleep 150 + + assert_not_equal(len(content), len(content_of_file("both.log"))) + + '# cleanup + process_cleanup() + assert_equal_error(0, kill("both.log")) + + delete child + end sub + + sub test_process_terminate() + dim content as string + + '# redirected output is used with logging files. + child = new ConsoleProcess("mock_process.exe", "wait") + child->redirect(ProcessStdBoth, "both.log") + + '# start + assert_true(child->start()) + sleep 150 + + '# validate if running + assert_true(child->running) + + '# validate PID + assert_not_equal(0, child->pid) + + '# now terminates it + assert_true(child->terminate()) + sleep 150 + + assert_equal(9, child->exit_code) + + '# it should be done + assert_false(child->running) + + '# validate output + '# file must exists + assert_true(fileexists("both.log")) + + '# contents must match + content = content_of_file("both.log") + + assert_not_equal(0, instr(content, "out: message")) + assert_not_equal(0, instr(content, "err: error")) + assert_not_equal(0, instr(content, "interrupted")) + + '# cleanup + process_cleanup() + assert_equal_error(0, kill("both.log")) + + delete child + end sub + + sub test_process_terminate_slow() + dim content as string + + '# redirected output is used with logging files. + child = new ConsoleProcess("mock_process.exe", "slow") + child->redirect(ProcessStdBoth, "both_slow.log") + + '# start + assert_true(child->start()) + sleep 150 + + '# validate if running + assert_true(child->running) + + '# validate PID + assert_not_equal(0, child->pid) + + '# now terminates it + assert_true(child->terminate()) + sleep 150 + + '# it should be done now + assert_false(child->running) + assert_equal(10, child->exit_code) + + '# validate output + '# file must exists + assert_true(fileexists("both_slow.log")) + + '# contents must match + content = content_of_file("both_slow.log") + + assert_not_equal(0, instr(content, "out: message")) + assert_not_equal(0, instr(content, "err: error")) + assert_not_equal(0, instr(content, "out: slow stop")) + assert_equal(0, instr(content, "interrupted")) + + '# cleanup + process_cleanup() + assert_equal_error(0, kill("both_slow.log")) + + delete child + end sub + + sub test_process_terminate_forced() + dim content as string + dim x as integer + + '# redirected output is used with logging files. + child = new ConsoleProcess("mock_process.exe", "wait") + child->redirect(ProcessStdBoth, "both_forced.log") + + '# start + assert_true(child->start()) + sleep 150 + + '# validate if running + assert_true(child->running) + + '# validate PID + assert_not_equal(0, child->pid) + + '# now terminates it + assert_true(child->terminate(true)) + sleep 150 + + '# it should be done + assert_false(child->running) + + '# look for termination code + assert_equal(0, child->exit_code) + + '# validate output + '# file must exists + assert_true(fileexists("both_forced.log")) + + '# contents must match + content = content_of_file("both_forced.log") + + assert_equal(0, instr(content, "out: message")) + assert_equal(0, instr(content, "err: error")) + assert_equal(0, instr(content, "interrupted")) + + '# cleanup + process_cleanup() + assert_equal_error(0, kill("both_forced.log")) + + delete child + end sub + + sub test_reuse_object_instance() + dim first_pid as uinteger + + child = new ConsoleProcess("mock_process.exe") + + '# start + assert_true(child->start()) + sleep 150 + + '# validate not running + assert_false(child->running) + + '# validate PID + assert_not_equal(0, child->pid) + + '# saves PID + first_pid = child->pid + + '# start it again + assert_true(child->start()) + sleep 150 + + '# it should have stopped by now + assert_false(child->running) + assert_not_equal(0, child->pid) + assert_not_equal(first_pid, child->pid) + + '# cleanup + process_cleanup() + + delete child + end sub + + private sub register() constructor + add_suite(Suite_Test_Console_Process) + add_test(test_process_create) + add_test(test_process_create_args) + add_test(test_properly_quoted_filename) + add_test(test_failed_unexistant_process) + add_test(test_process_spawn_exit_code) + add_test(test_redirected_output) + add_test(test_redirected_merged_output) + add_test(test_redirected_output_append) + add_test(test_process_terminate) + add_test(test_process_terminate_slow) + add_test(test_process_terminate_forced) + add_test(test_reuse_object_instance) + end sub + + '# test helpers below this point + private function process_cleanup() as boolean + shell "taskkill /f /im mock_process.exe 1>NUL 2>&1" + return true + end function +end namespace diff --git a/projects/mongrel_service/tests/test_helpers.bas b/projects/mongrel_service/tests/test_helpers.bas new file mode 100644 index 0000000..69b74cd --- /dev/null +++ b/projects/mongrel_service/tests/test_helpers.bas @@ -0,0 +1,37 @@ +'#-- +'# Copyright (c) 2006-2007 Luis Lavena, Multimedia systems +'# +'# This source code is released under the MIT License. +'# See MIT-LICENSE file for details +'#++ + +#include once "testly.bi" +#include once "test_helpers.bi" +#include once "file.bi" + +'# Global Helpers +function content_of_file(byref filename as string) as string + dim result as string + dim handle as integer + dim buffer as string + + result = "" + buffer = "" + + if (fileexists(filename) = true) then + handle = freefile + open filename for input as #handle + do while not (eof(handle)) + input #handle, buffer + result += buffer + buffer = "" + loop + close #handle + else + result = "" + end if + + return result +end function + +print content_of_file("testing.log") diff --git a/projects/mongrel_service/tests/test_helpers.bi b/projects/mongrel_service/tests/test_helpers.bi new file mode 100644 index 0000000..9397962 --- /dev/null +++ b/projects/mongrel_service/tests/test_helpers.bi @@ -0,0 +1,8 @@ +'#-- +'# Copyright (c) 2006-2007 Luis Lavena, Multimedia systems +'# +'# This source code is released under the MIT License. +'# See MIT-LICENSE file for details +'#++ + +declare function content_of_file(byref as string) as string \ No newline at end of file -- cgit v1.2.3-24-ge0c7 From 12cc38aaf337b2b0e0d518ec6d311e8d82db7d30 Mon Sep 17 00:00:00 2001 From: luislavena Date: Fri, 18 Apr 2008 07:09:38 +0000 Subject: Include tests projects and child process fixtures. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-2@1010 19e92222-5c0b-0410-8929-a290d50e31e9 --- projects/mongrel_service/Rakefile | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/projects/mongrel_service/Rakefile b/projects/mongrel_service/Rakefile index 9fb0ae9..efc9810 100644 --- a/projects/mongrel_service/Rakefile +++ b/projects/mongrel_service/Rakefile @@ -97,3 +97,42 @@ end #include_projects_of :native task :native_service => "native:build" task :clean => "native:clobber" + +project_task :mock_process do + executable :mock_process + build_to 'tests' + + main 'tests/fixtures/mock_process.bas' + + option OPTIONS +end + +task "all_tests:build" => "lib:build" +project_task :all_tests do + executable :all_tests + build_to 'tests' + + search_path 'src', 'lib', 'native' + lib_path 'lib' + + main 'tests/all_tests.bas' + + # this temporally fix the inverse namespace ctors of FB + source Dir.glob("tests/test_*.bas").reverse + + library 'testly' + + source 'native/console_process.bas' + + option OPTIONS +end + +desc "Run all the internal tests for the library" +task "all_tests:run" => ["mock_process:build", "all_tests:build"] do + Dir.chdir('tests') do + sh %{all_tests} + end +end + +desc "Run all the test for this project" +task :test => "all_tests:run" -- cgit v1.2.3-24-ge0c7 From 87e6494e924849fc22d0602187b650a0b7a11fc8 Mon Sep 17 00:00:00 2001 From: luislavena Date: Fri, 18 Apr 2008 07:09:41 +0000 Subject: Added emulation of slow termination processes. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-2@1011 19e92222-5c0b-0410-8929-a290d50e31e9 --- .../tests/fixtures/mock_process.bas | 76 ++++++++++++++++------ 1 file changed, 56 insertions(+), 20 deletions(-) diff --git a/projects/mongrel_service/tests/fixtures/mock_process.bas b/projects/mongrel_service/tests/fixtures/mock_process.bas index 833967c..e9405ab 100644 --- a/projects/mongrel_service/tests/fixtures/mock_process.bas +++ b/projects/mongrel_service/tests/fixtures/mock_process.bas @@ -14,43 +14,79 @@ #include once "crt.bi" #include once "windows.bi" -dim shared stop_hit as BOOL +dim shared as any ptr control_signal, control_mutex +dim shared flagged as byte +dim shared result as integer -function _console_handler(byval dwCtrlType as DWORD) as BOOL +function slow_console_handler(byval dwCtrlType as DWORD) as BOOL dim result as BOOL if (dwCtrlType = CTRL_C_EVENT) then - '# slow response, take 10 seconds... - fprintf(stdout, !"out: slow stop\r\n") - sleep (10*1000) + fprintf(stdout, !"out: CTRL-C received\r\n") + mutexlock(control_mutex) result = 1 - stop_hit = TRUE + flagged = 1 + condsignal(control_signal) + mutexunlock(control_mutex) + elseif (dwCtrlType = CTRL_BREAK_EVENT) then + fprintf(stdout, !"out: CTRL-BREAK received\r\n") + mutexlock(control_mutex) + result = 1 + flagged = 2 + condsignal(control_signal) + mutexunlock(control_mutex) end if return result end function -sub main() +sub wait_for(byval flag_level as integer) + flagged = 0 + '# set handler + if (SetConsoleCtrlHandler(@slow_console_handler, 1) = 0) then + fprintf(stderr, !"err: cannot set console handler\r\n") + end if + fprintf(stdout, !"out: waiting for keyboard signal\r\n") + mutexlock(control_mutex) + do until (flagged = flag_level) + condwait(control_signal, control_mutex) + loop + mutexunlock(control_mutex) + fprintf(stdout, !"out: got keyboard signal\r\n") + if (SetConsoleCtrlHandler(@slow_console_handler, 0) = 0) then + fprintf(stderr, !"err: cannot unset console handler\r\n") + end if +end sub + +function main() as integer fprintf(stdout, !"out: message\r\n") fprintf(stderr, !"err: error\r\n") select case lcase(command(1)) case "wait": sleep - + return 0 + case "error": '# terminate with error code - end 1 - - case "slow": - stop_hit = FALSE - SetConsoleCtrlHandler(@_console_handler, 1) - do while (stop_hit = FALSE) - sleep 15 - loop - SetConsoleCtrlHandler(@_console_handler, 0) - end 10 + return 1 + + case "slow1": + wait_for(1) + return 10 + + case "slow2": + wait_for(2) + return 20 end select -end sub +end function + +control_signal = condcreate() +control_mutex = mutexcreate() + +result = main() + +conddestroy(control_signal) +mutexdestroy(control_mutex) -main() +end result -- cgit v1.2.3-24-ge0c7 From e01981e04f12638176b7699e8daf23c0a805bde2 Mon Sep 17 00:00:00 2001 From: luislavena Date: Fri, 18 Apr 2008 07:09:44 +0000 Subject: Wait longer for child process terminate properly (max 20 seconds). Imported tests from RubyServices project. (Closes #18). git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-2@1012 19e92222-5c0b-0410-8929-a290d50e31e9 --- projects/mongrel_service/CHANGELOG | 5 + .../mongrel_service/native/console_process.bas | 22 ++- .../mongrel_service/tests/test_console_process.bas | 149 ++++++++++++--------- projects/mongrel_service/tests/test_helpers.bas | 2 - 4 files changed, 109 insertions(+), 69 deletions(-) diff --git a/projects/mongrel_service/CHANGELOG b/projects/mongrel_service/CHANGELOG index 67f5086..074c87a 100644 --- a/projects/mongrel_service/CHANGELOG +++ b/projects/mongrel_service/CHANGELOG @@ -1,3 +1,8 @@ +* 0.3.5 * + + * Wait longer for child process terminate properly (max 20 seconds). Imported + tests from RubyServices project. (Closes #18). + * Updated ServiceFB to work with FB > 0.18. * 0.3.4 * diff --git a/projects/mongrel_service/native/console_process.bas b/projects/mongrel_service/native/console_process.bas index 78dc1a0..a2bb5c9 100644 --- a/projects/mongrel_service/native/console_process.bas +++ b/projects/mongrel_service/native/console_process.bas @@ -81,6 +81,7 @@ property ConsoleProcess.pid() as uinteger end property property ConsoleProcess.exit_code() as uinteger + static previous_code as uinteger dim result as uinteger result = 0 @@ -90,9 +91,16 @@ property ConsoleProcess.exit_code() as uinteger if not (_process_info.hProcess = NULL) then '# the process reference is valid, get the exit_code if not (GetExitCodeProcess(_process_info.hProcess, @result) = 0) then + previous_code = result '# OK '# no error in the query, get result + if not (result = STILL_ACTIVE) then + CloseHandle(_process_info.hProcess) + _process_info.hProcess = NULL + end if '# (result = STILL_ACTIVE) end if '# not (GetExitCodeProcess() = 0) + else + result = previous_code end if '# not (proc = NULL) end if '# not (_pid = 0) @@ -228,7 +236,7 @@ function ConsoleProcess.start() as boolean else '# use pipes instead '# StdOut - if (CreatePipe(@StdErrRd, @StdErrWr, @proc_sa, 0) = 0) then + if (CreatePipe(@StdErrRd, @StdErrWr, @proc_sa, 0) = 0) then success = false end if @@ -283,10 +291,10 @@ function ConsoleProcess.start() as boolean CloseHandle(StdErrRd) CloseHandle(StdErrWr) - '# close children main Thread handle - 'CloseHandle(proc.hThread) - 'CloseHandle(proc.hProcess) - + '# close children main Thread handle and + '# NULLify to avoid issues + CloseHandle(_process_info.hThread) + _process_info.hThread = NULL end if '# (CreateProcess() = 0) else result = false @@ -322,7 +330,7 @@ function ConsoleProcess.terminate(byval force as boolean = false) as boolean '# send CTRL_C_EVENT and wait for result if not (GenerateConsoleCtrlEvent(CTRL_C_EVENT, 0) = 0) then '# it worked, wait 5 seconds terminates. - wait_code = WaitForSingleObject(proc, 5000) + wait_code = WaitForSingleObject(proc, 10000) if not (wait_code = WAIT_TIMEOUT) then success = true end if @@ -335,7 +343,7 @@ function ConsoleProcess.terminate(byval force as boolean = false) as boolean '# send CTRL_BREAK_EVENT and wait for result if not (GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, 0) = 0) then '# it worked, wait 5 seconds terminates. - wait_code = WaitForSingleObject(proc, 5000) + wait_code = WaitForSingleObject(proc, 10000) if not (wait_code = WAIT_TIMEOUT) then success = true end if diff --git a/projects/mongrel_service/tests/test_console_process.bas b/projects/mongrel_service/tests/test_console_process.bas index 02cb5f9..d41c0fb 100644 --- a/projects/mongrel_service/tests/test_console_process.bas +++ b/projects/mongrel_service/tests/test_console_process.bas @@ -30,7 +30,7 @@ namespace Suite_Test_Console_Process sub test_process_create() child = new ConsoleProcess() - assert_not_equal_error(0, child) + assert_not_equal(0, child) assert_equal("", child->filename) assert_equal("", child->arguments) assert_false(child->running) @@ -64,7 +64,7 @@ namespace Suite_Test_Console_Process '# start() should return true since it started, no matter if was terminated '# improperly assert_true(child->start()) - sleep 150 + sleep 500 '# should not be running, but pid should be != than 0 assert_not_equal(0, child->pid) @@ -80,6 +80,9 @@ namespace Suite_Test_Console_Process end sub sub test_redirected_output() + assert_false(fileexists("out.log")) + assert_false(fileexists("err.log")) + '# redirected output is used with logging files. child = new ConsoleProcess("mock_process.exe") @@ -93,7 +96,7 @@ namespace Suite_Test_Console_Process '# start() will be true since process terminated nicely assert_true(child->start()) - sleep 150 + sleep 500 '# running should be false assert_false(child->running) @@ -101,6 +104,8 @@ namespace Suite_Test_Console_Process '# exit_code should be 0 assert_equal(0, child->exit_code) + delete child + '# now out.log and err.log must exist and content must be valid. assert_true(fileexists("out.log")) assert_string_equal("out: message", content_of_file("out.log")) @@ -108,14 +113,8 @@ namespace Suite_Test_Console_Process assert_true(fileexists("err.log")) assert_string_equal("err: error", content_of_file("err.log")) - '# cleanup - process_cleanup() - assert_equal_error(0, kill("out.log")) - assert_equal_error(0, kill("err.log")) - - assert_true_error(fileexists("err.log")) - - delete child + assert_equal(0, kill("out.log")) + assert_equal(0, kill("err.log")) end sub sub test_redirected_merged_output() @@ -131,7 +130,7 @@ namespace Suite_Test_Console_Process '# start() will be true since process terminated nicely assert_true(child->start()) - sleep 150 + sleep 500 '# running should be false assert_false(child->running) @@ -139,6 +138,8 @@ namespace Suite_Test_Console_Process '# exit_code should be 0 assert_equal(0, child->exit_code) + delete child + '# file must exists assert_true(fileexists("both.log")) @@ -148,11 +149,7 @@ namespace Suite_Test_Console_Process assert_not_equal(0, instr(content, "out: message")) assert_not_equal(0, instr(content, "err: error")) - '# cleanup - process_cleanup() - assert_equal_error(0, kill("both.log")) - - delete child + assert_equal(0, kill("both.log")) end sub sub test_redirected_output_append() @@ -165,21 +162,19 @@ namespace Suite_Test_Console_Process '# start() will be true since process terminated nicely assert_true(child->start()) - sleep 150 + sleep 500 content = content_of_file("both.log") '# start() again assert_true(child->start()) - sleep 150 + sleep 500 - assert_not_equal(len(content), len(content_of_file("both.log"))) + delete child - '# cleanup - process_cleanup() - assert_equal_error(0, kill("both.log")) + assert_not_equal(len(content), len(content_of_file("both.log"))) - delete child + assert_equal(0, kill("both.log")) end sub sub test_process_terminate() @@ -191,7 +186,7 @@ namespace Suite_Test_Console_Process '# start assert_true(child->start()) - sleep 150 + sleep 500 '# validate if running assert_true(child->running) @@ -201,13 +196,15 @@ namespace Suite_Test_Console_Process '# now terminates it assert_true(child->terminate()) - sleep 150 + sleep 500 assert_equal(9, child->exit_code) '# it should be done assert_false(child->running) + delete child + '# validate output '# file must exists assert_true(fileexists("both.log")) @@ -219,23 +216,61 @@ namespace Suite_Test_Console_Process assert_not_equal(0, instr(content, "err: error")) assert_not_equal(0, instr(content, "interrupted")) - '# cleanup - process_cleanup() - assert_equal_error(0, kill("both.log")) + assert_equal(0, kill("both.log")) + end sub + + sub test_process_terminate_slow1() + dim content as string + + '# redirected output is used with logging files. + child = new ConsoleProcess("mock_process.exe", "slow1") + child->redirect(ProcessStdBoth, "both_slow1.log") + + '# start + assert_true(child->start()) + sleep 500 + + '# validate if running + assert_true(child->running) + + '# validate PID + assert_not_equal(0, child->pid) + + '# now terminates it + assert_true(child->terminate()) + sleep 500 + + assert_equal(10, child->exit_code) + + '# it should be done + assert_false(child->running) delete child + + '# validate output + '# file must exists + assert_true(fileexists("both_slow1.log")) + + '# contents must match + content = content_of_file("both_slow1.log") + + assert_equal(0, instr(content, "interrupted")) + assert_not_equal(0, instr(content, "out: CTRL-C received")) + assert_equal(0, instr(content, "out: CTRL-BREAK received")) + + assert_equal(0, kill("both_slow1.log")) end sub - sub test_process_terminate_slow() + sub test_process_terminate_slow2() dim content as string '# redirected output is used with logging files. - child = new ConsoleProcess("mock_process.exe", "slow") - child->redirect(ProcessStdBoth, "both_slow.log") + child = new ConsoleProcess("mock_process.exe", "slow2") + child->redirect(ProcessStdBoth, "both_slow2.log") '# start assert_true(child->start()) - sleep 150 + sleep 500 '# validate if running assert_true(child->running) @@ -245,34 +280,32 @@ namespace Suite_Test_Console_Process '# now terminates it assert_true(child->terminate()) - sleep 150 + sleep 500 + + assert_equal(20, child->exit_code) - '# it should be done now + '# it should be done assert_false(child->running) - assert_equal(10, child->exit_code) + + delete child '# validate output '# file must exists - assert_true(fileexists("both_slow.log")) + assert_true(fileexists("both_slow2.log")) '# contents must match - content = content_of_file("both_slow.log") + content = content_of_file("both_slow2.log") - assert_not_equal(0, instr(content, "out: message")) - assert_not_equal(0, instr(content, "err: error")) - assert_not_equal(0, instr(content, "out: slow stop")) assert_equal(0, instr(content, "interrupted")) + assert_not_equal(0, instr(content, "out: CTRL-C received")) + assert_not_equal(0, instr(content, "out: CTRL-BREAK received")) '# cleanup - process_cleanup() - assert_equal_error(0, kill("both_slow.log")) - - delete child + assert_equal(0, kill("both_slow2.log")) end sub - + sub test_process_terminate_forced() dim content as string - dim x as integer '# redirected output is used with logging files. child = new ConsoleProcess("mock_process.exe", "wait") @@ -280,7 +313,7 @@ namespace Suite_Test_Console_Process '# start assert_true(child->start()) - sleep 150 + sleep 500 '# validate if running assert_true(child->running) @@ -290,7 +323,7 @@ namespace Suite_Test_Console_Process '# now terminates it assert_true(child->terminate(true)) - sleep 150 + sleep 500 '# it should be done assert_false(child->running) @@ -298,6 +331,8 @@ namespace Suite_Test_Console_Process '# look for termination code assert_equal(0, child->exit_code) + delete child + '# validate output '# file must exists assert_true(fileexists("both_forced.log")) @@ -309,11 +344,7 @@ namespace Suite_Test_Console_Process assert_equal(0, instr(content, "err: error")) assert_equal(0, instr(content, "interrupted")) - '# cleanup - process_cleanup() - assert_equal_error(0, kill("both_forced.log")) - - delete child + assert_equal(0, kill("both_forced.log")) end sub sub test_reuse_object_instance() @@ -323,7 +354,7 @@ namespace Suite_Test_Console_Process '# start assert_true(child->start()) - sleep 150 + sleep 500 '# validate not running assert_false(child->running) @@ -336,16 +367,13 @@ namespace Suite_Test_Console_Process '# start it again assert_true(child->start()) - sleep 150 + sleep 500 '# it should have stopped by now assert_false(child->running) assert_not_equal(0, child->pid) assert_not_equal(first_pid, child->pid) - '# cleanup - process_cleanup() - delete child end sub @@ -360,7 +388,8 @@ namespace Suite_Test_Console_Process add_test(test_redirected_merged_output) add_test(test_redirected_output_append) add_test(test_process_terminate) - add_test(test_process_terminate_slow) + add_test(test_process_terminate_slow1) + add_test(test_process_terminate_slow2) add_test(test_process_terminate_forced) add_test(test_reuse_object_instance) end sub diff --git a/projects/mongrel_service/tests/test_helpers.bas b/projects/mongrel_service/tests/test_helpers.bas index 69b74cd..c4647c0 100644 --- a/projects/mongrel_service/tests/test_helpers.bas +++ b/projects/mongrel_service/tests/test_helpers.bas @@ -33,5 +33,3 @@ function content_of_file(byref filename as string) as string return result end function - -print content_of_file("testing.log") -- cgit v1.2.3-24-ge0c7 From fa3f48f65222eb5591ef3dd9c05b6c958d564fa4 Mon Sep 17 00:00:00 2001 From: evanweaver Date: Thu, 22 May 2008 02:31:57 +0000 Subject: I think that was a bug. git-svn-id: svn+ssh://rubyforge.org/var/svn/mongrel/branches/stable_1-2@1013 19e92222-5c0b-0410-8929-a290d50e31e9 --- bin/mongrel_rails | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/mongrel_rails b/bin/mongrel_rails index ba601c5..42ecf31 100644 --- a/bin/mongrel_rails +++ b/bin/mongrel_rails @@ -30,7 +30,7 @@ module Mongrel ['-a', '--address ADDR', "Address to bind to", :@address, "0.0.0.0"], ['-l', '--log FILE', "Where to write log messages", :@log_file, "log/mongrel.log"], ['-P', '--pid FILE', "Where to write the PID", :@pid_file, "log/mongrel.pid"], - ['-n', '--num-procs INT', "Number of processors active before clients denied", :@num_procs, 1024], + ['-n', '--num-processors INT', "Number of processors active before clients denied", :@num_processors, 1024], ['-o', '--timeout TIME', "Time to wait (in seconds) before killing a stalled thread", :@timeout, 60], ['-t', '--throttle TIME', "Time to pause (in hundredths of a second) between accepting clients", :@throttle, 0], ['-m', '--mime PATH', "A YAML file that lists additional MIME types", :@mime_map, nil], -- cgit v1.2.3-24-ge0c7