rack.git  about / heads / tags
a modular Ruby webserver interface
blob d028b3dec60bfe521743d10e747d86928c1df535 4855 bytes (raw)
$ git show chunk:test/spec_conditional_get.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
 
# frozen_string_literal: true

require_relative 'helper'
require 'time'

separate_testing do
  require_relative '../lib/rack/conditional_get'
  require_relative '../lib/rack/lint'
  require_relative '../lib/rack/mock_request'
end

describe Rack::ConditionalGet do
  def conditional_get(app)
    Rack::Lint.new Rack::ConditionalGet.new(app)
  end

  it "set a 304 status and truncate body when if-modified-since hits" do
    timestamp = Time.now.httpdate
    app = conditional_get(lambda { |env|
      [200, { 'last-modified' => timestamp }, ['TEST']] })

    response = Rack::MockRequest.new(app).
      get("/", 'HTTP_IF_MODIFIED_SINCE' => timestamp)

    response.status.must_equal 304
    response.body.must_be :empty?
  end

  it "set a 304 status and truncate body when if-modified-since hits and is higher than current time" do
    app = conditional_get(lambda { |env|
      [200, { 'last-modified' => (Time.now - 3600).httpdate }, ['TEST']] })

    response = Rack::MockRequest.new(app).
      get("/", 'HTTP_IF_MODIFIED_SINCE' => Time.now.httpdate)

    response.status.must_equal 304
    response.body.must_be :empty?
  end

  it "closes bodies" do
    body = Object.new
    def body.each; yield 'TEST' end
    closed = false
    body.define_singleton_method(:close){closed = true}
    app = conditional_get(lambda { |env|
      [200, { 'last-modified' => (Time.now - 3600).httpdate }, body] })

    response = Rack::MockRequest.new(app).
      get("/", 'HTTP_IF_MODIFIED_SINCE' => Time.now.httpdate)

    response.status.must_equal 304
    response.body.must_be :empty?
    closed.must_equal true
  end

  it "set a 304 status and truncate body when if-none-match hits" do
    app = conditional_get(lambda { |env|
      [200, { 'etag' => '1234' }, ['TEST']] })

    response = Rack::MockRequest.new(app).
      get("/", 'HTTP_IF_NONE_MATCH' => '1234')

    response.status.must_equal 304
    response.body.must_be :empty?
  end

  it "set a 304 status and truncate body when if-none-match hits but if-modified-since is after last-modified" do
    app = conditional_get(lambda { |env|
      [200, { 'last-modified' => (Time.now + 3600).httpdate, 'etag' => '1234', 'content-type' => 'text/plain' }, ['TEST']] })

    response = Rack::MockRequest.new(app).
      get("/", 'HTTP_IF_MODIFIED_SINCE' => Time.now.httpdate, 'HTTP_IF_NONE_MATCH' => '1234')

    response.status.must_equal 304
    response.body.must_be :empty?
  end

  it "not set a 304 status if last-modified is too short" do
    app = conditional_get(lambda { |env|
      [200, { 'last-modified' => '1234', 'content-type' => 'text/plain' }, ['TEST']] })

    response = Rack::MockRequest.new(app).
      get("/", 'HTTP_IF_MODIFIED_SINCE' => Time.now.httpdate)

    response.status.must_equal 200
    response.body.must_equal 'TEST'
  end

  it "not set a 304 status if if-modified-since hits but etag does not" do
    timestamp = Time.now.httpdate
    app = conditional_get(lambda { |env|
      [200, { 'last-modified' => timestamp, 'etag' => '1234', 'content-type' => 'text/plain' }, ['TEST']] })

    response = Rack::MockRequest.new(app).
      get("/", 'HTTP_IF_MODIFIED_SINCE' => timestamp, 'HTTP_IF_NONE_MATCH' => '4321')

    response.status.must_equal 200
    response.body.must_equal 'TEST'
  end

  it "set a 304 status and truncate body when both if-none-match and if-modified-since hits" do
    timestamp = Time.now.httpdate
    app = conditional_get(lambda { |env|
      [200, { 'last-modified' => timestamp, 'etag' => '1234' }, ['TEST']] })

    response = Rack::MockRequest.new(app).
      get("/", 'HTTP_IF_MODIFIED_SINCE' => timestamp, 'HTTP_IF_NONE_MATCH' => '1234')

    response.status.must_equal 304
    response.body.must_be :empty?
  end

  it "not affect non-GET/HEAD requests" do
    app = conditional_get(lambda { |env|
      [200, { 'etag' => '1234', 'content-type' => 'text/plain' }, ['TEST']] })

    response = Rack::MockRequest.new(app).
      post("/", 'HTTP_IF_NONE_MATCH' => '1234')

    response.status.must_equal 200
    response.body.must_equal 'TEST'
  end

  it "not affect non-200 requests" do
    app = conditional_get(lambda { |env|
      [302, { 'etag' => '1234', 'content-type' => 'text/plain' }, ['TEST']] })

    response = Rack::MockRequest.new(app).
      get("/", 'HTTP_IF_NONE_MATCH' => '1234')

    response.status.must_equal 302
    response.body.must_equal 'TEST'
  end

  it "not affect requests with malformed HTTP_IF_NONE_MATCH" do
    bad_timestamp = Time.now.strftime('%Y-%m-%d %H:%M:%S %z')
    app = conditional_get(lambda { |env|
      [200, { 'last-modified' => (Time.now - 3600).httpdate, 'content-type' => 'text/plain' }, ['TEST']] })

    response = Rack::MockRequest.new(app).
      get("/", 'HTTP_IF_MODIFIED_SINCE' => bad_timestamp)

    response.status.must_equal 200
    response.body.must_equal 'TEST'
  end

end

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