spec_response.rb 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. require 'rack/response'
  2. require 'stringio'
  3. describe Rack::Response do
  4. should "have sensible default values" do
  5. response = Rack::Response.new
  6. status, header, body = response.finish
  7. status.should.equal 200
  8. header.should.equal "Content-Type" => "text/html"
  9. body.each { |part|
  10. part.should.equal ""
  11. }
  12. response = Rack::Response.new
  13. status, header, body = *response
  14. status.should.equal 200
  15. header.should.equal "Content-Type" => "text/html"
  16. body.each { |part|
  17. part.should.equal ""
  18. }
  19. end
  20. it "can be written to" do
  21. response = Rack::Response.new
  22. _, _, body = response.finish do
  23. response.write "foo"
  24. response.write "bar"
  25. response.write "baz"
  26. end
  27. parts = []
  28. body.each { |part| parts << part }
  29. parts.should.equal ["foo", "bar", "baz"]
  30. end
  31. it "can set and read headers" do
  32. response = Rack::Response.new
  33. response["Content-Type"].should.equal "text/html"
  34. response["Content-Type"] = "text/plain"
  35. response["Content-Type"].should.equal "text/plain"
  36. end
  37. it "can override the initial Content-Type with a different case" do
  38. response = Rack::Response.new("", 200, "content-type" => "text/plain")
  39. response["Content-Type"].should.equal "text/plain"
  40. end
  41. it "can set cookies" do
  42. response = Rack::Response.new
  43. response.set_cookie "foo", "bar"
  44. response["Set-Cookie"].should.equal "foo=bar"
  45. response.set_cookie "foo2", "bar2"
  46. response["Set-Cookie"].should.equal ["foo=bar", "foo2=bar2"].join("\n")
  47. response.set_cookie "foo3", "bar3"
  48. response["Set-Cookie"].should.equal ["foo=bar", "foo2=bar2", "foo3=bar3"].join("\n")
  49. end
  50. it "can set cookies with the same name for multiple domains" do
  51. response = Rack::Response.new
  52. response.set_cookie "foo", {:value => "bar", :domain => "sample.example.com"}
  53. response.set_cookie "foo", {:value => "bar", :domain => ".example.com"}
  54. response["Set-Cookie"].should.equal ["foo=bar; domain=sample.example.com", "foo=bar; domain=.example.com"].join("\n")
  55. end
  56. it "formats the Cookie expiration date accordingly to RFC 2109" do
  57. response = Rack::Response.new
  58. response.set_cookie "foo", {:value => "bar", :expires => Time.now+10}
  59. response["Set-Cookie"].should.match(
  60. /expires=..., \d\d-...-\d\d\d\d \d\d:\d\d:\d\d .../)
  61. end
  62. it "can set secure cookies" do
  63. response = Rack::Response.new
  64. response.set_cookie "foo", {:value => "bar", :secure => true}
  65. response["Set-Cookie"].should.equal "foo=bar; secure"
  66. end
  67. it "can set http only cookies" do
  68. response = Rack::Response.new
  69. response.set_cookie "foo", {:value => "bar", :httponly => true}
  70. response["Set-Cookie"].should.equal "foo=bar; HttpOnly"
  71. end
  72. it "can delete cookies" do
  73. response = Rack::Response.new
  74. response.set_cookie "foo", "bar"
  75. response.set_cookie "foo2", "bar2"
  76. response.delete_cookie "foo"
  77. response["Set-Cookie"].should.equal [
  78. "foo2=bar2",
  79. "foo=; expires=Thu, 01-Jan-1970 00:00:00 GMT"
  80. ].join("\n")
  81. end
  82. it "can delete cookies with the same name from multiple domains" do
  83. response = Rack::Response.new
  84. response.set_cookie "foo", {:value => "bar", :domain => "sample.example.com"}
  85. response.set_cookie "foo", {:value => "bar", :domain => ".example.com"}
  86. response["Set-Cookie"].should.equal ["foo=bar; domain=sample.example.com", "foo=bar; domain=.example.com"].join("\n")
  87. response.delete_cookie "foo", :domain => ".example.com"
  88. response["Set-Cookie"].should.equal ["foo=bar; domain=sample.example.com", "foo=; domain=.example.com; expires=Thu, 01-Jan-1970 00:00:00 GMT"].join("\n")
  89. response.delete_cookie "foo", :domain => "sample.example.com"
  90. response["Set-Cookie"].should.equal ["foo=; domain=.example.com; expires=Thu, 01-Jan-1970 00:00:00 GMT",
  91. "foo=; domain=sample.example.com; expires=Thu, 01-Jan-1970 00:00:00 GMT"].join("\n")
  92. end
  93. it "can delete cookies with the same name with different paths" do
  94. response = Rack::Response.new
  95. response.set_cookie "foo", {:value => "bar", :path => "/"}
  96. response.set_cookie "foo", {:value => "bar", :path => "/path"}
  97. response["Set-Cookie"].should.equal ["foo=bar; path=/",
  98. "foo=bar; path=/path"].join("\n")
  99. response.delete_cookie "foo", :path => "/path"
  100. response["Set-Cookie"].should.equal ["foo=bar; path=/",
  101. "foo=; path=/path; expires=Thu, 01-Jan-1970 00:00:00 GMT"].join("\n")
  102. end
  103. it "can do redirects" do
  104. response = Rack::Response.new
  105. response.redirect "/foo"
  106. status, header, body = response.finish
  107. status.should.equal 302
  108. header["Location"].should.equal "/foo"
  109. response = Rack::Response.new
  110. response.redirect "/foo", 307
  111. status, header, body = response.finish
  112. status.should.equal 307
  113. end
  114. it "has a useful constructor" do
  115. r = Rack::Response.new("foo")
  116. status, header, body = r.finish
  117. str = ""; body.each { |part| str << part }
  118. str.should.equal "foo"
  119. r = Rack::Response.new(["foo", "bar"])
  120. status, header, body = r.finish
  121. str = ""; body.each { |part| str << part }
  122. str.should.equal "foobar"
  123. object_with_each = Object.new
  124. def object_with_each.each
  125. yield "foo"
  126. yield "bar"
  127. end
  128. r = Rack::Response.new(object_with_each)
  129. r.write "foo"
  130. status, header, body = r.finish
  131. str = ""; body.each { |part| str << part }
  132. str.should.equal "foobarfoo"
  133. r = Rack::Response.new([], 500)
  134. r.status.should.equal 500
  135. r = Rack::Response.new([], "200 OK")
  136. r.status.should.equal 200
  137. end
  138. it "has a constructor that can take a block" do
  139. r = Rack::Response.new { |res|
  140. res.status = 404
  141. res.write "foo"
  142. }
  143. status, _, body = r.finish
  144. str = ""; body.each { |part| str << part }
  145. str.should.equal "foo"
  146. status.should.equal 404
  147. end
  148. it "doesn't return invalid responses" do
  149. r = Rack::Response.new(["foo", "bar"], 204)
  150. _, header, body = r.finish
  151. str = ""; body.each { |part| str << part }
  152. str.should.be.empty
  153. header["Content-Type"].should.equal nil
  154. header['Content-Length'].should.equal nil
  155. lambda {
  156. Rack::Response.new(Object.new)
  157. }.should.raise(TypeError).
  158. message.should =~ /stringable or iterable required/
  159. end
  160. it "knows if it's empty" do
  161. r = Rack::Response.new
  162. r.should.be.empty
  163. r.write "foo"
  164. r.should.not.be.empty
  165. r = Rack::Response.new
  166. r.should.be.empty
  167. r.finish
  168. r.should.be.empty
  169. r = Rack::Response.new
  170. r.should.be.empty
  171. r.finish { }
  172. r.should.not.be.empty
  173. end
  174. should "provide access to the HTTP status" do
  175. res = Rack::Response.new
  176. res.status = 200
  177. res.should.be.successful
  178. res.should.be.ok
  179. res.status = 400
  180. res.should.not.be.successful
  181. res.should.be.client_error
  182. res.should.be.bad_request
  183. res.status = 404
  184. res.should.not.be.successful
  185. res.should.be.client_error
  186. res.should.be.not_found
  187. res.status = 405
  188. res.should.not.be.successful
  189. res.should.be.client_error
  190. res.should.be.method_not_allowed
  191. res.status = 422
  192. res.should.not.be.successful
  193. res.should.be.client_error
  194. res.should.be.unprocessable
  195. res.status = 501
  196. res.should.not.be.successful
  197. res.should.be.server_error
  198. res.status = 307
  199. res.should.be.redirect
  200. end
  201. should "provide access to the HTTP headers" do
  202. res = Rack::Response.new
  203. res["Content-Type"] = "text/yaml"
  204. res.should.include "Content-Type"
  205. res.headers["Content-Type"].should.equal "text/yaml"
  206. res["Content-Type"].should.equal "text/yaml"
  207. res.content_type.should.equal "text/yaml"
  208. res.content_length.should.be.nil
  209. res.location.should.be.nil
  210. end
  211. it "does not add or change Content-Length when #finish()ing" do
  212. res = Rack::Response.new
  213. res.status = 200
  214. res.finish
  215. res.headers["Content-Length"].should.be.nil
  216. res = Rack::Response.new
  217. res.status = 200
  218. res.headers["Content-Length"] = "10"
  219. res.finish
  220. res.headers["Content-Length"].should.equal "10"
  221. end
  222. it "updates Content-Length when body appended to using #write" do
  223. res = Rack::Response.new
  224. res.status = 200
  225. res.headers["Content-Length"].should.be.nil
  226. res.write "Hi"
  227. res.headers["Content-Length"].should.equal "2"
  228. res.write " there"
  229. res.headers["Content-Length"].should.equal "8"
  230. end
  231. it "calls close on #body" do
  232. res = Rack::Response.new
  233. res.body = StringIO.new
  234. res.close
  235. res.body.should.be.closed
  236. end
  237. end