From 48e167317ea9d15c957af8e0e600cc837e46c0a4 Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Sat, 17 Sep 2011 14:27:26 -0700 Subject: [PATCH 01/47] properly implement If-Matches and If-None-Matches handling according to RFC 2616, fixes #355 --- README.rdoc | 18 ++ lib/sinatra/base.rb | 38 ++- test/helper.rb | 4 + test/helpers_test.rb | 641 ++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 647 insertions(+), 54 deletions(-) diff --git a/README.rdoc b/README.rdoc index bbbfe92754..a0c5317cde 100644 --- a/README.rdoc +++ b/README.rdoc @@ -1018,6 +1018,24 @@ try {rack-cache}[http://rtomayko.github.com/rack-cache/]: Use the :static_cache_control setting (see below) to add Cache-Control header info to static files. +According to RFC 2616 your application should behave differently if the +If-Matches of If-None-Matches header is set to * depending on whether +the resource requested is already in existence. Sinatra assumes resources for +safe (like get) and idempotent (like put) requests are already in existence, +whereas other resources (for instance for post requests), are treated as new +resources. You can change this behavior by passing in a :new_resource +option: + + get '/create' do + etag '', :new_resource => true + Article.create + erb :new_article + end + +If you still want to use a weak ETag, pass in a :kind option: + + etag '', :new_resource => true, :kind => :weak + === Sending Files For sending files, you can use the send_file helper method: diff --git a/lib/sinatra/base.rb b/lib/sinatra/base.rb index df51d3d39b..cf5a432b6c 100644 --- a/lib/sinatra/base.rb +++ b/lib/sinatra/base.rb @@ -355,8 +355,12 @@ def last_modified(time) return unless time time = time_for time response['Last-Modified'] = time.httpdate - # compare based on seconds since epoch - halt 304 if Time.httpdate(env['HTTP_IF_MODIFIED_SINCE']).to_i >= time.to_i + + unless env['HTTP_IF_NONE_MATCH'] + # compare based on seconds since epoch + since = Time.httpdate(env['HTTP_IF_MODIFIED_SINCE']).to_i + halt 304 if since >= time.to_i + end rescue ArgumentError end @@ -369,22 +373,36 @@ def last_modified(time) # When the current request includes an 'If-None-Match' header with a # matching etag, execution is immediately halted. If the request method is # GET or HEAD, a '304 Not Modified' response is sent. - def etag(value, kind = :strong) - raise ArgumentError, ":strong or :weak expected" unless [:strong,:weak].include?(kind) + def etag(value, options = {}) + # Before touching this code, please double check RFC 2616 14.24 and 14.26. + options = {:kind => options} unless Hash === options + kind = options[:kind] || :strong + new_resource = options.fetch(:new_resource) { request.post? } + + unless [:strong, :weak].include?(kind) + raise ArgumentError, ":strong or :weak expected" + end + value = '"%s"' % value value = 'W/' + value if kind == :weak response['ETag'] = value - if etags = env['HTTP_IF_NONE_MATCH'] - etags = etags.split(/\s*,\s*/) - if etags.include?(value) or etags.include?('*') - halt 304 if request.safe? - else - halt 412 unless request.safe? + if success? or status == 304 + if etag_matches? env['HTTP_IF_NONE_MATCH'], new_resource + halt(request.safe? ? 304 : 412) + end + + if env['HTTP_IF_MATCH'] + halt 412 unless etag_matches? env['HTTP_IF_MATCH'], new_resource end end end + def etag_matches?(list, new_resource = request.post?) + return !new_resource if list == '*' + list.to_s.split(/\s*,\s*/).include? response['ETag'] + end + # Sugar for redirect (example: redirect back) def back request.referer diff --git a/test/helper.rb b/test/helper.rb index 972b416bb2..1f061d49d9 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -72,6 +72,10 @@ def assert_body(value) assert_equal value.lstrip.gsub(/\s*\n\s*/, ""), body.lstrip.gsub(/\s*\n\s*/, "") end + def assert_status(expected) + assert_equal Integer(expected), Integer(status) + end + def assert_like(a,b) pattern = /id=['"][^"']*["']|\s+/ assert_equal a.strip.gsub(pattern, ""), b.strip.gsub(pattern, "") diff --git a/test/helpers_test.rb b/test/helpers_test.rb index ca6d1c82b3..46055dda3d 100644 --- a/test/helpers_test.rb +++ b/test/helpers_test.rb @@ -960,69 +960,622 @@ def obj.is_a?(thing) 60.is_a?(thing) end end describe 'etag' do - setup do - mock_app { - get '/' do - body { 'Hello World' } - etag 'FOO' - 'Boo!' + context "safe requests" do + it 'returns 200 for normal requests' do + mock_app do + get '/' do + etag 'foo' + 'ok' + end end - post '/' do - etag 'FOO' - 'Matches!' + get('/') + assert_status 200 + assert_body 'ok' + end + + context "If-None-Match" do + it 'returns 304 when If-None-Match is *' do + mock_app do + get '/' do + etag 'foo' + 'ok' + end + end + + get('/', {}, 'HTTP_IF_NONE_MATCH' => '*') + assert_status 304 + assert_body '' end - } - end - it 'sets the ETag header' do - get '/' - assert_equal '"FOO"', response['ETag'] - end + it 'returns 200 when If-None-Match is * for new resources' do + mock_app do + get '/' do + etag 'foo', :new_resource => true + 'ok' + end + end - it 'returns a body when conditional get misses' do - get '/' - assert_equal 200, status - assert_equal 'Boo!', body - end + get('/', {}, 'HTTP_IF_NONE_MATCH' => '*') + assert_status 200 + assert_body 'ok' + end - it 'returns a body when posting with no If-None-Match header' do - post '/' - assert_equal 200, status - assert_equal 'Matches!', body - end + it 'returns 304 when If-None-Match is * for existing resources' do + mock_app do + get '/' do + etag 'foo', :new_resource => false + 'ok' + end + end - it 'returns a body when conditional post matches' do - post '/', {}, { 'HTTP_IF_NONE_MATCH' => '"FOO"' } - assert_equal 200, status - assert_equal 'Matches!', body - end + get('/', {}, 'HTTP_IF_NONE_MATCH' => '*') + assert_status 304 + assert_body '' + end - it 'halts with 412 when conditional post misses' do - post '/', {}, { 'HTTP_IF_NONE_MATCH' => '"BAR"' } - assert_equal 412, status - assert_equal '', body + it 'returns 304 when If-None-Match is the etag' do + mock_app do + get '/' do + etag 'foo' + 'ok' + end + end + + get('/', {}, 'HTTP_IF_NONE_MATCH' => '"foo"') + assert_status 304 + assert_body '' + end + + it 'returns 304 when If-None-Match includes the etag' do + mock_app do + get '/' do + etag 'foo' + 'ok' + end + end + + get('/', {}, 'HTTP_IF_NONE_MATCH' => '"bar", "foo"') + assert_status 304 + assert_body '' + end + + it 'returns 200 when If-None-Match does not include the etag' do + mock_app do + get '/' do + etag 'foo' + 'ok' + end + end + + get('/', {}, 'HTTP_IF_NONE_MATCH' => '"bar"') + assert_status 200 + assert_body 'ok' + end + + it 'ignores If-Modified-Since if If-None-Match does not match' do + mock_app do + get '/' do + etag 'foo' + last_modified Time.at(0) + 'ok' + end + end + + get('/', {}, 'HTTP_IF_NONE_MATCH' => '"bar"') + assert_status 200 + assert_body 'ok' + end + + it 'does not change a status code other than 2xx or 304' do + mock_app do + get '/' do + status 499 + etag 'foo' + 'ok' + end + end + + get('/', {}, 'HTTP_IF_NONE_MATCH' => '"foo"') + assert_status 499 + assert_body 'ok' + end + + it 'does change 2xx status codes' do + mock_app do + get '/' do + status 299 + etag 'foo' + 'ok' + end + end + + get('/', {}, 'HTTP_IF_NONE_MATCH' => '"foo"') + assert_status 304 + assert_body '' + end + + it 'does not send a body on 304 status codes' do + mock_app do + get '/' do + status 304 + etag 'foo' + 'ok' + end + end + + get('/', {}, 'HTTP_IF_NONE_MATCH' => '"foo"') + assert_status 304 + assert_body '' + end + end + + context "If-Match" do + it 'returns 200 when If-Match is the etag' do + mock_app do + get '/' do + etag 'foo' + 'ok' + end + end + + get('/', {}, 'HTTP_IF_MATCH' => '"foo"') + assert_status 200 + assert_body 'ok' + end + + it 'returns 200 when If-Match includes the etag' do + mock_app do + get '/' do + etag 'foo' + 'ok' + end + end + + get('/', {}, 'HTTP_IF_MATCH' => '"foo", "bar"') + assert_status 200 + assert_body 'ok' + end + + it 'returns 200 when If-Match is *' do + mock_app do + get '/' do + etag 'foo' + 'ok' + end + end + + get('/', {}, 'HTTP_IF_MATCH' => '*') + assert_status 200 + assert_body 'ok' + end + + it 'returns 412 when If-Match is * for new resources' do + mock_app do + get '/' do + etag 'foo', :new_resource => true + 'ok' + end + end + + get('/', {}, 'HTTP_IF_MATCH' => '*') + assert_status 412 + assert_body '' + end + + it 'returns 200 when If-Match is * for existing resources' do + mock_app do + get '/' do + etag 'foo', :new_resource => false + 'ok' + end + end + + get('/', {}, 'HTTP_IF_MATCH' => '*') + assert_status 200 + assert_body 'ok' + end + + it 'returns 412 when If-Match does not include the etag' do + mock_app do + get '/' do + etag 'foo' + 'ok' + end + end + + get('/', {}, 'HTTP_IF_MATCH' => '"bar"') + assert_status 412 + assert_body '' + end + end end - it 'halts when a conditional GET matches' do - get '/', {}, { 'HTTP_IF_NONE_MATCH' => '"FOO"' } - assert_equal 304, status - assert_equal '', body + context "idempotent requests" do + it 'returns 200 for normal requests' do + mock_app do + put '/' do + etag 'foo' + 'ok' + end + end + + put('/') + assert_status 200 + assert_body 'ok' + end + + context "If-None-Match" do + it 'returns 412 when If-None-Match is *' do + mock_app do + put '/' do + etag 'foo' + 'ok' + end + end + + put('/', {}, 'HTTP_IF_NONE_MATCH' => '*') + assert_status 412 + assert_body '' + end + + it 'returns 200 when If-None-Match is * for new resources' do + mock_app do + put '/' do + etag 'foo', :new_resource => true + 'ok' + end + end + + put('/', {}, 'HTTP_IF_NONE_MATCH' => '*') + assert_status 200 + assert_body 'ok' + end + + it 'returns 412 when If-None-Match is * for existing resources' do + mock_app do + put '/' do + etag 'foo', :new_resource => false + 'ok' + end + end + + put('/', {}, 'HTTP_IF_NONE_MATCH' => '*') + assert_status 412 + assert_body '' + end + + it 'returns 412 when If-None-Match is the etag' do + mock_app do + put '/' do + etag 'foo' + 'ok' + end + end + + put('/', {}, 'HTTP_IF_NONE_MATCH' => '"foo"') + assert_status 412 + assert_body '' + end + + it 'returns 412 when If-None-Match includes the etag' do + mock_app do + put '/' do + etag 'foo' + 'ok' + end + end + + put('/', {}, 'HTTP_IF_NONE_MATCH' => '"bar", "foo"') + assert_status 412 + assert_body '' + end + + it 'returns 200 when If-None-Match does not include the etag' do + mock_app do + put '/' do + etag 'foo' + 'ok' + end + end + + put('/', {}, 'HTTP_IF_NONE_MATCH' => '"bar"') + assert_status 200 + assert_body 'ok' + end + + it 'ignores If-Modified-Since if If-None-Match does not match' do + mock_app do + put '/' do + etag 'foo' + last_modified Time.at(0) + 'ok' + end + end + + put('/', {}, 'HTTP_IF_NONE_MATCH' => '"bar"') + assert_status 200 + assert_body 'ok' + end + end + + context "If-Match" do + it 'returns 200 when If-Match is the etag' do + mock_app do + put '/' do + etag 'foo' + 'ok' + end + end + + put('/', {}, 'HTTP_IF_MATCH' => '"foo"') + assert_status 200 + assert_body 'ok' + end + + it 'returns 200 when If-Match includes the etag' do + mock_app do + put '/' do + etag 'foo' + 'ok' + end + end + + put('/', {}, 'HTTP_IF_MATCH' => '"foo", "bar"') + assert_status 200 + assert_body 'ok' + end + + it 'returns 200 when If-Match is *' do + mock_app do + put '/' do + etag 'foo' + 'ok' + end + end + + put('/', {}, 'HTTP_IF_MATCH' => '*') + assert_status 200 + assert_body 'ok' + end + + it 'returns 412 when If-Match is * for new resources' do + mock_app do + put '/' do + etag 'foo', :new_resource => true + 'ok' + end + end + + put('/', {}, 'HTTP_IF_MATCH' => '*') + assert_status 412 + assert_body '' + end + + it 'returns 200 when If-Match is * for existing resources' do + mock_app do + put '/' do + etag 'foo', :new_resource => false + 'ok' + end + end + + put('/', {}, 'HTTP_IF_MATCH' => '*') + assert_status 200 + assert_body 'ok' + end + + it 'returns 412 when If-Match does not include the etag' do + mock_app do + put '/' do + etag 'foo' + 'ok' + end + end + + put('/', {}, 'HTTP_IF_MATCH' => '"bar"') + assert_status 412 + assert_body '' + end + end end - it 'should handle multiple ETag values in If-None-Match header' do - get '/', {}, { 'HTTP_IF_NONE_MATCH' => '"BAR", *' } - assert_equal 304, status - assert_equal '', body + context "post requests" do + it 'returns 200 for normal requests' do + mock_app do + post '/' do + etag 'foo' + 'ok' + end + end + + post('/') + assert_status 200 + assert_body 'ok' + end + + context "If-None-Match" do + it 'returns 200 when If-None-Match is *' do + mock_app do + post '/' do + etag 'foo' + 'ok' + end + end + + post('/', {}, 'HTTP_IF_NONE_MATCH' => '*') + assert_status 200 + assert_body 'ok' + end + + it 'returns 200 when If-None-Match is * for new resources' do + mock_app do + post '/' do + etag 'foo', :new_resource => true + 'ok' + end + end + + post('/', {}, 'HTTP_IF_NONE_MATCH' => '*') + assert_status 200 + assert_body 'ok' + end + + it 'returns 412 when If-None-Match is * for existing resources' do + mock_app do + post '/' do + etag 'foo', :new_resource => false + 'ok' + end + end + + post('/', {}, 'HTTP_IF_NONE_MATCH' => '*') + assert_status 412 + assert_body '' + end + + it 'returns 412 when If-None-Match is the etag' do + mock_app do + post '/' do + etag 'foo' + 'ok' + end + end + + post('/', {}, 'HTTP_IF_NONE_MATCH' => '"foo"') + assert_status 412 + assert_body '' + end + + it 'returns 412 when If-None-Match includes the etag' do + mock_app do + post '/' do + etag 'foo' + 'ok' + end + end + + post('/', {}, 'HTTP_IF_NONE_MATCH' => '"bar", "foo"') + assert_status 412 + assert_body '' + end + + it 'returns 200 when If-None-Match does not include the etag' do + mock_app do + post '/' do + etag 'foo' + 'ok' + end + end + + post('/', {}, 'HTTP_IF_NONE_MATCH' => '"bar"') + assert_status 200 + assert_body 'ok' + end + + it 'ignores If-Modified-Since if If-None-Match does not match' do + mock_app do + post '/' do + etag 'foo' + last_modified Time.at(0) + 'ok' + end + end + + post('/', {}, 'HTTP_IF_NONE_MATCH' => '"bar"') + assert_status 200 + assert_body 'ok' + end + end + + context "If-Match" do + it 'returns 200 when If-Match is the etag' do + mock_app do + post '/' do + etag 'foo' + 'ok' + end + end + + post('/', {}, 'HTTP_IF_MATCH' => '"foo"') + assert_status 200 + assert_body 'ok' + end + + it 'returns 200 when If-Match includes the etag' do + mock_app do + post '/' do + etag 'foo' + 'ok' + end + end + + post('/', {}, 'HTTP_IF_MATCH' => '"foo", "bar"') + assert_status 200 + assert_body 'ok' + end + + it 'returns 412 when If-Match is *' do + mock_app do + post '/' do + etag 'foo' + 'ok' + end + end + + post('/', {}, 'HTTP_IF_MATCH' => '*') + assert_status 412 + assert_body '' + end + + it 'returns 412 when If-Match is * for new resources' do + mock_app do + post '/' do + etag 'foo', :new_resource => true + 'ok' + end + end + + post('/', {}, 'HTTP_IF_MATCH' => '*') + assert_status 412 + assert_body '' + end + + it 'returns 200 when If-Match is * for existing resources' do + mock_app do + post '/' do + etag 'foo', :new_resource => false + 'ok' + end + end + + post('/', {}, 'HTTP_IF_MATCH' => '*') + assert_status 200 + assert_body 'ok' + end + + it 'returns 412 when If-Match does not include the etag' do + mock_app do + post '/' do + etag 'foo' + 'ok' + end + end + + post('/', {}, 'HTTP_IF_MATCH' => '"bar"') + assert_status 412 + assert_body '' + end + end end it 'uses a weak etag with the :weak option' do - mock_app { + mock_app do get '/' do etag 'FOO', :weak "that's weak, dude." end - } + end get '/' assert_equal 'W/"FOO"', response['ETag'] end From f54f322b6576b6d9586a8d188679ecd7813b0c04 Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Sat, 17 Sep 2011 14:42:38 -0700 Subject: [PATCH 02/47] only halt execution in last_modified if status is currently 200 (to confrom with RFC 2616) --- CHANGES | 3 +++ lib/sinatra/base.rb | 2 +- test/helpers_test.rb | 14 ++++++++++++++ 3 files changed, 18 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index dc0ef77c82..5b869de94b 100644 --- a/CHANGES +++ b/CHANGES @@ -82,6 +82,9 @@ * Conditional requests on `etag` helper now work properly for unsafe HTTP methods. (Matthew Schinckel, Konstantin Haase) + * The `last_modified` helper does not stop execution and change the status code + if the status code is something different than 200. (Konstantin Haase) + * `Sinatra::Base.run!` now prints to stderr rather than stdout. (Andrew Armenia) diff --git a/lib/sinatra/base.rb b/lib/sinatra/base.rb index cf5a432b6c..8782b34509 100644 --- a/lib/sinatra/base.rb +++ b/lib/sinatra/base.rb @@ -356,7 +356,7 @@ def last_modified(time) time = time_for time response['Last-Modified'] = time.httpdate - unless env['HTTP_IF_NONE_MATCH'] + if status == 200 and not env['HTTP_IF_NONE_MATCH'] # compare based on seconds since epoch since = Time.httpdate(env['HTTP_IF_MODIFIED_SINCE']).to_i halt 304 if since >= time.to_i diff --git a/test/helpers_test.rb b/test/helpers_test.rb index 46055dda3d..566e2d374a 100644 --- a/test/helpers_test.rb +++ b/test/helpers_test.rb @@ -858,6 +858,20 @@ def obj.is_a?(thing) 60.is_a?(thing) end assert ! response['Last-Modified'] end + it 'does not change a status other than 200' do + mock_app do + get '/' do + status 299 + last_modified Time.at(0) + 'ok' + end + end + + get('/', {}, 'HTTP_IF_MODIFIED_SINCE' => 'Sun, 26 Sep 2030 23:43:52 GMT') + assert_status 299 + assert_body 'ok' + end + [Time.now, DateTime.now, Date.today, Time.now.to_i, Struct.new(:to_time).new(Time.now) ].each do |last_modified_time| describe "with #{last_modified_time.class.name}" do From 092157f6fbcb1b863fbf42757db22d76e94df628 Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Sat, 17 Sep 2011 15:11:32 -0700 Subject: [PATCH 03/47] add support for If-Unmodified-Since --- CHANGES | 2 ++ lib/sinatra/base.rb | 9 ++++++++- test/helpers_test.rb | 14 ++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 5b869de94b..c5b625044f 100644 --- a/CHANGES +++ b/CHANGES @@ -85,6 +85,8 @@ * The `last_modified` helper does not stop execution and change the status code if the status code is something different than 200. (Konstantin Haase) + * Added support for If-Unmodified-Since header. (Konstantin Haase) + * `Sinatra::Base.run!` now prints to stderr rather than stdout. (Andrew Armenia) diff --git a/lib/sinatra/base.rb b/lib/sinatra/base.rb index 8782b34509..5531d015df 100644 --- a/lib/sinatra/base.rb +++ b/lib/sinatra/base.rb @@ -355,12 +355,19 @@ def last_modified(time) return unless time time = time_for time response['Last-Modified'] = time.httpdate + return if env['HTTP_IF_NONE_MATCH'] - if status == 200 and not env['HTTP_IF_NONE_MATCH'] + if status == 200 and env['HTTP_IF_MODIFIED_SINCE'] # compare based on seconds since epoch since = Time.httpdate(env['HTTP_IF_MODIFIED_SINCE']).to_i halt 304 if since >= time.to_i end + + if (success? or status == 412) and env['HTTP_IF_UNMODIFIED_SINCE'] + # compare based on seconds since epoch + since = Time.httpdate(env['HTTP_IF_UNMODIFIED_SINCE']).to_i + halt 412 if since < time.to_i + end rescue ArgumentError end diff --git a/test/helpers_test.rb b/test/helpers_test.rb index 566e2d374a..f136190427 100644 --- a/test/helpers_test.rb +++ b/test/helpers_test.rb @@ -969,6 +969,20 @@ def obj.is_a?(thing) 60.is_a?(thing) end assert_equal '', body end end + + context "If-Unmodified-Since" do + it 'results in 200 if resource has not been modified' do + get '/', {}, { 'HTTP_IF_UNMODIFIED_SINCE' => 'Sun, 26 Sep 2030 23:43:52 GMT' } + assert_equal 200, status + assert_equal 'Boo!', body + end + + it 'results in 412 if resource has been modified' do + get '/', {}, { 'HTTP_IF_UNMODIFIED_SINCE' => Time.at(0).httpdate } + assert_equal 412, status + assert_equal '', body + end + end end end end From 596b5d408a5be9b795aca8b287862d5610a164ac Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Sat, 17 Sep 2011 15:12:39 -0700 Subject: [PATCH 04/47] make #etag_matches? private --- lib/sinatra/base.rb | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/sinatra/base.rb b/lib/sinatra/base.rb index 5531d015df..c62eab45cb 100644 --- a/lib/sinatra/base.rb +++ b/lib/sinatra/base.rb @@ -405,11 +405,6 @@ def etag(value, options = {}) end end - def etag_matches?(list, new_resource = request.post?) - return !new_resource if list == '*' - list.to_s.split(/\s*,\s*/).include? response['ETag'] - end - # Sugar for redirect (example: redirect back) def back request.referer @@ -470,6 +465,14 @@ def time_for(value) rescue Exception raise ArgumentError, "unable to convert #{value.inspect} to a Time object" end + + private + + # Helper method checking if a ETag value list includes the current ETag. + def etag_matches?(list, new_resource = request.post?) + return !new_resource if list == '*' + list.to_s.split(/\s*,\s*/).include? response['ETag'] + end end private From a90d9236b8f98c56495c8293dc600b57a4181114 Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Sat, 17 Sep 2011 15:15:19 -0700 Subject: [PATCH 05/47] fix typo --- README.rdoc | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/README.rdoc b/README.rdoc index a0c5317cde..fb5c82781e 100644 --- a/README.rdoc +++ b/README.rdoc @@ -1018,13 +1018,12 @@ try {rack-cache}[http://rtomayko.github.com/rack-cache/]: Use the :static_cache_control setting (see below) to add Cache-Control header info to static files. -According to RFC 2616 your application should behave differently if the -If-Matches of If-None-Matches header is set to * depending on whether -the resource requested is already in existence. Sinatra assumes resources for -safe (like get) and idempotent (like put) requests are already in existence, -whereas other resources (for instance for post requests), are treated as new -resources. You can change this behavior by passing in a :new_resource -option: +According to RFC 2616 your application should behave differently if the If-Match +of If-None-Match header is set to * depending on whether the resource +requested is already in existence. Sinatra assumes resources for safe (like get) +and idempotent (like put) requests are already in existence, whereas other +resources (for instance for post requests), are treated as new resources. You +can change this behavior by passing in a :new_resource option: get '/create' do etag '', :new_resource => true From f602a162b79eafd6a725d02753886e512e363c48 Mon Sep 17 00:00:00 2001 From: Gabriel Andretta Date: Sun, 18 Sep 2011 16:00:29 -0300 Subject: [PATCH 06/47] doc If-Match and If-None-Match in Spanish readme --- README.es.rdoc | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/README.es.rdoc b/README.es.rdoc index 5fc2191579..77c47fbd3b 100644 --- a/README.es.rdoc +++ b/README.es.rdoc @@ -1055,6 +1055,23 @@ Usá la configuración :static_cache_control para agregar el encabezado Cache-Control a archivos estáticos (ver la sección de configuración para más detalles). +De acuerdo con la RFC 2616 tu aplicación debería comportarse diferente si a las +cabeceras If-Match o If-None-Match se le asigna el valor * cuando el +recurso solicitado ya existe. Sinatra asume para peticiones seguras (como get) +e idempotentes (como put) que el recurso existe, mientras que para el resto +(como post), que no. Podes cambiar este comportamiento con la opción +:new_resource: + + get '/crear' do + etag '', :new_resource => true + Articulo.create + erb :nuevo_articulo + end + +Si querés seguir usando una weak ETag, indicalo con la opción :kind: + + etag '', :new_resource => true, :kind => :weak + === Enviando Archivos Para enviar archivos, podés usar el método send_file: From 0c69c7ef97b4401f92066a30bd956d6ede0b733e Mon Sep 17 00:00:00 2001 From: Gabriel Andretta Date: Sun, 18 Sep 2011 16:01:43 -0300 Subject: [PATCH 07/47] fix typo in readme --- README.rdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rdoc b/README.rdoc index fb5c82781e..7305bad5d0 100644 --- a/README.rdoc +++ b/README.rdoc @@ -1019,7 +1019,7 @@ Use the :static_cache_control setting (see below) to add Cache-Control header info to static files. According to RFC 2616 your application should behave differently if the If-Match -of If-None-Match header is set to * depending on whether the resource +or If-None-Match header is set to * depending on whether the resource requested is already in existence. Sinatra assumes resources for safe (like get) and idempotent (like put) requests are already in existence, whereas other resources (for instance for post requests), are treated as new resources. You From dd48e93815621e8daadf7e8b0599fef366233b3f Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Mon, 19 Sep 2011 14:38:10 -0700 Subject: [PATCH 08/47] expand_path to compare the main script with the app_file --- lib/sinatra/main.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sinatra/main.rb b/lib/sinatra/main.rb index 3f644aaabb..fc6ac70dfc 100644 --- a/lib/sinatra/main.rb +++ b/lib/sinatra/main.rb @@ -8,7 +8,7 @@ class Application < Base # on this path by default. set :app_file, caller_files.first || $0 - set :run, Proc.new { $0 == app_file } + set :run, Proc.new { File.expand_path($0) == File.expand_path(app_file) } if run? && ARGV.any? require 'optparse' From a3c7c799e833e9ac93d948a9df049790d616bdf1 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Tue, 20 Sep 2011 11:43:10 -0700 Subject: [PATCH 09/47] remove maglev specific switches, maglev master can provide/install patched gems as needed now --- Gemfile | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/Gemfile b/Gemfile index 37d30ab08d..f33ede6b29 100644 --- a/Gemfile +++ b/Gemfile @@ -30,13 +30,7 @@ gem 'sass' gem 'builder' gem 'erubis' gem 'less', '~> 1.0' - -if RUBY_ENGINE == "maglev" - gem 'liquid', :git => "https://github.com/Shopify/liquid.git" -else - gem 'liquid' -end - +gem 'liquid' gem 'slim', '~> 1.0' gem 'temple', '!= 0.3.3' gem 'RedCloth' if RUBY_VERSION < "1.9.3" and not RUBY_ENGINE.start_with? 'ma' @@ -49,7 +43,7 @@ gem 'creole' if RUBY_ENGINE == 'jruby' gem 'nokogiri', '!= 1.5.0' gem 'jruby-openssl' -elsif RUBY_ENGINE != 'maglev' +else gem 'nokogiri' end @@ -62,16 +56,10 @@ unless RUBY_ENGINE == 'jruby' && JRUBY_VERSION < "1.6.1" && !ENV['TRAVIS'] #gem 'bluecloth' end -if RUBY_ENGINE == 'maglev' - gem 'json', :git => "https://github.com/MagLev/json.git" +platforms :ruby_18, :jruby do + gem 'json' gem 'markaby' gem 'radius' -else - platforms :ruby_18, :jruby do - gem 'json' - gem 'markaby' - gem 'radius' - end end platforms :mri_18 do From c59fad7eb008e08af0fc5ac74469370c0fa76245 Mon Sep 17 00:00:00 2001 From: Jacob Burkhart & Josh Lane Date: Thu, 22 Sep 2011 15:19:24 -0700 Subject: [PATCH 10/47] Don't escape parameters by default in included rack-protection. relates to issue #310 --- lib/sinatra/base.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/sinatra/base.rb b/lib/sinatra/base.rb index c62eab45cb..2139b6de5c 100644 --- a/lib/sinatra/base.rb +++ b/lib/sinatra/base.rb @@ -1361,7 +1361,7 @@ def setup_logging(builder) def setup_protection(builder) return unless protection? - options = Hash === protection ? protection.dup : {} + options = Hash === protection ? protection.dup : {:except => [:escaped_params]} options[:except] = Array options[:except] options[:except] += [:session_hijacking, :remote_token] unless sessions? builder.use Rack::Protection, options From 73c7f2de1490011027d4780da3891d34ae635a79 Mon Sep 17 00:00:00 2001 From: Jacob Burkhart & Josh Lane Date: Thu, 22 Sep 2011 15:35:44 -0700 Subject: [PATCH 11/47] test for parameter escaping --- test/filter_test.rb | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/filter_test.rb b/test/filter_test.rb index 031af9ef44..57f4d01c37 100644 --- a/test/filter_test.rb +++ b/test/filter_test.rb @@ -97,6 +97,17 @@ class BeforeFilterTest < Test::Unit::TestCase assert_equal 'cool', body end + it "properly unescapes parameters" do + mock_app { + before { @foo = params['foo'] } + get('/foo') { @foo } + } + + get '/foo?foo=bar%3Abaz%2Fbend' + assert ok? + assert_equal 'bar:baz/bend', body + end + it "runs filters defined in superclasses" do base = Class.new(Sinatra::Base) base.before { @foo = 'hello from superclass' } From 8ae3d0aec914be45866503f568af308e579cce97 Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Thu, 22 Sep 2011 15:43:41 -0700 Subject: [PATCH 12/47] Add Josh Lane to CHANGES. --- CHANGES | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index c5b625044f..9b77ac40f2 100644 --- a/CHANGES +++ b/CHANGES @@ -12,7 +12,7 @@ * Added support for HTTP PATCH requests. (Konstantin Haase) * Use rack-protection to defend against common opportunistic attacks. - (Konstantin Haase) + (Konstantin Haase, Josh Lane) * Support for Creole templates, Creole is a standardized wiki markup, supported by many wiki implementations. (Konstanin Haase) From c0a9b3368e3c650905b25d535379524ac6fc7b53 Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Thu, 22 Sep 2011 15:48:45 -0700 Subject: [PATCH 13/47] Also mention Jacob Burkhart --- CHANGES | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 9b77ac40f2..6a73fc00c6 100644 --- a/CHANGES +++ b/CHANGES @@ -12,7 +12,7 @@ * Added support for HTTP PATCH requests. (Konstantin Haase) * Use rack-protection to defend against common opportunistic attacks. - (Konstantin Haase, Josh Lane) + (Josh Lane, Jacob Burkhart, Konstantin Haase) * Support for Creole templates, Creole is a standardized wiki markup, supported by many wiki implementations. (Konstanin Haase) From aee668df6c8907feeb0fd0cc713d95f8e1c4ca58 Mon Sep 17 00:00:00 2001 From: Davide D'Agostino Date: Thu, 15 Sep 2011 13:27:06 +0200 Subject: [PATCH 14/47] Removed an unused var. Signed-off-by: Konstantin Haase --- lib/sinatra/base.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/sinatra/base.rb b/lib/sinatra/base.rb index 04350c99e6..31bb30b7d9 100644 --- a/lib/sinatra/base.rb +++ b/lib/sinatra/base.rb @@ -1098,7 +1098,6 @@ def compile!(verb, path, block, options = {}) def compile(path) keys = [] if path.respond_to? :to_str - special_chars = %w{. + ( ) $} pattern = path.to_str.gsub(/[^\?\%\\\/\:\*\w]/) { |c| encoded(c) } pattern.gsub! /((:\w+)|\*)/ do |match| if match == "*" From afa93b0d3107e7328d1961699e7fd4d618e12e6c Mon Sep 17 00:00:00 2001 From: David Kellum Date: Wed, 28 Sep 2011 22:36:04 -0700 Subject: [PATCH 15/47] Add parens for 'Ambiguous first argument' warnings in jruby --- lib/sinatra/base.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/sinatra/base.rb b/lib/sinatra/base.rb index bb67cc60e3..2be5c30d50 100644 --- a/lib/sinatra/base.rb +++ b/lib/sinatra/base.rb @@ -845,7 +845,7 @@ def static! return unless path.start_with?(public_dir) and File.file?(path) env['sinatra.static_file'] = path - cache_control *settings.static_cache_control if settings.static_cache_control? + cache_control(*settings.static_cache_control) if settings.static_cache_control? send_file path, :disposition => nil end @@ -1213,7 +1213,7 @@ def compile(path) keys = [] if path.respond_to? :to_str pattern = path.to_str.gsub(/[^\?\%\\\/\:\*\w]/) { |c| encoded(c) } - pattern.gsub! /((:\w+)|\*)/ do |match| + pattern.gsub!(/((:\w+)|\*)/) do |match| if match == "*" keys << 'splat' "(.*?)" From bcc1d34443c52bbbec8ba8cc5c713f0feb9674e2 Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Fri, 30 Sep 2011 17:18:06 -0500 Subject: [PATCH 16/47] adjust tests for less 2.0 --- Gemfile | 2 +- test/less_test.rb | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index f33ede6b29..108f6b4caa 100644 --- a/Gemfile +++ b/Gemfile @@ -29,7 +29,7 @@ gem 'haml', '>= 3.0' gem 'sass' gem 'builder' gem 'erubis' -gem 'less', '~> 1.0' +gem 'less', '~> 2.0' gem 'liquid' gem 'slim', '~> 1.0' gem 'temple', '!= 0.3.3' diff --git a/test/less_test.rb b/test/less_test.rb index e79b83593d..21014e3165 100644 --- a/test/less_test.rb +++ b/test/less_test.rb @@ -16,7 +16,7 @@ def less_app(options = {}, &block) it 'renders inline Less strings' do less_app { less "@white_color: #fff; #main { background-color: @white_color }" } assert ok? - assert_equal "#main { background-color: #ffffff; }\n", body + assert_body "#main {background-color: #ffffff;}" end it 'defaults content type to css' do @@ -45,13 +45,13 @@ def less_app(options = {}, &block) it 'renders .less files in views path' do less_app { less :hello } assert ok? - assert_equal "#main { background-color: #ffffff; }\n", body + assert_body "#main {background-color: #ffffff;}" end it 'ignores the layout option' do less_app { less :hello, :layout => :layout2 } assert ok? - assert_equal "#main { background-color: #ffffff; }\n", body + assert_body "#main {background-color: #ffffff;}" end it "raises error if template not found" do From 244a0b8cea16790bcc10e18473b3f7a4ade13eb9 Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Fri, 30 Sep 2011 21:18:04 -0500 Subject: [PATCH 17/47] 1.3.0 release From 04bb502c9248acdee8dabba2e4d32efb628a3630 Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Sat, 1 Oct 2011 01:21:03 -0500 Subject: [PATCH 18/47] add missing dates --- CHANGES | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index 6a73fc00c6..2aee4b2027 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,4 @@ -= 1.3.0 / Not Yet Released += 1.3.0 / 2011-09-30 * Added `stream` helper method for easily creating streaming APIs, Server Sent Events or even WebSockets. See README for more on that topic. @@ -125,7 +125,7 @@ * Fix handling of broken query params when displaying exceptions. (Luke Jahnke) -= 1.2.7 (backports release) / Not Yet Released += 1.2.7 (backports release) / 2011-09-30 Custom changes: From 0ab52943f5f0e15522bc152616b125576c628851 Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Sun, 2 Oct 2011 23:36:59 -0700 Subject: [PATCH 19/47] bump version --- CHANGES | 2 ++ lib/sinatra/version.rb | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 2aee4b2027..2b0f56c6c8 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,5 @@ += 1.3.1 / Not Yet Released + = 1.3.0 / 2011-09-30 * Added `stream` helper method for easily creating streaming APIs, Server diff --git a/lib/sinatra/version.rb b/lib/sinatra/version.rb index a5f10d3322..f6e4da3b10 100644 --- a/lib/sinatra/version.rb +++ b/lib/sinatra/version.rb @@ -1,3 +1,3 @@ module Sinatra - VERSION = '1.3.0' + VERSION = '1.3.1' end From 91cafec437ed717923cc7bdd8f9307ecb3cfea09 Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Sun, 2 Oct 2011 23:39:23 -0700 Subject: [PATCH 20/47] add support for more than one callback --- CHANGES | 3 +++ lib/sinatra/base.rb | 6 +++--- test/streaming_test.rb | 10 ++++++++++ 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/CHANGES b/CHANGES index 2b0f56c6c8..4212234b8c 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,8 @@ = 1.3.1 / Not Yet Released + * Support adding more than one callback to the stream object. (Konstantin + Haase) + = 1.3.0 / 2011-09-30 * Added `stream` helper method for easily creating streaming APIs, Server diff --git a/lib/sinatra/base.rb b/lib/sinatra/base.rb index bb67cc60e3..3b6fffe712 100644 --- a/lib/sinatra/base.rb +++ b/lib/sinatra/base.rb @@ -247,11 +247,11 @@ def self.schedule(*) yield end def self.defer(*) yield end def initialize(scheduler = self.class, keep_open = false, &back) - @back, @scheduler, @callback, @keep_open = back.to_proc, scheduler, nil, keep_open + @back, @scheduler, @callbacks, @keep_open = back.to_proc, scheduler, [], keep_open end def close - @scheduler.schedule { @callback.call if @callback } + @scheduler.schedule { @callbacks.each { |c| c.call }} end def each(&front) @@ -272,7 +272,7 @@ def <<(data) end def callback(&block) - @callback = block + @callbacks << block end alias errback callback diff --git a/test/streaming_test.rb b/test/streaming_test.rb index f3dc91d44b..15afb55e10 100644 --- a/test/streaming_test.rb +++ b/test/streaming_test.rb @@ -56,6 +56,16 @@ class StreamingTest < Test::Unit::TestCase assert_equal 0, final end + it 'allows adding more than one callback' do + a = b = false + stream = Stream.new { } + stream.callback { a = true } + stream.callback { b = true } + stream.each { |str| } + assert a, 'should trigger first callback' + assert b, 'should trigger second callback' + end + class MockScheduler def initialize(*) @schedule, @defer = [], [] end def schedule(&block) @schedule << block end From 3d68174922f24b32465b0273189d41da557edf72 Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Mon, 3 Oct 2011 14:03:24 -0700 Subject: [PATCH 21/47] disable protection for one routing test --- test/routing_test.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/routing_test.rb b/test/routing_test.rb index b637f7acb3..e3f4d0bead 100644 --- a/test/routing_test.rb +++ b/test/routing_test.rb @@ -114,6 +114,8 @@ class RoutingTest < Test::Unit::TestCase it 'matches empty PATH_INFO to "" if a route is defined for ""' do mock_app do + disable :protection + get '/' do 'did not work' end From 1b6e301c61d37df5095e92eb29553162b9f22b0f Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Mon, 3 Oct 2011 14:40:10 -0700 Subject: [PATCH 22/47] be more strict about dependencies --- sinatra.gemspec | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sinatra.gemspec b/sinatra.gemspec index 9548a6bc15..34918c2a28 100644 --- a/sinatra.gemspec +++ b/sinatra.gemspec @@ -12,7 +12,7 @@ Gem::Specification.new 'sinatra', Sinatra::VERSION do |s| s.extra_rdoc_files = s.files.select { |p| p =~ /^README/ } << 'LICENSE' s.rdoc_options = %w[--line-numbers --inline-source --title Sinatra --main README.rdoc] - s.add_dependency 'rack', '~> 1.3' - s.add_dependency 'rack-protection', '~> 1.1' - s.add_dependency 'tilt', '~> 1.3' + s.add_dependency 'rack', '~> 1.3', '>= 1.3.4' + s.add_dependency 'rack-protection', '~> 1.1', '>= 1.1.2' + s.add_dependency 'tilt', '~> 1.3', '>= 1.3.3' end From d0a8907998038476796f9a335dcc018134e35174 Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Mon, 3 Oct 2011 15:04:46 -0700 Subject: [PATCH 23/47] adjust travis envs to gemspec changes --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 75b4d43cab..016ebf16c7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,9 +7,9 @@ rvm: - jruby - ruby-head env: - - "rack=1.3.0" + - "rack=1.3.4" - "rack=master" - - "tilt=1.3.2" + - "tilt=1.3.3" - "tilt=master" notifications: recipients: From d6fb8cc06789d38d3cfabdd9155031410efe351f Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Tue, 4 Oct 2011 15:13:40 -0700 Subject: [PATCH 24/47] dont include escaped_params because some other protection option has been set, related to rkh/rack-protection#6 --- lib/sinatra/base.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/sinatra/base.rb b/lib/sinatra/base.rb index 107d954d7f..a1fbffd176 100644 --- a/lib/sinatra/base.rb +++ b/lib/sinatra/base.rb @@ -1360,8 +1360,8 @@ def setup_logging(builder) def setup_protection(builder) return unless protection? - options = Hash === protection ? protection.dup : {:except => [:escaped_params]} - options[:except] = Array options[:except] + options = Hash === protection ? protection.dup : {} + options[:except] = Array(options[:except] || :escaped_params) options[:except] += [:session_hijacking, :remote_token] unless sessions? builder.use Rack::Protection, options end From 1d002390e3f1b89a84a0a2bfc3fb8e27350dd015 Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Tue, 4 Oct 2011 16:37:19 -0700 Subject: [PATCH 25/47] avoid infinite loop on thin when running a modular application, fixes #369 --- lib/sinatra/base.rb | 5 ++++- test/streaming_test.rb | 5 +++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/sinatra/base.rb b/lib/sinatra/base.rb index a1fbffd176..eef79643b6 100644 --- a/lib/sinatra/base.rb +++ b/lib/sinatra/base.rb @@ -247,10 +247,13 @@ def self.schedule(*) yield end def self.defer(*) yield end def initialize(scheduler = self.class, keep_open = false, &back) - @back, @scheduler, @callbacks, @keep_open = back.to_proc, scheduler, [], keep_open + @back, @scheduler, @keep_open = back.to_proc, scheduler, keep_open + @callbacks, @closed = [], false end def close + return if @closed + @closed = true @scheduler.schedule { @callbacks.each { |c| c.call }} end diff --git a/test/streaming_test.rb b/test/streaming_test.rb index 15afb55e10..9448d358db 100644 --- a/test/streaming_test.rb +++ b/test/streaming_test.rb @@ -107,4 +107,9 @@ def defer!(*) @defer.pop.call until @defer.empty? end scheduler.defer! assert_raise(RuntimeError) { scheduler.schedule! } end + + it 'does not trigger an infinite loop if you call close in a callback' do + stream = Stream.new { |out| out.callback { out.close }} + stream.each { |str| } + end end From cf6b6f64f4d68ae4c48b596243540e3271b2905e Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Tue, 4 Oct 2011 18:07:39 -0700 Subject: [PATCH 26/47] do not include .gitignore and .travis.yml in gem --- sinatra.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sinatra.gemspec b/sinatra.gemspec index 34918c2a28..1b3bccd59a 100644 --- a/sinatra.gemspec +++ b/sinatra.gemspec @@ -7,7 +7,7 @@ Gem::Specification.new 'sinatra', Sinatra::VERSION do |s| s.authors = ["Blake Mizerany", "Ryan Tomayko", "Simon Rozet", "Konstantin Haase"] s.email = "sinatrarb@googlegroups.com" s.homepage = "http://www.sinatrarb.com/" - s.files = `git ls-files`.split("\n") + s.files = `git ls-files`.split("\n") - %w[.gitignore .travis.yml] s.test_files = s.files.select { |p| p =~ /^test\/.*_test.rb/ } s.extra_rdoc_files = s.files.select { |p| p =~ /^README/ } << 'LICENSE' s.rdoc_options = %w[--line-numbers --inline-source --title Sinatra --main README.rdoc] From ea57aaaa9671124279c3ae4690c58a1c5f05be78 Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Tue, 4 Oct 2011 18:29:28 -0700 Subject: [PATCH 27/47] 1.3.1 release From a765cce441279030af3fc4d69393aac257a7f707 Mon Sep 17 00:00:00 2001 From: rbq Date: Wed, 5 Oct 2011 12:45:52 +0300 Subject: [PATCH 28/47] fixing changelog (the version in the 1.3.1 release contains no release date for 1.3.1) --- CHANGES | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/CHANGES b/CHANGES index 4212234b8c..a5938a97c7 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,6 @@ -= 1.3.1 / Not Yet Released += 1.3.2 / Not Yet Released + += 1.3.1 / 2011-10-05 * Support adding more than one callback to the stream object. (Konstantin Haase) From 47c11e5f624f0018e961dc3e0628a8d732b683a5 Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Wed, 5 Oct 2011 09:40:12 -0700 Subject: [PATCH 29/47] update changes --- CHANGES | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGES b/CHANGES index a5938a97c7..56f14a185f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,10 +1,11 @@ -= 1.3.2 / Not Yet Released - = 1.3.1 / 2011-10-05 * Support adding more than one callback to the stream object. (Konstantin Haase) + * Fix for infinite loop when streaming on 1.9.2 with Thin from a modular + application (Konstantin Haase) + = 1.3.0 / 2011-09-30 * Added `stream` helper method for easily creating streaming APIs, Server From bf097d6dad76783b8983f76fa225c444db41e8a1 Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Wed, 5 Oct 2011 09:44:47 -0700 Subject: [PATCH 30/47] add CHANGES check to release task --- Rakefile | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Rakefile b/Rakefile index a315079f4f..0a66e66887 100644 --- a/Rakefile +++ b/Rakefile @@ -164,6 +164,10 @@ if defined?(Gem) end task 'release' => ['test', package('.gem')] do + if File.read("CHANGES") =~ /= \d\.\d\.\d - not yet released$/i + fail 'please update changes first' + end + sh <<-SH gem install #{package('.gem')} --local && gem push #{package('.gem')} && From 5fdfa0d5d4bed8d2ade164839ad9255264c8e214 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Thu, 6 Oct 2011 21:47:06 -0700 Subject: [PATCH 31/47] therubyracer is very unstable/crashes often on rbx,jruby and maglev - revert to less 1.x for those --- Gemfile | 7 ++++++- test/less_test.rb | 6 +++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/Gemfile b/Gemfile index 108f6b4caa..834e43f862 100644 --- a/Gemfile +++ b/Gemfile @@ -29,7 +29,6 @@ gem 'haml', '>= 3.0' gem 'sass' gem 'builder' gem 'erubis' -gem 'less', '~> 2.0' gem 'liquid' gem 'slim', '~> 1.0' gem 'temple', '!= 0.3.3' @@ -47,6 +46,12 @@ else gem 'nokogiri' end +if RUBY_ENGINE == "ruby" + gem 'less', '~> 2.0' +else + gem 'less', '~> 1.0' +end + unless RUBY_ENGINE == 'jruby' && JRUBY_VERSION < "1.6.1" && !ENV['TRAVIS'] # C extensions gem 'rdiscount' diff --git a/test/less_test.rb b/test/less_test.rb index 21014e3165..979f201c74 100644 --- a/test/less_test.rb +++ b/test/less_test.rb @@ -16,7 +16,7 @@ def less_app(options = {}, &block) it 'renders inline Less strings' do less_app { less "@white_color: #fff; #main { background-color: @white_color }" } assert ok? - assert_body "#main {background-color: #ffffff;}" + assert_equal "#main{background-color:#ffffff;}", body.gsub(/\s/, "") end it 'defaults content type to css' do @@ -45,13 +45,13 @@ def less_app(options = {}, &block) it 'renders .less files in views path' do less_app { less :hello } assert ok? - assert_body "#main {background-color: #ffffff;}" + assert_equal "#main{background-color:#ffffff;}", body.gsub(/\s/, "") end it 'ignores the layout option' do less_app { less :hello, :layout => :layout2 } assert ok? - assert_body "#main {background-color: #ffffff;}" + assert_equal "#main{background-color:#ffffff;}", body.gsub(/\s/, "") end it "raises error if template not found" do From 8ce0d35d8b356cdb2c5060ebb03f493abe0f3400 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Thu, 6 Oct 2011 22:11:45 -0700 Subject: [PATCH 32/47] redcloth now works on maglev --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 834e43f862..a4ffa91af9 100644 --- a/Gemfile +++ b/Gemfile @@ -32,7 +32,7 @@ gem 'erubis' gem 'liquid' gem 'slim', '~> 1.0' gem 'temple', '!= 0.3.3' -gem 'RedCloth' if RUBY_VERSION < "1.9.3" and not RUBY_ENGINE.start_with? 'ma' +gem 'RedCloth' if RUBY_VERSION < "1.9.3" and not RUBY_ENGINE == "macruby" gem 'coffee-script', '>= 2.0' gem 'rdoc' gem 'kramdown' From 5b6c83d5956f42d8e7a3e3a6dc18d929d5220573 Mon Sep 17 00:00:00 2001 From: Vasiliy Ermolovich Date: Fri, 7 Oct 2011 22:39:26 +0300 Subject: [PATCH 33/47] small refactoring --- lib/sinatra/base.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/sinatra/base.rb b/lib/sinatra/base.rb index eef79643b6..1fb566c328 100644 --- a/lib/sinatra/base.rb +++ b/lib/sinatra/base.rb @@ -51,7 +51,7 @@ def idempotent? private def accept_entry(entry) - type, *options = entry.gsub(/\s/, '').split(';') + type, *options = entry.delete(' ').split(';') quality = 0 # we sort smalles first options.delete_if { |e| quality = 1 - e[2..-1].to_f if e.start_with? 'q=' } [type, [quality, type.count('*'), 1 - options.size]] @@ -311,7 +311,7 @@ def cache_control(*values) hash = {} end - values = values.map { |value| value.to_s.tr('_','-') } + values.map! { |value| value.to_s.tr('_','-') } hash.each do |key, value| key = key.to_s.tr('_', '-') value = value.to_i if key == "max-age" From dc1ff1867096c5ef036c7aff9b55e4e72e4eaa6a Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Mon, 10 Oct 2011 18:57:14 -0700 Subject: [PATCH 34/47] Update rdoc test to work with RDoc 3.10 --- test/rdoc_test.rb | 1 + 1 file changed, 1 insertion(+) diff --git a/test/rdoc_test.rb b/test/rdoc_test.rb index ff547bc463..d28b16ad9b 100644 --- a/test/rdoc_test.rb +++ b/test/rdoc_test.rb @@ -1,6 +1,7 @@ require File.expand_path('../helper', __FILE__) begin +require 'rdoc' require 'rdoc/markup/to_html' class RdocTest < Test::Unit::TestCase From bee190b42ec8b3d1bf9ced2eccca4842d20e3433 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Mon, 10 Oct 2011 18:57:44 -0700 Subject: [PATCH 35/47] Update README's to avoid surprises when using RDoc 3.10 --- README.jp.rdoc | 1 + README.zh.rdoc | 1 + 2 files changed, 2 insertions(+) diff --git a/README.jp.rdoc b/README.jp.rdoc index 1562aa417e..1765bb977e 100644 --- a/README.jp.rdoc +++ b/README.jp.rdoc @@ -376,6 +376,7 @@ textileからメソッドを呼び出すことも、localsに変数を渡すこ RDocテンプレートを使うにはRDocライブラリが必要です: # rdoc/markup/to_htmlを読み込みます + require "rdoc" require "rdoc/markup/to_html" get '/' do diff --git a/README.zh.rdoc b/README.zh.rdoc index 64b562ecc3..4b6fc37385 100644 --- a/README.zh.rdoc +++ b/README.zh.rdoc @@ -492,6 +492,7 @@ Rack body对象或者HTTP状态码: 需要引入 RDoc gem/library 以渲染RDoc模板: # 需要在你的应用中引入rdoc/markup/to_html + require "rdoc" require "rdoc/markup/to_html" get '/' do From 3d78b5ee6c18d5776ddf9c7d148158a3604f80e6 Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Mon, 10 Oct 2011 19:50:59 -0700 Subject: [PATCH 36/47] fix rdoc tests for 3.10 --- test/helper.rb | 6 +++++- test/rdoc_test.rb | 4 ++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/test/helper.rb b/test/helper.rb index 1f061d49d9..dc8fd40515 100644 --- a/test/helper.rb +++ b/test/helper.rb @@ -69,7 +69,11 @@ def body end def assert_body(value) - assert_equal value.lstrip.gsub(/\s*\n\s*/, ""), body.lstrip.gsub(/\s*\n\s*/, "") + if value.respond_to? :to_str + assert_equal value.lstrip.gsub(/\s*\n\s*/, ""), body.lstrip.gsub(/\s*\n\s*/, "") + else + assert_match value, body + end end def assert_status(expected) diff --git a/test/rdoc_test.rb b/test/rdoc_test.rb index d28b16ad9b..0d5885630e 100644 --- a/test/rdoc_test.rb +++ b/test/rdoc_test.rb @@ -16,13 +16,13 @@ def rdoc_app(&block) it 'renders inline rdoc strings' do rdoc_app { rdoc '= Hiya' } assert ok? - assert_body "

Hiya

" + assert_body /]*>Hiya<\/h1>/ end it 'renders .rdoc files in views path' do rdoc_app { rdoc :hello } assert ok? - assert_body "

Hello From RDoc

" + assert_body /]*>Hello From RDoc<\/h1>/ end it "raises error if template not found" do From 08d6907ce0f423393c7cb8c6ec96bd27591ca65c Mon Sep 17 00:00:00 2001 From: Tim Felgentreff Date: Mon, 10 Oct 2011 20:21:41 -0700 Subject: [PATCH 37/47] Edit Gemfile to use the swiggly-operator when specifying a version of rack+tilt via an environment variable --- Gemfile | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index a4ffa91af9..e1e2ba5fe8 100644 --- a/Gemfile +++ b/Gemfile @@ -19,9 +19,14 @@ gem 'ci_reporter', :group => :ci github = "git://github.com/%s.git" repos = { 'tilt' => github % "rtomayko/tilt", 'rack' => github % "rack/rack" } %w[tilt rack].each do |lib| - dep = (ENV[lib] || 'stable').sub "#{lib}-", '' - dep = nil if dep == 'stable' - dep = {:git => repos[lib], :branch => dep} if dep and dep !~ /(\d+\.)+\d+/ + dep = case ENV[lib] || 'stable' + when 'stable' + nil + when /(\d+\.)+\d+/ + "~> " + ENV[lib].sub("#{lib}-", '') + else + {:git => repos[lib], :branch => dep} + end gem lib, dep end From 313def15eeced2678a7bbfdcd722fda52473143d Mon Sep 17 00:00:00 2001 From: Nathan Baum Date: Fri, 14 Oct 2011 17:09:30 +0200 Subject: [PATCH 38/47] Don't leave @default_layout set to false if rendering a template fails. --- lib/sinatra/base.rb | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/sinatra/base.rb b/lib/sinatra/base.rb index 1fb566c328..7d63061069 100644 --- a/lib/sinatra/base.rb +++ b/lib/sinatra/base.rb @@ -619,11 +619,14 @@ def render(engine, data, options={}, locals={}, &block) scope = options.delete(:scope) || self # compile and render template - layout_was = @default_layout - @default_layout = false - template = compile_template(engine, data, options, views) - output = template.render(scope, locals, &block) - @default_layout = layout_was + begin + layout_was = @default_layout + @default_layout = false + template = compile_template(engine, data, options, views) + output = template.render(scope, locals, &block) + ensure + @default_layout = layout_was + end # render layout if layout From b95764bec06214ba4ce5f46a995ea9c13f80b63b Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Fri, 14 Oct 2011 14:04:04 -0700 Subject: [PATCH 39/47] remove unnecessary parens from example --- README.rdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rdoc b/README.rdoc index 7305bad5d0..3434e153df 100644 --- a/README.rdoc +++ b/README.rdoc @@ -885,7 +885,7 @@ default, so if you inherit from Sinatra::Base, you probably want to enable it yourself: class MyApp < Sinatra::Base - configure(:production, :development) do + configure :production, :development do enable :logging end end From bf3ad8c40ae20d6358abab16c429d502bb60d49d Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Fri, 14 Oct 2011 14:08:43 -0700 Subject: [PATCH 40/47] rework logger setup * CommonLogger by Sinatra is no longer added if Rack::Server will add it. Fixes #380. * Setting the logger options to nil will avoid automatically pulling in Rack::NullLogger, thus allowing you to set up your own logging middleware outside of the Sinatra middleware stack. Fixes #371. --- README.rdoc | 5 +++++ lib/sinatra/base.rb | 27 ++++++++++++++++++++------- test/helpers_test.rb | 10 ++++++++++ 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/README.rdoc b/README.rdoc index 3434e153df..8f0b8e4f0e 100644 --- a/README.rdoc +++ b/README.rdoc @@ -890,6 +890,11 @@ enable it yourself: end end +To avoid any logging middleware to be set up, set the +logging+ setting to ++nil+. However, keep in mind that +logger+ will in that case return +nil+. A +common use case is when you want to set your own logger. Sinatra will use +whatever it will find in env['rack.logger']. + === Mime Types When using send_file or static files you may have mime types Sinatra diff --git a/lib/sinatra/base.rb b/lib/sinatra/base.rb index 7d63061069..81fbfd5750 100644 --- a/lib/sinatra/base.rb +++ b/lib/sinatra/base.rb @@ -1353,14 +1353,27 @@ def setup_middleware(builder) def setup_logging(builder) if logging? - builder.use Rack::CommonLogger - if logging.respond_to? :to_int - builder.use Rack::Logger, logging - else - builder.use Rack::Logger - end + setup_common_logger(builder) + setup_custom_logger(builder) + elsif logging == false + setup_null_logger(builder) + end + end + + def setup_null_logger(builder) + builder.use Rack::NullLogger + end + + def setup_common_logger(builder) + return if ["development", "deployment", nil].include? ENV["RACK_ENV"] + builder.use Rack::CommonLogger + end + + def setup_custom_logger(builder) + if logging.respond_to? :to_int + builder.use Rack::Logger, logging else - builder.use Rack::NullLogger + builder.use Rack::Logger end end diff --git a/test/helpers_test.rb b/test/helpers_test.rb index f136190427..1997754717 100644 --- a/test/helpers_test.rb +++ b/test/helpers_test.rb @@ -1711,6 +1711,16 @@ def obj.is_a?(thing) 60.is_a?(thing) end assert !io.string.include?("INFO -- : Program started") assert !io.string.include?("WARN -- : Nothing to do") end + + it 'does not create a logger when logging is set to nil' do + mock_app do + disable :logging + get('/') { logger.inspect } + end + + get '/' + assert_body 'nil' + end end module ::HelperOne; def one; '1'; end; end From 855e5671adc37b023f553a812c502bd6c7ee3b1e Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Fri, 14 Oct 2011 14:15:20 -0700 Subject: [PATCH 41/47] fix CHANGES check --- Rakefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Rakefile b/Rakefile index 0a66e66887..d7e0d8a964 100644 --- a/Rakefile +++ b/Rakefile @@ -164,7 +164,7 @@ if defined?(Gem) end task 'release' => ['test', package('.gem')] do - if File.read("CHANGES") =~ /= \d\.\d\.\d - not yet released$/i + if File.read("CHANGES") =~ /= \d\.\d\.\d . not yet released$/i fail 'please update changes first' end From 25e8aec3335b0808b9ce822186b00e79122a9ad1 Mon Sep 17 00:00:00 2001 From: Zachary Scott Date: Fri, 14 Oct 2011 18:12:40 -0400 Subject: [PATCH 42/47] book-contrib is now recipes --- README.de.rdoc | 4 ++-- README.es.rdoc | 2 +- README.fr.rdoc | 2 +- README.rdoc | 2 +- README.ru.rdoc | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.de.rdoc b/README.de.rdoc index 6b62f582dc..a1a78a09b4 100644 --- a/README.de.rdoc +++ b/README.de.rdoc @@ -1953,9 +1953,9 @@ SemVer und SemVerTag. * {Mailing-Liste}[http://groups.google.com/group/sinatrarb] * {IRC: #sinatra}[irc://chat.freenode.net/#sinatra] auf http://freenode.net * {Sinatra Book}[http://sinatra-book.gittr.com] Kochbuch Tutorial -* {Sinatra Book Contrib}[http://sinatra-book-contrib.com/] Sinatra-Rezepte aus +* {Sinatra Recipes}[http://recipes.sinatrarb.com/] Sinatra-Rezepte aus der Community * API Dokumentation für die {aktuelle Version}[http://rubydoc.info/gems/sinatra] oder für {HEAD}[http://rubydoc.info/github/sinatra/sinatra] auf http://rubydoc.info -* {CI Server}[http://ci.rkh.im/view/Sinatra/] \ No newline at end of file +* {CI Server}[http://ci.rkh.im/view/Sinatra/] diff --git a/README.es.rdoc b/README.es.rdoc index 77c47fbd3b..b4ad2808dd 100644 --- a/README.es.rdoc +++ b/README.es.rdoc @@ -2004,7 +2004,7 @@ siguiendo las especificaciones SemVer y SemVerTag. * {Lista de Correo}[http://groups.google.com/group/sinatrarb/topics] * {IRC: #sinatra}[irc://chat.freenode.net/#sinatra] en http://freenode.net * {Sinatra Book}[http://sinatra-book.gittr.com] Tutorial (en inglés). -* {Sinatra Book Contrib}[http://sinatra-book-contrib.com/] Recetas contribuidas +* {Sinatra Recipes}[http://recipes.sinatrarb.com/] Recetas contribuidas por la comunidad (en inglés). * Documentación de la API para la {última versión liberada}[http://rubydoc.info/gems/sinatra] o para la diff --git a/README.fr.rdoc b/README.fr.rdoc index 2e0b14a537..458490f36c 100644 --- a/README.fr.rdoc +++ b/README.fr.rdoc @@ -1974,7 +1974,7 @@ SemVer que SemVerTag. * {IRC : #sinatra}[irc://chat.freenode.net/#sinatra] sur http://freenode.net * {IRC : #sinatra}[irc://chat.freenode.net/#sinatra] on http://freenode.net * {Sinatra Book}[http://sinatra-book.gittr.com] Tutoriels et recettes -* {Sinatra Book Contrib}[http://sinatra-book-contrib.com/] Recettes contribuées +* {Sinatra Recipes}[http://recipes.sinatrarb.com/] Recettes contribuées par la communauté * Documentation API de la {dernière version}[http://rubydoc.info/gems/sinatra] ou du {HEAD courant}[http://rubydoc.info/github/sinatra/sinatra] sur diff --git a/README.rdoc b/README.rdoc index 7305bad5d0..ba43c35d18 100644 --- a/README.rdoc +++ b/README.rdoc @@ -1942,7 +1942,7 @@ SemVerTag. * {Mailing List}[http://groups.google.com/group/sinatrarb/topics] * {IRC: #sinatra}[irc://chat.freenode.net/#sinatra] on http://freenode.net * {Sinatra Book}[http://sinatra-book.gittr.com] Cookbook Tutorial -* {Sinatra Book Contrib}[http://sinatra-book-contrib.com/] Community +* {Sinatra Recipes}[http://recipes.sinatrarb.com/] Community contributed recipes * API documentation for the {latest release}[http://rubydoc.info/gems/sinatra] or the {current HEAD}[http://rubydoc.info/github/sinatra/sinatra] on diff --git a/README.ru.rdoc b/README.ru.rdoc index 63def1e70e..bffba5e920 100644 --- a/README.ru.rdoc +++ b/README.ru.rdoc @@ -1779,7 +1779,7 @@ SemVerTag. * {Группы рассылки}[http://groups.google.com/group/sinatrarb/topics] * {IRC: #sinatra}[irc://chat.freenode.net/#sinatra] на http://freenode.net * {Sinatra Book}[http://sinatra-book.gittr.com] учебник и сборник рецептов -* {Sinatra Book Contrib}[http://sinatra-book-contrib.com/] сборник рецептов +* {Sinatra Recipes}[http://recipes.sinatrarb.com/] сборник рецептов * API документация к {последнему релизу}[http://rubydoc.info/gems/sinatra] или {текущему HEAD}[http://rubydoc.info/github/sinatra/sinatra] на http://rubydoc.info From 678fdfb8c6bcea5f29000939304a4071f08538f5 Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Fri, 14 Oct 2011 22:45:26 -0700 Subject: [PATCH 43/47] update changes --- CHANGES | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CHANGES b/CHANGES index 56f14a185f..c90653c591 100644 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,14 @@ += 1.3.2 / Not Yet Released + + * Don't automatically add `Rack::CommonLogger` if `Rack::Server` is adding it, + too. (Konstantin Haase) + + * Setting `logging` to `nil` will avoid setting up `Rack::NullLogger`. + (Konstantin Haase) + + * Fix bug where rendering a second template in the same request after the + first one raised an exception skipped the default layout (Nathan Baum) + = 1.3.1 / 2011-10-05 * Support adding more than one callback to the stream object. (Konstantin @@ -133,6 +144,13 @@ * Fix handling of broken query params when displaying exceptions. (Luke Jahnke) += 1.2.8 / Not Yet Released + +Backported from 1.3.2: + +* Fix bug where rendering a second template in the same request after the + first one raised an exception skipped the default layout (Nathan Baum) + = 1.2.7 (backports release) / 2011-09-30 Custom changes: From 038220280a5295a38f4fc205c25ab921b4c13161 Mon Sep 17 00:00:00 2001 From: Konstantin Haase Date: Fri, 14 Oct 2011 23:02:13 -0700 Subject: [PATCH 44/47] fix logging test --- test/helpers_test.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/helpers_test.rb b/test/helpers_test.rb index 1997754717..42d1f9a106 100644 --- a/test/helpers_test.rb +++ b/test/helpers_test.rb @@ -1714,7 +1714,7 @@ def obj.is_a?(thing) 60.is_a?(thing) end it 'does not create a logger when logging is set to nil' do mock_app do - disable :logging + set :logging, nil get('/') { logger.inspect } end From a5746ad6091d1adb657d2572b7a5d43cdc719d1c Mon Sep 17 00:00:00 2001 From: Gabriel Andretta Date: Sun, 23 Oct 2011 12:16:13 -0300 Subject: [PATCH 45/47] fix title level in Spanish readme --- README.es.rdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.es.rdoc b/README.es.rdoc index b4ad2808dd..0cba4f978c 100644 --- a/README.es.rdoc +++ b/README.es.rdoc @@ -1300,7 +1300,7 @@ Podés acceder a estas opciones utilizando el método settings: ... end -==== Configurando la Protección de Ataques +=== Configurando la Protección de Ataques Sinatra usa {Rack::Protection}[https://github.com/rkh/rack-protection#readme] para defender a tu aplicación de los ataques más comunes. Tenés que tener en From 1c6147c84120f9243810c54170b83f986a79d9d4 Mon Sep 17 00:00:00 2001 From: Gabriel Andretta Date: Sun, 23 Oct 2011 12:18:22 -0300 Subject: [PATCH 46/47] remove unnecessary parens in Spanish readme --- README.es.rdoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.es.rdoc b/README.es.rdoc index 0cba4f978c..59aff584b9 100644 --- a/README.es.rdoc +++ b/README.es.rdoc @@ -916,7 +916,7 @@ para Sinatra::Application. Si heredaste de Sinatra::Base, probablemente quieras habilitarlo manualmente: class MiApp < Sinatra::Base - configure(:production, :development) do + configure :production, :development do enable :logging end end From 045d444dde05a421e12d2e09f0212b2fe9d36406 Mon Sep 17 00:00:00 2001 From: Gabriel Andretta Date: Sun, 23 Oct 2011 12:30:08 -0300 Subject: [PATCH 47/47] doc logger setup changes in Spanish readme --- README.es.rdoc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.es.rdoc b/README.es.rdoc index 59aff584b9..292783c917 100644 --- a/README.es.rdoc +++ b/README.es.rdoc @@ -921,6 +921,11 @@ para Sinatra::Application. Si heredaste de end end +Para evitar que se inicialice cualquier middleware de logging, configurá ++logging+ a +nil+. Tené en cuenta que, cuando hagas esto, +logger+ va a +devolver +nil+. Un caso común es cuando querés usar tu propio logger. Sinatra +va a usar lo que encuentre en env['rack.logger']. + === Tipos Mime Cuando usás send_file o archivos estáticos tal vez tengas tipos mime