/vendor/bundle/jruby/2.1/gems/rack-1.5.2/test/spec_deflater.rb

https://github.com/delowong/logstash · Ruby · 204 lines · 168 code · 35 blank · 1 comment · 4 complexity · 680f934fa360cb12e8df28b5cea2cbc7 MD5 · raw file

  1. require 'stringio'
  2. require 'time' # for Time#httpdate
  3. require 'rack/deflater'
  4. require 'rack/lint'
  5. require 'rack/mock'
  6. require 'zlib'
  7. describe Rack::Deflater do
  8. def deflater(app)
  9. Rack::Lint.new Rack::Deflater.new(app)
  10. end
  11. def build_response(status, body, accept_encoding, headers = {})
  12. body = [body] if body.respond_to? :to_str
  13. app = lambda do |env|
  14. res = [status, {}, body]
  15. res[1]["Content-Type"] = "text/plain" unless res[0] == 304
  16. res
  17. end
  18. request = Rack::MockRequest.env_for("", headers.merge("HTTP_ACCEPT_ENCODING" => accept_encoding))
  19. response = deflater(app).call(request)
  20. return response
  21. end
  22. def inflate(buf)
  23. inflater = Zlib::Inflate.new(-Zlib::MAX_WBITS)
  24. inflater.inflate(buf) << inflater.finish
  25. end
  26. should "be able to deflate bodies that respond to each" do
  27. body = Object.new
  28. class << body; def each; yield("foo"); yield("bar"); end; end
  29. response = build_response(200, body, "deflate")
  30. response[0].should.equal(200)
  31. response[1].should.equal({
  32. "Content-Encoding" => "deflate",
  33. "Vary" => "Accept-Encoding",
  34. "Content-Type" => "text/plain"
  35. })
  36. buf = ''
  37. response[2].each { |part| buf << part }
  38. inflate(buf).should.equal("foobar")
  39. end
  40. should "flush deflated chunks to the client as they become ready" do
  41. body = Object.new
  42. class << body; def each; yield("foo"); yield("bar"); end; end
  43. response = build_response(200, body, "deflate")
  44. response[0].should.equal(200)
  45. response[1].should.equal({
  46. "Content-Encoding" => "deflate",
  47. "Vary" => "Accept-Encoding",
  48. "Content-Type" => "text/plain"
  49. })
  50. buf = []
  51. inflater = Zlib::Inflate.new(-Zlib::MAX_WBITS)
  52. response[2].each { |part| buf << inflater.inflate(part) }
  53. buf << inflater.finish
  54. buf.delete_if { |part| part.empty? }
  55. buf.join.should.equal("foobar")
  56. end
  57. # TODO: This is really just a special case of the above...
  58. should "be able to deflate String bodies" do
  59. response = build_response(200, "Hello world!", "deflate")
  60. response[0].should.equal(200)
  61. response[1].should.equal({
  62. "Content-Encoding" => "deflate",
  63. "Vary" => "Accept-Encoding",
  64. "Content-Type" => "text/plain"
  65. })
  66. buf = ''
  67. response[2].each { |part| buf << part }
  68. inflate(buf).should.equal("Hello world!")
  69. end
  70. should "be able to gzip bodies that respond to each" do
  71. body = Object.new
  72. class << body; def each; yield("foo"); yield("bar"); end; end
  73. response = build_response(200, body, "gzip")
  74. response[0].should.equal(200)
  75. response[1].should.equal({
  76. "Content-Encoding" => "gzip",
  77. "Vary" => "Accept-Encoding",
  78. "Content-Type" => "text/plain"
  79. })
  80. buf = ''
  81. response[2].each { |part| buf << part }
  82. io = StringIO.new(buf)
  83. gz = Zlib::GzipReader.new(io)
  84. gz.read.should.equal("foobar")
  85. gz.close
  86. end
  87. should "flush gzipped chunks to the client as they become ready" do
  88. body = Object.new
  89. class << body; def each; yield("foo"); yield("bar"); end; end
  90. response = build_response(200, body, "gzip")
  91. response[0].should.equal(200)
  92. response[1].should.equal({
  93. "Content-Encoding" => "gzip",
  94. "Vary" => "Accept-Encoding",
  95. "Content-Type" => "text/plain"
  96. })
  97. buf = []
  98. inflater = Zlib::Inflate.new(Zlib::MAX_WBITS + 32)
  99. response[2].each { |part| buf << inflater.inflate(part) }
  100. buf << inflater.finish
  101. buf.delete_if { |part| part.empty? }
  102. buf.join.should.equal("foobar")
  103. end
  104. should "be able to fallback to no deflation" do
  105. response = build_response(200, "Hello world!", "superzip")
  106. response[0].should.equal(200)
  107. response[1].should.equal({ "Vary" => "Accept-Encoding", "Content-Type" => "text/plain" })
  108. response[2].to_enum.to_a.should.equal(["Hello world!"])
  109. end
  110. should "be able to skip when there is no response entity body" do
  111. response = build_response(304, [], "gzip")
  112. response[0].should.equal(304)
  113. response[1].should.equal({})
  114. response[2].to_enum.to_a.should.equal([])
  115. end
  116. should "handle the lack of an acceptable encoding" do
  117. response1 = build_response(200, "Hello world!", "identity;q=0", "PATH_INFO" => "/")
  118. response1[0].should.equal(406)
  119. response1[1].should.equal({"Content-Type" => "text/plain", "Content-Length" => "71"})
  120. response1[2].to_enum.to_a.should.equal(["An acceptable encoding for the requested resource / could not be found."])
  121. response2 = build_response(200, "Hello world!", "identity;q=0", "SCRIPT_NAME" => "/foo", "PATH_INFO" => "/bar")
  122. response2[0].should.equal(406)
  123. response2[1].should.equal({"Content-Type" => "text/plain", "Content-Length" => "78"})
  124. response2[2].to_enum.to_a.should.equal(["An acceptable encoding for the requested resource /foo/bar could not be found."])
  125. end
  126. should "handle gzip response with Last-Modified header" do
  127. last_modified = Time.now.httpdate
  128. app = lambda { |env| [200, { "Content-Type" => "text/plain", "Last-Modified" => last_modified }, ["Hello World!"]] }
  129. request = Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => "gzip")
  130. response = deflater(app).call(request)
  131. response[0].should.equal(200)
  132. response[1].should.equal({
  133. "Content-Encoding" => "gzip",
  134. "Vary" => "Accept-Encoding",
  135. "Last-Modified" => last_modified,
  136. "Content-Type" => "text/plain"
  137. })
  138. buf = ''
  139. response[2].each { |part| buf << part }
  140. io = StringIO.new(buf)
  141. gz = Zlib::GzipReader.new(io)
  142. gz.read.should.equal("Hello World!")
  143. gz.close
  144. end
  145. should "do nothing when no-transform Cache-Control directive present" do
  146. app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'Cache-Control' => 'no-transform'}, ['Hello World!']] }
  147. request = Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => "gzip")
  148. response = deflater(app).call(request)
  149. response[0].should.equal(200)
  150. response[1].should.not.include "Content-Encoding"
  151. response[2].to_enum.to_a.join.should.equal("Hello World!")
  152. end
  153. should "do nothing when Content-Encoding already present" do
  154. app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'Content-Encoding' => 'gzip'}, ['Hello World!']] }
  155. request = Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => "gzip")
  156. response = deflater(app).call(request)
  157. response[0].should.equal(200)
  158. response[2].to_enum.to_a.join.should.equal("Hello World!")
  159. end
  160. should "deflate when Content-Encoding is identity" do
  161. app = lambda { |env| [200, {'Content-Type' => 'text/plain', 'Content-Encoding' => 'identity'}, ['Hello World!']] }
  162. request = Rack::MockRequest.env_for("", "HTTP_ACCEPT_ENCODING" => "deflate")
  163. response = deflater(app).call(request)
  164. response[0].should.equal(200)
  165. buf = ''
  166. response[2].each { |part| buf << part }
  167. inflate(buf).should.equal("Hello World!")
  168. end
  169. end