##// END OF EJS Templates
Fixed that X-Sendfile header is never set (#24646)....
Jean-Philippe Lang -
r15732:aef4a8a65bd6
parent child
Show More
@@ -1,83 +1,83
1 require File.expand_path('../boot', __FILE__)
1 require File.expand_path('../boot', __FILE__)
2
2
3 require 'rails/all'
3 require 'rails/all'
4
4
5 Bundler.require(*Rails.groups)
5 Bundler.require(*Rails.groups)
6
6
7 module RedmineApp
7 module RedmineApp
8 class Application < Rails::Application
8 class Application < Rails::Application
9 # Settings in config/environments/* take precedence over those specified here.
9 # Settings in config/environments/* take precedence over those specified here.
10 # Application configuration should go into files in config/initializers
10 # Application configuration should go into files in config/initializers
11 # -- all .rb files in that directory are automatically loaded.
11 # -- all .rb files in that directory are automatically loaded.
12
12
13 # Custom directories with classes and modules you want to be autoloadable.
13 # Custom directories with classes and modules you want to be autoloadable.
14 config.autoload_paths += %W(#{config.root}/lib)
14 config.autoload_paths += %W(#{config.root}/lib)
15
15
16 # Only load the plugins named here, in the order given (default is alphabetical).
16 # Only load the plugins named here, in the order given (default is alphabetical).
17 # :all can be used as a placeholder for all plugins not explicitly named.
17 # :all can be used as a placeholder for all plugins not explicitly named.
18 # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
18 # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
19
19
20 config.active_record.store_full_sti_class = true
20 config.active_record.store_full_sti_class = true
21 config.active_record.default_timezone = :local
21 config.active_record.default_timezone = :local
22
22
23 # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
23 # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
24 # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
24 # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
25 # config.time_zone = 'Central Time (US & Canada)'
25 # config.time_zone = 'Central Time (US & Canada)'
26
26
27 # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
27 # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
28 # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
28 # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
29 # config.i18n.default_locale = :de
29 # config.i18n.default_locale = :de
30
30
31 I18n.enforce_available_locales = true
31 I18n.enforce_available_locales = true
32
32
33 # Configure the default encoding used in templates for Ruby 1.9.
33 # Configure the default encoding used in templates for Ruby 1.9.
34 config.encoding = "utf-8"
34 config.encoding = "utf-8"
35
35
36 # Configure sensitive parameters which will be filtered from the log file.
36 # Configure sensitive parameters which will be filtered from the log file.
37 config.filter_parameters += [:password]
37 config.filter_parameters += [:password]
38
38
39 # Enable the asset pipeline
39 # Enable the asset pipeline
40 config.assets.enabled = false
40 config.assets.enabled = false
41
41
42 # Version of your assets, change this if you want to expire all your assets
42 # Version of your assets, change this if you want to expire all your assets
43 config.assets.version = '1.0'
43 config.assets.version = '1.0'
44
44
45 config.action_mailer.perform_deliveries = false
45 config.action_mailer.perform_deliveries = false
46
46
47 # Do not include all helpers
47 # Do not include all helpers
48 config.action_controller.include_all_helpers = false
48 config.action_controller.include_all_helpers = false
49
49
50 # Do not supress errors in after_rollback and after_commit callbacks
50 # Do not supress errors in after_rollback and after_commit callbacks
51 config.active_record.raise_in_transactional_callbacks = true
51 config.active_record.raise_in_transactional_callbacks = true
52
52
53 # XML parameter parser removed from core in Rails 4.0
53 # XML parameter parser removed from core in Rails 4.0
54 # and extracted to actionpack-xml_parser gem
54 # and extracted to actionpack-xml_parser gem
55 config.middleware.insert_after ActionDispatch::ParamsParser, ActionDispatch::XmlParamsParser
55 config.middleware.insert_after ActionDispatch::ParamsParser, ActionDispatch::XmlParamsParser
56
56
57 # Sets the Content-Length header on responses with fixed-length bodies
57 # Sets the Content-Length header on responses with fixed-length bodies
58 config.middleware.use Rack::ContentLength
58 config.middleware.insert_after Rack::Sendfile, Rack::ContentLength
59
59
60 # Verify validity of user sessions
60 # Verify validity of user sessions
61 config.redmine_verify_sessions = true
61 config.redmine_verify_sessions = true
62
62
63 # Specific cache for search results, the default file store cache is not
63 # Specific cache for search results, the default file store cache is not
64 # a good option as it could grow fast. A memory store (32MB max) is used
64 # a good option as it could grow fast. A memory store (32MB max) is used
65 # as the default. If you're running multiple server processes, it's
65 # as the default. If you're running multiple server processes, it's
66 # recommended to switch to a shared cache store (eg. mem_cache_store).
66 # recommended to switch to a shared cache store (eg. mem_cache_store).
67 # See http://guides.rubyonrails.org/caching_with_rails.html#cache-stores
67 # See http://guides.rubyonrails.org/caching_with_rails.html#cache-stores
68 # for more options (same options as config.cache_store).
68 # for more options (same options as config.cache_store).
69 config.redmine_search_cache_store = :memory_store
69 config.redmine_search_cache_store = :memory_store
70
70
71 # Configure log level here so that additional environment file
71 # Configure log level here so that additional environment file
72 # can change it (environments/ENV.rb would take precedence over it)
72 # can change it (environments/ENV.rb would take precedence over it)
73 config.log_level = Rails.env.production? ? :info : :debug
73 config.log_level = Rails.env.production? ? :info : :debug
74
74
75 config.session_store :cookie_store,
75 config.session_store :cookie_store,
76 :key => '_redmine_session',
76 :key => '_redmine_session',
77 :path => config.relative_url_root || '/'
77 :path => config.relative_url_root || '/'
78
78
79 if File.exists?(File.join(File.dirname(__FILE__), 'additional_environment.rb'))
79 if File.exists?(File.join(File.dirname(__FILE__), 'additional_environment.rb'))
80 instance_eval File.read(File.join(File.dirname(__FILE__), 'additional_environment.rb'))
80 instance_eval File.read(File.join(File.dirname(__FILE__), 'additional_environment.rb'))
81 end
81 end
82 end
82 end
83 end
83 end
@@ -1,152 +1,164
1 # Redmine - project management software
1 # Redmine - project management software
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
2 # Copyright (C) 2006-2016 Jean-Philippe Lang
3 #
3 #
4 # This program is free software; you can redistribute it and/or
4 # This program is free software; you can redistribute it and/or
5 # modify it under the terms of the GNU General Public License
5 # modify it under the terms of the GNU General Public License
6 # as published by the Free Software Foundation; either version 2
6 # as published by the Free Software Foundation; either version 2
7 # of the License, or (at your option) any later version.
7 # of the License, or (at your option) any later version.
8 #
8 #
9 # This program is distributed in the hope that it will be useful,
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
12 # GNU General Public License for more details.
13 #
13 #
14 # You should have received a copy of the GNU General Public License
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17
17
18 require File.expand_path('../../test_helper', __FILE__)
18 require File.expand_path('../../test_helper', __FILE__)
19
19
20 class AttachmentsTest < Redmine::IntegrationTest
20 class AttachmentsTest < Redmine::IntegrationTest
21 fixtures :projects, :enabled_modules,
21 fixtures :projects, :enabled_modules,
22 :users, :roles, :members, :member_roles,
22 :users, :roles, :members, :member_roles,
23 :trackers, :projects_trackers,
23 :trackers, :projects_trackers,
24 :issue_statuses, :enumerations
24 :issue_statuses, :enumerations
25
25
26 def test_upload_should_set_default_content_type
26 def test_upload_should_set_default_content_type
27 log_user('jsmith', 'jsmith')
27 log_user('jsmith', 'jsmith')
28 assert_difference 'Attachment.count' do
28 assert_difference 'Attachment.count' do
29 post "/uploads.js?attachment_id=1&filename=foo.txt", "File content", {"CONTENT_TYPE" => 'application/octet-stream'}
29 post "/uploads.js?attachment_id=1&filename=foo.txt", "File content", {"CONTENT_TYPE" => 'application/octet-stream'}
30 assert_response :success
30 assert_response :success
31 end
31 end
32 attachment = Attachment.order(:id => :desc).first
32 attachment = Attachment.order(:id => :desc).first
33 assert_equal 'text/plain', attachment.content_type
33 assert_equal 'text/plain', attachment.content_type
34 end
34 end
35
35
36 def test_upload_should_accept_content_type_param
36 def test_upload_should_accept_content_type_param
37 log_user('jsmith', 'jsmith')
37 log_user('jsmith', 'jsmith')
38 assert_difference 'Attachment.count' do
38 assert_difference 'Attachment.count' do
39 post "/uploads.js?attachment_id=1&filename=foo&content_type=image/jpeg", "File content", {"CONTENT_TYPE" => 'application/octet-stream'}
39 post "/uploads.js?attachment_id=1&filename=foo&content_type=image/jpeg", "File content", {"CONTENT_TYPE" => 'application/octet-stream'}
40 assert_response :success
40 assert_response :success
41 end
41 end
42 attachment = Attachment.order(:id => :desc).first
42 attachment = Attachment.order(:id => :desc).first
43 assert_equal 'image/jpeg', attachment.content_type
43 assert_equal 'image/jpeg', attachment.content_type
44 end
44 end
45
45
46 def test_upload_as_js_and_attach_to_an_issue
46 def test_upload_as_js_and_attach_to_an_issue
47 log_user('jsmith', 'jsmith')
47 log_user('jsmith', 'jsmith')
48
48
49 token = ajax_upload('myupload.txt', 'File content')
49 token = ajax_upload('myupload.txt', 'File content')
50
50
51 assert_difference 'Issue.count' do
51 assert_difference 'Issue.count' do
52 post '/projects/ecookbook/issues', {
52 post '/projects/ecookbook/issues', {
53 :issue => {:tracker_id => 1, :subject => 'Issue with upload'},
53 :issue => {:tracker_id => 1, :subject => 'Issue with upload'},
54 :attachments => {'1' => {:filename => 'myupload.txt', :description => 'My uploaded file', :token => token}}
54 :attachments => {'1' => {:filename => 'myupload.txt', :description => 'My uploaded file', :token => token}}
55 }
55 }
56 assert_response 302
56 assert_response 302
57 end
57 end
58
58
59 issue = Issue.order('id DESC').first
59 issue = Issue.order('id DESC').first
60 assert_equal 'Issue with upload', issue.subject
60 assert_equal 'Issue with upload', issue.subject
61 assert_equal 1, issue.attachments.count
61 assert_equal 1, issue.attachments.count
62
62
63 attachment = issue.attachments.first
63 attachment = issue.attachments.first
64 assert_equal 'myupload.txt', attachment.filename
64 assert_equal 'myupload.txt', attachment.filename
65 assert_equal 'My uploaded file', attachment.description
65 assert_equal 'My uploaded file', attachment.description
66 assert_equal 'File content'.length, attachment.filesize
66 assert_equal 'File content'.length, attachment.filesize
67 end
67 end
68
68
69 def test_upload_as_js_and_preview_as_inline_attachment
69 def test_upload_as_js_and_preview_as_inline_attachment
70 log_user('jsmith', 'jsmith')
70 log_user('jsmith', 'jsmith')
71
71
72 token = ajax_upload('myupload.jpg', 'JPEG content')
72 token = ajax_upload('myupload.jpg', 'JPEG content')
73
73
74 post '/issues/preview/new/ecookbook', {
74 post '/issues/preview/new/ecookbook', {
75 :issue => {:tracker_id => 1, :description => 'Inline upload: !myupload.jpg!'},
75 :issue => {:tracker_id => 1, :description => 'Inline upload: !myupload.jpg!'},
76 :attachments => {'1' => {:filename => 'myupload.jpg', :description => 'My uploaded file', :token => token}}
76 :attachments => {'1' => {:filename => 'myupload.jpg', :description => 'My uploaded file', :token => token}}
77 }
77 }
78 assert_response :success
78 assert_response :success
79
79
80 attachment_path = response.body.match(%r{<img src="(/attachments/download/\d+/myupload.jpg)"})[1]
80 attachment_path = response.body.match(%r{<img src="(/attachments/download/\d+/myupload.jpg)"})[1]
81 assert_not_nil token, "No attachment path found in response:\n#{response.body}"
81 assert_not_nil token, "No attachment path found in response:\n#{response.body}"
82
82
83 get attachment_path
83 get attachment_path
84 assert_response :success
84 assert_response :success
85 assert_equal 'JPEG content', response.body
85 assert_equal 'JPEG content', response.body
86 end
86 end
87
87
88 def test_upload_and_resubmit_after_validation_failure
88 def test_upload_and_resubmit_after_validation_failure
89 log_user('jsmith', 'jsmith')
89 log_user('jsmith', 'jsmith')
90
90
91 token = ajax_upload('myupload.txt', 'File content')
91 token = ajax_upload('myupload.txt', 'File content')
92
92
93 assert_no_difference 'Issue.count' do
93 assert_no_difference 'Issue.count' do
94 post '/projects/ecookbook/issues', {
94 post '/projects/ecookbook/issues', {
95 :issue => {:tracker_id => 1, :subject => ''},
95 :issue => {:tracker_id => 1, :subject => ''},
96 :attachments => {'1' => {:filename => 'myupload.txt', :description => 'My uploaded file', :token => token}}
96 :attachments => {'1' => {:filename => 'myupload.txt', :description => 'My uploaded file', :token => token}}
97 }
97 }
98 assert_response :success
98 assert_response :success
99 end
99 end
100 assert_select 'input[type=hidden][name=?][value=?]', 'attachments[p0][token]', token
100 assert_select 'input[type=hidden][name=?][value=?]', 'attachments[p0][token]', token
101 assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'myupload.txt'
101 assert_select 'input[name=?][value=?]', 'attachments[p0][filename]', 'myupload.txt'
102 assert_select 'input[name=?][value=?]', 'attachments[p0][description]', 'My uploaded file'
102 assert_select 'input[name=?][value=?]', 'attachments[p0][description]', 'My uploaded file'
103
103
104 assert_difference 'Issue.count' do
104 assert_difference 'Issue.count' do
105 post '/projects/ecookbook/issues', {
105 post '/projects/ecookbook/issues', {
106 :issue => {:tracker_id => 1, :subject => 'Issue with upload'},
106 :issue => {:tracker_id => 1, :subject => 'Issue with upload'},
107 :attachments => {'p0' => {:filename => 'myupload.txt', :description => 'My uploaded file', :token => token}}
107 :attachments => {'p0' => {:filename => 'myupload.txt', :description => 'My uploaded file', :token => token}}
108 }
108 }
109 assert_response 302
109 assert_response 302
110 end
110 end
111
111
112 issue = Issue.order('id DESC').first
112 issue = Issue.order('id DESC').first
113 assert_equal 'Issue with upload', issue.subject
113 assert_equal 'Issue with upload', issue.subject
114 assert_equal 1, issue.attachments.count
114 assert_equal 1, issue.attachments.count
115
115
116 attachment = issue.attachments.first
116 attachment = issue.attachments.first
117 assert_equal 'myupload.txt', attachment.filename
117 assert_equal 'myupload.txt', attachment.filename
118 assert_equal 'My uploaded file', attachment.description
118 assert_equal 'My uploaded file', attachment.description
119 assert_equal 'File content'.length, attachment.filesize
119 assert_equal 'File content'.length, attachment.filesize
120 end
120 end
121
121
122 def test_upload_as_js_and_destroy
122 def test_upload_as_js_and_destroy
123 log_user('jsmith', 'jsmith')
123 log_user('jsmith', 'jsmith')
124
124
125 token = ajax_upload('myupload.txt', 'File content')
125 token = ajax_upload('myupload.txt', 'File content')
126
126
127 attachment = Attachment.order('id DESC').first
127 attachment = Attachment.order('id DESC').first
128 attachment_path = "/attachments/#{attachment.id}.js?attachment_id=1"
128 attachment_path = "/attachments/#{attachment.id}.js?attachment_id=1"
129 assert_include "href: '#{attachment_path}'", response.body, "Path to attachment: #{attachment_path} not found in response:\n#{response.body}"
129 assert_include "href: '#{attachment_path}'", response.body, "Path to attachment: #{attachment_path} not found in response:\n#{response.body}"
130
130
131 assert_difference 'Attachment.count', -1 do
131 assert_difference 'Attachment.count', -1 do
132 delete attachment_path
132 delete attachment_path
133 assert_response :success
133 assert_response :success
134 end
134 end
135
135
136 assert_include "$('#attachments_1').remove();", response.body
136 assert_include "$('#attachments_1').remove();", response.body
137 end
137 end
138
138
139 def test_download_should_set_sendfile_header
140 set_fixtures_attachments_directory
141 Rack::Sendfile.any_instance.stubs(:variation).returns("X-Sendfile")
142
143 get "/attachments/download/4"
144 assert_response :success
145 assert_not_nil response.headers["X-Sendfile"]
146
147 ensure
148 set_tmp_attachments_directory
149 end
150
139 private
151 private
140
152
141 def ajax_upload(filename, content, attachment_id=1)
153 def ajax_upload(filename, content, attachment_id=1)
142 assert_difference 'Attachment.count' do
154 assert_difference 'Attachment.count' do
143 post "/uploads.js?attachment_id=#{attachment_id}&filename=#{filename}", content, {"CONTENT_TYPE" => 'application/octet-stream'}
155 post "/uploads.js?attachment_id=#{attachment_id}&filename=#{filename}", content, {"CONTENT_TYPE" => 'application/octet-stream'}
144 assert_response :success
156 assert_response :success
145 assert_equal 'text/javascript', response.content_type
157 assert_equal 'text/javascript', response.content_type
146 end
158 end
147
159
148 token = response.body.match(/\.val\('(\d+\.[0-9a-f]+)'\)/)[1]
160 token = response.body.match(/\.val\('(\d+\.[0-9a-f]+)'\)/)[1]
149 assert_not_nil token, "No upload token found in response:\n#{response.body}"
161 assert_not_nil token, "No upload token found in response:\n#{response.body}"
150 token
162 token
151 end
163 end
152 end
164 end
General Comments 0
You need to be logged in to leave comments. Login now