unicorn.git  about / heads / tags
Rack HTTP server for Unix and fast clients
blob 67fe43b8e15a1f08a008dac5de209edd7fb66e3f 4425 bytes (raw)
$ git show v0.9.0:test/unit/test_chunked_reader.rb	# shows this blob on the CLI

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
 
require 'test/unit'
require 'unicorn'
require 'unicorn/http11'
require 'tempfile'
require 'io/nonblock'
require 'digest/sha1'

class TestChunkedReader < Test::Unit::TestCase

  def setup
    @env = {}
    @rd, @wr = IO.pipe
    @rd.binmode
    @wr.binmode
    @rd.sync = @wr.sync = true
    @start_pid = $$
  end

  def teardown
    return if $$ != @start_pid
    @rd.close rescue nil
    @wr.close rescue nil
    begin
      Process.wait
    rescue Errno::ECHILD
      break
    end while true
  end

  def test_error
    cr = bin_reader("8\r\nasdfasdf\r\n8\r\nasdfasdfa#{'a' * 1024}")
    a = nil
    assert_nothing_raised { a = cr.readpartial(8192) }
    assert_equal 'asdfasdf', a
    assert_nothing_raised { a = cr.readpartial(8192) }
    assert_equal 'asdfasdf', a
    assert_raises(Unicorn::HttpParserError) { cr.readpartial(8192) }
  end

  def test_eof1
    cr = bin_reader("0\r\n")
    assert_raises(EOFError) { cr.readpartial(8192) }
  end

  def test_eof2
    cr = bin_reader("0\r\n\r\n")
    assert_raises(EOFError) { cr.readpartial(8192) }
  end

  def test_readpartial1
    cr = bin_reader("4\r\nasdf\r\n0\r\n")
    assert_equal 'asdf', cr.readpartial(8192)
    assert_raises(EOFError) { cr.readpartial(8192) }
  end

  def test_gets1
    cr = bin_reader("4\r\nasdf\r\n0\r\n")
    STDOUT.sync = true
    assert_equal 'asdf', cr.gets
    assert_raises(EOFError) { cr.readpartial(8192) }
  end

  def test_gets2
    cr = bin_reader("4\r\nasd\n\r\n0\r\n\r\n")
    assert_equal "asd\n", cr.gets
    assert_nil cr.gets
  end

  def test_gets3
    max = Unicorn::Const::CHUNK_SIZE * 2
    str = ('a' * max).freeze
    first = 5
    last = str.size - first
    cr = bin_reader(
      "#{'%x' % first}\r\n#{str[0, first]}\r\n" \
      "#{'%x' % last}\r\n#{str[-last, last]}\r\n" \
      "0\r\n")
    assert_equal str, cr.gets
    assert_nil cr.gets
  end

  def test_readpartial_gets_mixed1
    max = Unicorn::Const::CHUNK_SIZE * 2
    str = ('a' * max).freeze
    first = 5
    last = str.size - first
    cr = bin_reader(
      "#{'%x' % first}\r\n#{str[0, first]}\r\n" \
      "#{'%x' % last}\r\n#{str[-last, last]}\r\n" \
      "0\r\n")
    partial = cr.readpartial(16384)
    assert String === partial

    len = max - partial.size
    assert_equal(str[-len, len], cr.gets)
    assert_raises(EOFError) { cr.readpartial(1) }
    assert_nil cr.gets
  end

  def test_gets_mixed_readpartial
    max = 10
    str = ("z\n" * max).freeze
    first = 5
    last = str.size - first
    cr = bin_reader(
      "#{'%x' % first}\r\n#{str[0, first]}\r\n" \
      "#{'%x' % last}\r\n#{str[-last, last]}\r\n" \
      "0\r\n")
    assert_equal("z\n", cr.gets)
    assert_equal("z\n", cr.gets)
  end

  def test_dd
    cr = bin_reader("6\r\nhello\n\r\n")
    tmp = Tempfile.new('test_dd')
    tmp.sync = true

    pid = fork {
      crd, cwr = IO.pipe
      crd.binmode
      cwr.binmode
      crd.sync = cwr.sync = true

      pid = fork {
        STDOUT.reopen(cwr)
        crd.close
        cwr.close
        exec('dd', 'if=/dev/urandom', 'bs=93390', 'count=16')
      }
      cwr.close
      begin
        buf = crd.readpartial(16384)
        tmp.write(buf)
        @wr.write("#{'%x' % buf.size}\r\n#{buf}\r\n")
      rescue EOFError
        @wr.write("0\r\n\r\n")
        Process.waitpid(pid)
        exit 0
      end while true
    }
    assert_equal "hello\n", cr.gets
    sha1 = Digest::SHA1.new
    buf = Unicorn::Z.dup
    begin
      cr.readpartial(16384, buf)
      sha1.update(buf)
    rescue EOFError
      break
    end while true

    assert_nothing_raised { Process.waitpid(pid) }
    sha1_file = Digest::SHA1.new
    File.open(tmp.path, 'rb') { |fp|
      while fp.read(16384, buf)
        sha1_file.update(buf)
      end
    }
    assert_equal sha1_file.hexdigest, sha1.hexdigest
  end

  def test_trailer
    @env['HTTP_TRAILER'] = 'Content-MD5'
    pid = fork { @wr.syswrite("Content-MD5: asdf\r\n") }
    cr = bin_reader("8\r\nasdfasdf\r\n8\r\nasdfasdf\r\n0\r\n")
    assert_equal 'asdfasdf', cr.readpartial(4096)
    assert_equal 'asdfasdf', cr.readpartial(4096)
    assert_raises(EOFError) { cr.readpartial(4096) }
    pid, status = Process.waitpid2(pid)
    assert status.success?
    assert_equal 'asdf', @env['HTTP_CONTENT_MD5']
  end

private

  def bin_reader(buf)
    buf.force_encoding(Encoding::BINARY) if buf.respond_to?(:force_encoding)
    Unicorn::ChunkedReader.new(@env, @rd, buf)
  end

end

git clone https://yhbt.net/unicorn.git