puma 0.8.2-java

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puma might be problematic. Click here for more details.

Files changed (63) hide show
  1. data/.gemtest +0 -0
  2. data/COPYING +55 -0
  3. data/Gemfile +6 -0
  4. data/History.txt +69 -0
  5. data/LICENSE +26 -0
  6. data/Manifest.txt +60 -0
  7. data/README.md +60 -0
  8. data/Rakefile +12 -0
  9. data/TODO +5 -0
  10. data/bin/puma +15 -0
  11. data/examples/builder.rb +29 -0
  12. data/examples/camping/README +3 -0
  13. data/examples/camping/blog.rb +294 -0
  14. data/examples/camping/tepee.rb +149 -0
  15. data/examples/httpd.conf +474 -0
  16. data/examples/mime.yaml +3 -0
  17. data/examples/mongrel.conf +9 -0
  18. data/examples/monitrc +57 -0
  19. data/examples/random_thrash.rb +19 -0
  20. data/examples/simpletest.rb +52 -0
  21. data/examples/webrick_compare.rb +20 -0
  22. data/ext/puma_http11/PumaHttp11Service.java +13 -0
  23. data/ext/puma_http11/ext_help.h +15 -0
  24. data/ext/puma_http11/extconf.rb +5 -0
  25. data/ext/puma_http11/http11_parser.c +1225 -0
  26. data/ext/puma_http11/http11_parser.h +63 -0
  27. data/ext/puma_http11/http11_parser.java.rl +161 -0
  28. data/ext/puma_http11/http11_parser.rl +146 -0
  29. data/ext/puma_http11/http11_parser_common.rl +54 -0
  30. data/ext/puma_http11/org/jruby/puma/Http11.java +225 -0
  31. data/ext/puma_http11/org/jruby/puma/Http11Parser.java +488 -0
  32. data/ext/puma_http11/puma_http11.c +482 -0
  33. data/lib/puma.rb +18 -0
  34. data/lib/puma/cli.rb +164 -0
  35. data/lib/puma/const.rb +132 -0
  36. data/lib/puma/events.rb +36 -0
  37. data/lib/puma/gems.rb +20 -0
  38. data/lib/puma/mime_types.yml +616 -0
  39. data/lib/puma/rack_patch.rb +22 -0
  40. data/lib/puma/server.rb +429 -0
  41. data/lib/puma/thread_pool.rb +95 -0
  42. data/lib/puma/utils.rb +44 -0
  43. data/lib/puma_http11.jar +0 -0
  44. data/lib/rack/handler/puma.rb +48 -0
  45. data/puma.gemspec +40 -0
  46. data/tasks/gem.rake +24 -0
  47. data/tasks/java.rake +12 -0
  48. data/tasks/native.rake +36 -0
  49. data/tasks/ragel.rake +24 -0
  50. data/test/lobster.ru +4 -0
  51. data/test/mime.yaml +3 -0
  52. data/test/test_cli.rb +19 -0
  53. data/test/test_http10.rb +27 -0
  54. data/test/test_http11.rb +151 -0
  55. data/test/test_persistent.rb +205 -0
  56. data/test/test_rack_handler.rb +10 -0
  57. data/test/test_rack_server.rb +122 -0
  58. data/test/test_thread_pool.rb +102 -0
  59. data/test/test_unix_socket.rb +37 -0
  60. data/test/test_ws.rb +97 -0
  61. data/test/testhelp.rb +41 -0
  62. data/tools/trickletest.rb +45 -0
  63. metadata +163 -0
@@ -0,0 +1,95 @@
1
+ require 'thread'
2
+
3
+ module Puma
4
+ class ThreadPool
5
+ def initialize(min, max, &blk)
6
+ @todo = Queue.new
7
+ @mutex = Mutex.new
8
+
9
+ @spawned = 0
10
+ @min = min
11
+ @max = max
12
+ @block = blk
13
+
14
+ @trim_requested = 0
15
+
16
+ @workers = []
17
+
18
+ min.times { spawn_thread }
19
+ end
20
+
21
+ attr_reader :spawned
22
+
23
+ def backlog
24
+ @todo.size
25
+ end
26
+
27
+ Stop = Object.new
28
+ Trim = Object.new
29
+
30
+ def spawn_thread
31
+ @mutex.synchronize do
32
+ @spawned += 1
33
+ end
34
+
35
+ th = Thread.new do
36
+ todo = @todo
37
+ block = @block
38
+
39
+ while true
40
+ work = todo.pop
41
+
42
+ case work
43
+ when Stop
44
+ break
45
+ when Trim
46
+ @mutex.synchronize do
47
+ @trim_requested -= 1
48
+ end
49
+
50
+ break
51
+ else
52
+ block.call work
53
+ end
54
+ end
55
+
56
+ @mutex.synchronize do
57
+ @spawned -= 1
58
+ @workers.delete th
59
+ end
60
+ end
61
+
62
+ @mutex.synchronize { @workers << th }
63
+
64
+ th
65
+ end
66
+
67
+ def <<(work)
68
+ if @todo.num_waiting == 0 and @spawned < @max
69
+ spawn_thread
70
+ end
71
+
72
+ @todo << work
73
+ end
74
+
75
+ def trim
76
+ @mutex.synchronize do
77
+ if @spawned - @trim_requested > @min
78
+ @trim_requested += 1
79
+ @todo << Trim
80
+ end
81
+ end
82
+ end
83
+
84
+ def shutdown
85
+ @spawned.times do
86
+ @todo << Stop
87
+ end
88
+
89
+ @workers.each { |w| w.join }
90
+
91
+ @spawned = 0
92
+ @workers = []
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,44 @@
1
+ module Puma
2
+ module Utils
3
+ # Performs URI escaping so that you can construct proper
4
+ # query strings faster. Use this rather than the cgi.rb
5
+ # version since it's faster. (Stolen from Camping).
6
+ def self.escape(s)
7
+ s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) {
8
+ '%'+$1.unpack('H2'*$1.size).join('%').upcase
9
+ }.tr(' ', '+')
10
+ end
11
+
12
+
13
+ # Unescapes a URI escaped string. (Stolen from Camping).
14
+ def self.unescape(s)
15
+ s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){
16
+ [$1.delete('%')].pack('H*')
17
+ }
18
+ end
19
+
20
+ # Parses a query string by breaking it up at the '&'
21
+ # and ';' characters. You can also use this to parse
22
+ # cookies by changing the characters used in the second
23
+ # parameter (which defaults to '&;'.
24
+ def self.query_parse(qs, d = '&;')
25
+ params = {}
26
+
27
+ qs.split(/[#{d}] */n).each do |p|
28
+ k, v = unescape(p).split('=', 2)
29
+
30
+ if cur = params[k]
31
+ if cur.kind_of? Array
32
+ params[k] << v
33
+ else
34
+ params[k] = [cur, v]
35
+ end
36
+ else
37
+ params[k] = v
38
+ end
39
+ end
40
+
41
+ return params
42
+ end
43
+ end
44
+ end
Binary file
@@ -0,0 +1,48 @@
1
+ require 'rack/handler'
2
+ require 'puma'
3
+
4
+ module Rack
5
+ module Handler
6
+ module Puma
7
+ DEFAULT_OPTIONS = {
8
+ :Host => '0.0.0.0',
9
+ :Port => 8080,
10
+ :Threads => '0:16',
11
+ :Quiet => false
12
+ }
13
+
14
+ def self.run(app, options = {})
15
+ options = DEFAULT_OPTIONS.merge(options)
16
+
17
+ unless options[:Quiet]
18
+ app = Rack::CommonLogger.new(app, STDOUT)
19
+ end
20
+
21
+ server = ::Puma::Server.new(app)
22
+ min, max = options[:Threads].split(':', 2)
23
+
24
+ puts "Puma #{::Puma::Const::PUMA_VERSION} starting..."
25
+ puts "* Min threads: #{min}, max threads: #{max}"
26
+ puts "* Listening on tcp://#{options[:Host]}:#{options[:Port]}"
27
+
28
+ server.add_tcp_listener options[:Host], options[:Port]
29
+ server.min_threads = Integer(min)
30
+ server.max_threads = Integer(max)
31
+ yield server if block_given?
32
+
33
+ server.run.join
34
+ end
35
+
36
+ def self.valid_options
37
+ {
38
+ "Host=HOST" => "Hostname to listen on (default: localhost)",
39
+ "Port=PORT" => "Port to listen on (default: 8080)",
40
+ "Threads=MIN:MAX" => "min:max threads to use (default 0:16)",
41
+ "Quiet" => "Don't report each request"
42
+ }
43
+ end
44
+ end
45
+
46
+ register :puma, Puma
47
+ end
48
+ end
@@ -0,0 +1,40 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = "puma"
5
+ s.version = "0.8.2"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Evan Phoenix"]
9
+ s.date = "2011-11-22"
10
+ s.description = "Puma is a small library that provides a very fast and concurrent HTTP 1.1 server for Ruby web applications. It is designed for running rack apps only.\n\nWhat makes Puma so fast is the careful use of an Ragel extension to provide fast, accurate HTTP 1.1 protocol parsing. This makes the server scream without too many portability issues."
11
+ s.email = ["evan@phx.io"]
12
+ s.executables = ["puma"]
13
+ s.extensions = ["ext/puma_http11/extconf.rb"]
14
+ s.extra_rdoc_files = ["History.txt", "Manifest.txt"]
15
+ s.files = ["COPYING", "Gemfile", "History.txt", "LICENSE", "Manifest.txt", "README.md", "Rakefile", "TODO", "bin/puma", "examples/builder.rb", "examples/camping/README", "examples/camping/blog.rb", "examples/camping/tepee.rb", "examples/httpd.conf", "examples/mime.yaml", "examples/mongrel.conf", "examples/monitrc", "examples/random_thrash.rb", "examples/simpletest.rb", "examples/webrick_compare.rb", "ext/puma_http11/PumaHttp11Service.java", "ext/puma_http11/ext_help.h", "ext/puma_http11/extconf.rb", "ext/puma_http11/http11_parser.c", "ext/puma_http11/http11_parser.h", "ext/puma_http11/http11_parser.java.rl", "ext/puma_http11/http11_parser.rl", "ext/puma_http11/http11_parser_common.rl", "ext/puma_http11/org/jruby/puma/Http11.java", "ext/puma_http11/org/jruby/puma/Http11Parser.java", "ext/puma_http11/puma_http11.c", "lib/puma.rb", "lib/puma/cli.rb", "lib/puma/const.rb", "lib/puma/events.rb", "lib/puma/gems.rb", "lib/puma/mime_types.yml", "lib/puma/rack_patch.rb", "lib/puma/server.rb", "lib/puma/thread_pool.rb", "lib/puma/utils.rb", "lib/rack/handler/puma.rb", "puma.gemspec", "tasks/gem.rake", "tasks/java.rake", "tasks/native.rake", "tasks/ragel.rake", "test/lobster.ru", "test/mime.yaml", "test/test_cli.rb", "test/test_http10.rb", "test/test_http11.rb", "test/test_persistent.rb", "test/test_rack_handler.rb", "test/test_rack_server.rb", "test/test_thread_pool.rb", "test/test_unix_socket.rb", "test/test_ws.rb", "test/testhelp.rb", "tools/trickletest.rb", ".gemtest"]
16
+ s.rdoc_options = ["--main", "README.md"]
17
+ s.require_paths = ["lib"]
18
+ s.rubyforge_project = "puma"
19
+ s.rubygems_version = "1.8.10"
20
+ s.summary = "Puma is a small library that provides a very fast and concurrent HTTP 1.1 server for Ruby web applications"
21
+ s.test_files = ["test/test_cli.rb", "test/test_http10.rb", "test/test_http11.rb", "test/test_persistent.rb", "test/test_rack_handler.rb", "test/test_rack_server.rb", "test/test_thread_pool.rb", "test/test_unix_socket.rb", "test/test_ws.rb"]
22
+
23
+ if s.respond_to? :specification_version then
24
+ s.specification_version = 3
25
+
26
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
27
+ s.add_runtime_dependency(%q<rack>, ["~> 1.2"])
28
+ s.add_development_dependency(%q<rake-compiler>, ["~> 0.7.0"])
29
+ s.add_development_dependency(%q<hoe>, ["~> 2.10"])
30
+ else
31
+ s.add_dependency(%q<rack>, ["~> 1.2"])
32
+ s.add_dependency(%q<rake-compiler>, ["~> 0.7.0"])
33
+ s.add_dependency(%q<hoe>, ["~> 2.10"])
34
+ end
35
+ else
36
+ s.add_dependency(%q<rack>, ["~> 1.2"])
37
+ s.add_dependency(%q<rake-compiler>, ["~> 0.7.0"])
38
+ s.add_dependency(%q<hoe>, ["~> 2.10"])
39
+ end
40
+ end
@@ -0,0 +1,24 @@
1
+ require 'hoe'
2
+
3
+ HOE = Hoe.spec 'puma' do
4
+ self.rubyforge_name = 'puma'
5
+ self.readme_file = "README.md"
6
+ developer 'Evan Phoenix', 'evan@phx.io'
7
+
8
+ spec_extras[:extensions] = ["ext/puma_http11/extconf.rb"]
9
+ spec_extras[:executables] = ['puma']
10
+
11
+ dependency 'rack', '~> 1.2'
12
+
13
+ extra_dev_deps << ['rake-compiler', "~> 0.7.0"]
14
+
15
+ clean_globs.push('test_*.log', 'log')
16
+ end
17
+
18
+ file "#{HOE.spec.name}.gemspec" => ['Rakefile', 'tasks/gem.rake'] do |t|
19
+ puts "Generating #{t.name}"
20
+ File.open(t.name, 'w') { |f| f.puts HOE.spec.to_ruby }
21
+ end
22
+
23
+ desc "Generate or update the standalone gemspec file for the project"
24
+ task :gemspec => ["#{HOE.spec.name}.gemspec"]
@@ -0,0 +1,12 @@
1
+ if IS_JRUBY
2
+
3
+ require 'rake/javaextensiontask'
4
+
5
+ # build http11 java extension
6
+ Rake::JavaExtensionTask.new('puma_http11', HOE.spec) do |ext|
7
+ ext.java_compiling do |gs|
8
+ gs.dependencies.delete gs.dependencies.find { |d| d.name == 'daemons' }
9
+ end
10
+ end
11
+
12
+ end
@@ -0,0 +1,36 @@
1
+ unless IS_JRUBY
2
+
3
+ # use rake-compiler for building the extension
4
+ require 'rake/extensiontask'
5
+
6
+ # build http11 C extension
7
+ Rake::ExtensionTask.new('puma_http11', HOE.spec) do |ext|
8
+ # define target for extension (supporting fat binaries)
9
+ if RUBY_PLATFORM =~ /mingw|mswin/ then
10
+ RUBY_VERSION =~ /(\d+\.\d+)/
11
+ ext.lib_dir = "lib/#{$1}"
12
+ elsif ENV['CROSS']
13
+ # define cross-compilation tasks when not on Windows.
14
+ ext.cross_compile = true
15
+ ext.cross_platform = ['i386-mswin32', 'i386-mingw32']
16
+
17
+ ext.cross_compiling do |gs|
18
+ gs.dependencies.delete gs.dependencies.find { |d| d.name == 'daemons' }
19
+ end
20
+ end
21
+
22
+ # cleanup versioned library directory
23
+ CLEAN.include 'lib/{1.8,1.9}'
24
+ end
25
+ end
26
+
27
+ task :ext_clean do
28
+ sh "rm -rf lib/puma_http11.bundle"
29
+ sh "rm -rf lib/puma_http11.jar"
30
+ sh "rm -rf lib/puma_http11.so"
31
+ end
32
+
33
+ # ensure things are built prior testing
34
+ task :test => [:compile]
35
+
36
+ task :clean => :ext_clean
@@ -0,0 +1,24 @@
1
+
2
+ # the following tasks ease the build of C file from Ragel one
3
+
4
+ file 'ext/puma_http11/http11_parser.c' => ['ext/puma_http11/http11_parser.rl'] do |t|
5
+ begin
6
+ sh "ragel #{t.prerequisites.last} -C -G2 -o #{t.name}"
7
+ rescue
8
+ fail "Could not build wrapper using Ragel (it failed or not installed?)"
9
+ end
10
+ end
11
+
12
+ file 'ext/puma_http11/org/jruby/puma/Http11Parser.java' => ['ext/puma_http11/http11_parser.java.rl'] do |t|
13
+ begin
14
+ sh "ragel #{t.prerequisites.last} -J -G2 -o #{t.name}"
15
+ rescue
16
+ fail "Could not build wrapper using Ragel (it failed or not installed?)"
17
+ end
18
+ end
19
+
20
+ if IS_JRUBY
21
+ task :ragel => 'ext/puma_http11/org/jruby/puma/Http11Parser.java'
22
+ else
23
+ task :ragel => 'ext/puma_http11/http11_parser.c'
24
+ end
@@ -0,0 +1,4 @@
1
+ require 'rack/lobster'
2
+
3
+ use Rack::ShowExceptions
4
+ run Rack::Lobster.new
@@ -0,0 +1,3 @@
1
+ ---
2
+ .jpeg: image/jpeg
3
+ .png: image/test
@@ -0,0 +1,19 @@
1
+ require 'test/unit'
2
+ require 'puma/cli'
3
+ require 'tempfile'
4
+
5
+ class TestCLI < Test::Unit::TestCase
6
+ def setup
7
+ @pid_file = Tempfile.new("puma-test")
8
+ @pid_path = @pid_file.path
9
+ @pid_file.close!
10
+ end
11
+
12
+ def test_pid_file
13
+ cli = Puma::CLI.new ["--pidfile", @pid_path]
14
+ cli.parse_options
15
+ cli.write_pid
16
+
17
+ assert_equal File.read(@pid_path).strip.to_i, Process.pid
18
+ end
19
+ end
@@ -0,0 +1,27 @@
1
+ require 'test/testhelp'
2
+
3
+ class Http10ParserTest < Test::Unit::TestCase
4
+ include Puma
5
+
6
+ def test_parse_simple
7
+ parser = HttpParser.new
8
+ req = {}
9
+ http = "GET / HTTP/1.0\r\n\r\n"
10
+ nread = parser.execute(req, http, 0)
11
+
12
+ assert nread == http.length, "Failed to parse the full HTTP request"
13
+ assert parser.finished?, "Parser didn't finish"
14
+ assert !parser.error?, "Parser had error"
15
+ assert nread == parser.nread, "Number read returned from execute does not match"
16
+
17
+ assert_equal '/', req['REQUEST_PATH']
18
+ assert_equal 'HTTP/1.0', req['HTTP_VERSION']
19
+ assert_equal '/', req['REQUEST_URI']
20
+ assert_equal 'GET', req['REQUEST_METHOD']
21
+ assert_nil req['FRAGMENT']
22
+ assert_nil req['QUERY_STRING']
23
+
24
+ parser.reset
25
+ assert parser.nread == 0, "Number read after reset should be 0"
26
+ end
27
+ end
@@ -0,0 +1,151 @@
1
+ # Copyright (c) 2011 Evan Phoenix
2
+ # Copyright (c) 2005 Zed A. Shaw
3
+
4
+ require 'test/testhelp'
5
+
6
+ include Puma
7
+
8
+ class Http11ParserTest < Test::Unit::TestCase
9
+
10
+ def test_parse_simple
11
+ parser = HttpParser.new
12
+ req = {}
13
+ http = "GET / HTTP/1.1\r\n\r\n"
14
+ nread = parser.execute(req, http, 0)
15
+
16
+ assert nread == http.length, "Failed to parse the full HTTP request"
17
+ assert parser.finished?, "Parser didn't finish"
18
+ assert !parser.error?, "Parser had error"
19
+ assert nread == parser.nread, "Number read returned from execute does not match"
20
+
21
+ assert_equal '/', req['REQUEST_PATH']
22
+ assert_equal 'HTTP/1.1', req['HTTP_VERSION']
23
+ assert_equal '/', req['REQUEST_URI']
24
+ assert_equal 'GET', req['REQUEST_METHOD']
25
+ assert_nil req['FRAGMENT']
26
+ assert_nil req['QUERY_STRING']
27
+
28
+ parser.reset
29
+ assert parser.nread == 0, "Number read after reset should be 0"
30
+ end
31
+
32
+ def test_parse_dumbfuck_headers
33
+ parser = HttpParser.new
34
+ req = {}
35
+ should_be_good = "GET / HTTP/1.1\r\naaaaaaaaaaaaa:++++++++++\r\n\r\n"
36
+ nread = parser.execute(req, should_be_good, 0)
37
+ assert_equal should_be_good.length, nread
38
+ assert parser.finished?
39
+ assert !parser.error?
40
+
41
+ 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"
42
+ parser = HttpParser.new
43
+ req = {}
44
+ #nread = parser.execute(req, nasty_pound_header, 0)
45
+ #assert_equal nasty_pound_header.length, nread
46
+ #assert parser.finished?
47
+ #assert !parser.error?
48
+ end
49
+
50
+ def test_parse_error
51
+ parser = HttpParser.new
52
+ req = {}
53
+ bad_http = "GET / SsUTF/1.1"
54
+
55
+ error = false
56
+ begin
57
+ nread = parser.execute(req, bad_http, 0)
58
+ rescue => details
59
+ error = true
60
+ end
61
+
62
+ assert error, "failed to throw exception"
63
+ assert !parser.finished?, "Parser shouldn't be finished"
64
+ assert parser.error?, "Parser SHOULD have error"
65
+ end
66
+
67
+ def test_fragment_in_uri
68
+ parser = HttpParser.new
69
+ req = {}
70
+ get = "GET /forums/1/topics/2375?page=1#posts-17408 HTTP/1.1\r\n\r\n"
71
+ assert_nothing_raised do
72
+ parser.execute(req, get, 0)
73
+ end
74
+ assert parser.finished?
75
+ assert_equal '/forums/1/topics/2375?page=1', req['REQUEST_URI']
76
+ assert_equal 'posts-17408', req['FRAGMENT']
77
+ end
78
+
79
+ # lame random garbage maker
80
+ def rand_data(min, max, readable=true)
81
+ count = min + ((rand(max)+1) *10).to_i
82
+ res = count.to_s + "/"
83
+
84
+ if readable
85
+ res << Digest::SHA1.hexdigest(rand(count * 100).to_s) * (count / 40)
86
+ else
87
+ res << Digest::SHA1.digest(rand(count * 100).to_s) * (count / 20)
88
+ end
89
+
90
+ return res
91
+ end
92
+
93
+
94
+ def test_horrible_queries
95
+ parser = HttpParser.new
96
+
97
+ # then that large header names are caught
98
+ 10.times do |c|
99
+ get = "GET /#{rand_data(10,120)} HTTP/1.1\r\nX-#{rand_data(1024, 1024+(c*1024))}: Test\r\n\r\n"
100
+ assert_raises Puma::HttpParserError do
101
+ parser.execute({}, get, 0)
102
+ parser.reset
103
+ end
104
+ end
105
+
106
+ # then that large mangled field values are caught
107
+ 10.times do |c|
108
+ get = "GET /#{rand_data(10,120)} HTTP/1.1\r\nX-Test: #{rand_data(1024, 1024+(c*1024), false)}\r\n\r\n"
109
+ assert_raises Puma::HttpParserError do
110
+ parser.execute({}, get, 0)
111
+ parser.reset
112
+ end
113
+ end
114
+
115
+ # then large headers are rejected too
116
+ get = "GET /#{rand_data(10,120)} HTTP/1.1\r\n"
117
+ get << "X-Test: test\r\n" * (80 * 1024)
118
+ assert_raises Puma::HttpParserError do
119
+ parser.execute({}, get, 0)
120
+ parser.reset
121
+ end
122
+
123
+ # finally just that random garbage gets blocked all the time
124
+ 10.times do |c|
125
+ get = "GET #{rand_data(1024, 1024+(c*1024), false)} #{rand_data(1024, 1024+(c*1024), false)}\r\n\r\n"
126
+ assert_raises Puma::HttpParserError do
127
+ parser.execute({}, get, 0)
128
+ parser.reset
129
+ end
130
+ end
131
+
132
+ end
133
+
134
+
135
+
136
+ def test_query_parse
137
+ res = Utils.query_parse("zed=1&frank=#{Utils.escape('&&& ')}")
138
+ assert res["zed"], "didn't get the request right"
139
+ assert res["frank"], "no frank"
140
+ assert_equal "1", res["zed"], "wrong result"
141
+ assert_equal "&&& ", Utils.unescape(res["frank"]), "wrong result"
142
+
143
+ res = Utils.query_parse("zed=1&zed=2&zed=3&frank=11;zed=45")
144
+ assert res["zed"], "didn't get the request right"
145
+ assert res["frank"], "no frank"
146
+ assert_equal 4,res["zed"].length, "wrong number for zed"
147
+ assert_equal "11",res["frank"], "wrong number for frank"
148
+ end
149
+
150
+ end
151
+