about summary refs log tree commit homepage
path: root/test/test_session.rb
diff options
context:
space:
mode:
Diffstat (limited to 'test/test_session.rb')
-rw-r--r--test/test_session.rb342
1 files changed, 342 insertions, 0 deletions
diff --git a/test/test_session.rb b/test/test_session.rb
new file mode 100644
index 0000000..aef7d70
--- /dev/null
+++ b/test/test_session.rb
@@ -0,0 +1,342 @@
+# -*- encoding: binary -*-
+require 'test/unit'
+require 'pp'
+require 'socket'
+require 'kcar'
+
+class TestSession < Test::Unit::TestCase
+  def setup
+    @s, @c = UNIXSocket.pair
+  end
+
+  def test_http_one_zero
+    pid = fork do
+      @s << "HTTP/1.0 200 OK\r\n\r\nHI"
+      @s.close
+    end
+    @s.close
+    @session = Kcar::Session.new(@c)
+    status, headers, body = @session.read
+    assert_equal status, "200 OK"
+    assert headers.empty?
+    tmp = []
+    assert ! body.parser.keepalive?
+    assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
+    assert_equal [ "HI" ], tmp
+    _, status = Process.waitpid2(pid)
+    assert status.success?
+    body.close
+    assert @c.closed?
+  end
+
+  def test_http_keepalive
+    pid = fork do
+      @s << "HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nHI"
+    end
+    @session = Kcar::Session.new(@c)
+    status, headers, body = @session.read
+    assert_equal status, "200 OK"
+    assert_equal({"Content-Length" => "2" }, headers)
+    tmp = []
+    assert body.parser.keepalive?
+    assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
+    assert_equal [ "HI" ], tmp
+    _, status = Process.waitpid2(pid)
+    assert status.success?
+    body.close
+    assert ! @c.closed?
+
+    pid = fork do
+      @s << "HTTP/1.1 200 OK\r\nContent-Length: 3\r\n"
+      @s << "Connection: close\r\n\r\nBYE"
+    end
+    status, headers, body = @session.read
+    assert_equal status, "200 OK"
+    assert_equal({ "Content-Length" => "3", "Connection" => "close" }, headers)
+    tmp = []
+    assert ! body.parser.keepalive?
+    assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
+    assert_equal [ "BYE" ], tmp
+    _, status = Process.waitpid2(pid)
+    assert status.success?
+    body.close
+    assert @c.closed?
+  end
+
+  def test_http_keepalive_chunky
+    @session = Kcar::Session.new(@c)
+    pid = fork do
+      @s << "HTTP/1.1 200 OK\r\nTransfer-Encoding: chunked\r\n\r\n"
+      @s << "5\r\nabcde\r\n"
+      @s << "0\r\n\r\nHTTP/1.1 " # partial response
+    end
+    status, headers, body = @session.read
+    assert_equal status, "200 OK"
+    assert_equal({"Transfer-Encoding" => "chunked" }, headers)
+    tmp = []
+    assert body.parser.keepalive?
+    assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
+    assert_equal [ "abcde" ], tmp
+    _, status = Process.waitpid2(pid)
+    assert status.success?
+    body.close
+    assert ! @c.closed?
+    assert_equal "HTTP/1.1 ", @session.buf
+
+    pid = fork do
+      @s << "200 OK\r\nContent-Length: 3\r\n"
+      @s << "Connection: close\r\n\r\nBYE"
+    end
+    status, headers, body = @session.read
+    assert_equal status, "200 OK"
+    assert_equal({ "Content-Length" => "3", "Connection" => "close" }, headers)
+    tmp = []
+    assert ! body.parser.keepalive?
+    assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
+    assert_equal [ "BYE" ], tmp
+    _, status = Process.waitpid2(pid)
+    assert status.success?
+    body.close
+    assert @c.closed?
+  end
+
+  def test_http_no_body_keepalive
+    pid = fork { @s << "HTTP/1.1 100 Continue\r\n\r\n" }
+    @session = Kcar::Session.new(@c)
+    status, headers, body = @session.read
+    assert_equal status, "100 Continue"
+    assert_equal({}, headers)
+    tmp = []
+    assert body.parser.keepalive?
+    assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
+    assert tmp.empty?
+    _, status = Process.waitpid2(pid)
+    assert status.success?
+    body.close
+    assert ! @c.closed?
+
+    pid = fork { @s << "HTTP/1.1 200 OK\r\nConnection: close\r\n\r\nhello" }
+    @s.close
+    status, headers, body = @session.read
+    assert_equal status, "200 OK"
+    assert_equal({'Connection' => 'close'}, headers)
+    tmp = []
+    assert ! body.parser.keepalive?
+    assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
+    assert_equal(%w(hello), tmp)
+    _, status = Process.waitpid2(pid)
+    assert status.success?
+    body.close
+    assert @c.closed?
+  end
+
+  def test_trailers
+    pid = fork do
+      @s << "HTTP/1.1 200 OK\r\nTrailer: Foo\r\n"
+      @s << "Transfer-Encoding: chunked\r\n\r\n"
+    end
+    @session = Kcar::Session.new(@c)
+    status, headers, body = @session.read
+    assert_equal status, "200 OK"
+    expect = {
+      "Trailer" => "Foo",
+      "Transfer-Encoding" => "chunked",
+    }
+    assert_equal(expect, headers)
+    assert body.parser.keepalive?
+    _, status = Process.waitpid2(pid)
+    assert status.success?
+    tmp = []
+    pid = fork { @s << "5\r\nhello\r\n0\r\nFoo: bar\r\n\r\n" }
+    assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
+    assert_equal %w(hello), tmp
+    expect['Foo'] = 'bar'
+    assert_equal(expect, headers)
+    _, status = Process.waitpid2(pid)
+    assert status.success?
+    body.close
+    assert ! @c.closed?
+  end
+
+  def test_trailers_pass_through
+    pid = fork do
+      @s << "HTTP/1.1 200 OK\r\nTrailer: Foo\r\n"
+      @s << "Transfer-Encoding: chunked\r\n\r\n"
+    end
+    @session = Kcar::Session.new(@c, false)
+    status, headers, body = @session.read
+    assert_equal status, "200 OK"
+    expect = {
+      "Trailer" => "Foo",
+      "Transfer-Encoding" => "chunked",
+    }
+    assert_equal(expect, headers)
+    assert body.parser.keepalive?
+    _, status = Process.waitpid2(pid)
+    assert status.success?
+    tmp = []
+    pid = fork { @s << "5\r\nhello\r\n0\r\nFoo: bar\r\n\r\n" }
+    assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
+    assert_equal ["5\r\n", "hello\r\n", "0\r\n", "Foo: bar\r\n\r\n"], tmp
+    expect['Foo'] = 'bar'
+    assert_equal(expect, headers)
+    _, status = Process.waitpid2(pid)
+    assert status.success?
+    body.close
+    assert ! @c.closed?
+  end
+
+  def test_pass_through_one_oh
+    pid = fork do
+      @s << "HTTP/1.0 200 OK\r\n"
+      @s << "Content-Type: text/plain\r\n\r\n"
+    end
+    @session = Kcar::Session.new(@c, false)
+    status, headers, body = @session.read
+    assert_equal status, "200 OK"
+    expect = { "Content-Type" => "text/plain", }
+    assert_equal(expect, headers)
+    assert ! body.parser.keepalive?
+    _, status = Process.waitpid2(pid)
+    assert status.success?
+    tmp = []
+    pid = fork { @s << "hello" }
+    @s.close
+    assert_nothing_raised { body.each { |chunk| tmp << chunk.dup } }
+    assert_equal %w(hello), tmp
+    assert_equal(expect, headers)
+    _, status = Process.waitpid2(pid)
+    assert status.success?
+    body.close
+    assert @c.closed?
+  end
+
+  def test_trailers_burpy
+    pid = fork do
+      @s << "HTTP/1.1 200 OK\r\nTrailer: Foo\r\n"
+      @s << "Transfer-Encoding: chunked\r\n\r\n"
+    end
+    @session = Kcar::Session.new(@c)
+    status, headers, body = @session.read
+    assert_equal status, "200 OK"
+    expect = {
+      "Trailer" => "Foo",
+      "Transfer-Encoding" => "chunked",
+    }
+    assert_equal(expect, headers)
+    assert body.parser.keepalive?
+    _, status = Process.waitpid2(pid)
+    assert status.success?
+    tmp = []
+    pid = fork { @s << "5\r\nhello\r\n0\r\nFoo: bar" }
+    rd, wr = IO.pipe
+    crlf_pid = fork do
+      wr.close
+      @s << rd.sysread(4)
+    end
+    rd.close
+    assert_nothing_raised do
+      first = true
+      body.each do |chunk|
+        tmp << chunk.dup
+        if first
+          first = false
+          wr.syswrite "\r\n\r\n"
+        end
+      end
+    end
+    assert_equal %w(hello), tmp
+    _, status = Process.waitpid2(pid)
+    assert status.success?
+    _, status = Process.waitpid2(crlf_pid)
+    assert status.success?
+    expect['Foo'] = 'bar'
+    assert_equal(expect, headers)
+    body.close
+    assert ! @c.closed?
+  end
+
+  def test_pass_through_trailers_burpy
+    pid = fork do
+      @s << "HTTP/1.1 200 OK\r\nTrailer: Foo\r\n"
+      @s << "Transfer-Encoding: chunked\r\n\r\n"
+    end
+    @session = Kcar::Session.new(@c, false)
+    status, headers, body = @session.read
+    assert_equal status, "200 OK"
+    expect = {
+      "Trailer" => "Foo",
+      "Transfer-Encoding" => "chunked",
+    }
+    assert_equal(expect, headers)
+    assert body.parser.keepalive?
+    _, status = Process.waitpid2(pid)
+    assert status.success?
+    tmp = []
+    pid = fork { @s << "5\r\nhello\r\n0\r\nFoo: bar" }
+    rd, wr = IO.pipe
+    crlf_pid = fork do
+      wr.close
+      @s << rd.sysread(4)
+    end
+    rd.close
+    assert_nothing_raised do
+      first = true
+      body.each do |chunk|
+        tmp << chunk.dup
+        if first
+          first = false
+          wr.syswrite "\r\n\r\n"
+        end
+      end
+    end
+    assert_equal ["5\r\n", "hello\r\n", "0\r\n", "Foo: bar\r\n\r\n"], tmp
+    _, status = Process.waitpid2(pid)
+    assert status.success?
+    _, status = Process.waitpid2(crlf_pid)
+    assert status.success?
+    expect['Foo'] = 'bar'
+    assert_equal(expect, headers)
+    body.close
+    assert ! @c.closed?
+  end
+
+  def test_identity_burpy
+    pid = fork { @s << "HTTP/1.1 200 OK\r\nContent-Length: 5\r\n\r\n" }
+    @session = Kcar::Session.new(@c)
+    status, headers, body = @session.read
+    assert_equal status, "200 OK"
+    expect = { "Content-Length" => '5' }
+    assert_equal(expect, headers)
+    assert body.parser.keepalive?
+    _, status = Process.waitpid2(pid)
+    assert status.success?
+    tmp = []
+    pid = fork { @s << "h" }
+    rd, wr = IO.pipe
+    crlf_pid = fork do
+      wr.close
+      @s << rd.sysread(4)
+    end
+    rd.close
+    assert_nothing_raised do
+      first = true
+      body.each do |chunk|
+        tmp << chunk.dup
+        if first
+          first = false
+          wr.syswrite "ello"
+        end
+      end
+    end
+    assert_equal %w(h ello), tmp
+    _, status = Process.waitpid2(pid)
+    assert status.success?
+    _, status = Process.waitpid2(crlf_pid)
+    assert status.success?
+    assert_equal(expect, headers)
+    body.close
+    assert ! @c.closed?
+  end
+
+end