mirror of
https://github.com/codeninjasllc/discourse.git
synced 2024-11-27 17:46:05 -05:00
proper content-disposition header when downloading attachments
This commit is contained in:
parent
eae7e75611
commit
45b838009c
8 changed files with 94 additions and 42 deletions
|
@ -252,8 +252,7 @@ Discourse.ComposerView = Discourse.View.extend({
|
||||||
|
|
||||||
$uploadTarget.fileupload({
|
$uploadTarget.fileupload({
|
||||||
url: Discourse.getURL('/uploads'),
|
url: Discourse.getURL('/uploads'),
|
||||||
dataType: 'json',
|
dataType: 'json'
|
||||||
timeout: 20000
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// submit - this event is triggered for each upload
|
// submit - this event is triggered for each upload
|
||||||
|
|
|
@ -24,7 +24,6 @@ class TopicsController < ApplicationController
|
||||||
skip_before_filter :check_xhr, only: [:show, :feed]
|
skip_before_filter :check_xhr, only: [:show, :feed]
|
||||||
|
|
||||||
def show
|
def show
|
||||||
|
|
||||||
# We'd like to migrate the wordpress feed to another url. This keeps up backwards compatibility with
|
# We'd like to migrate the wordpress feed to another url. This keeps up backwards compatibility with
|
||||||
# existing installs.
|
# existing installs.
|
||||||
return wordpress if params[:best].present?
|
return wordpress if params[:best].present?
|
||||||
|
@ -33,7 +32,6 @@ class TopicsController < ApplicationController
|
||||||
begin
|
begin
|
||||||
@topic_view = TopicView.new(params[:id] || params[:topic_id], current_user, opts)
|
@topic_view = TopicView.new(params[:id] || params[:topic_id], current_user, opts)
|
||||||
rescue Discourse::NotFound
|
rescue Discourse::NotFound
|
||||||
Rails.logger.info ">>>> B"
|
|
||||||
topic = Topic.where(slug: params[:id]).first if params[:id]
|
topic = Topic.where(slug: params[:id]).first if params[:id]
|
||||||
raise Discourse::NotFound unless topic
|
raise Discourse::NotFound unless topic
|
||||||
return redirect_to(topic.relative_url)
|
return redirect_to(topic.relative_url)
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
class UploadsController < ApplicationController
|
class UploadsController < ApplicationController
|
||||||
before_filter :ensure_logged_in
|
before_filter :ensure_logged_in, except: [:show]
|
||||||
|
skip_before_filter :check_xhr, only: [:show]
|
||||||
|
|
||||||
def create
|
def create
|
||||||
file = params[:file] || params[:files].first
|
file = params[:file] || params[:files].first
|
||||||
|
@ -28,4 +29,18 @@ class UploadsController < ApplicationController
|
||||||
render status: 422, text: I18n.t("upload.images.size_not_found")
|
render status: 422, text: I18n.t("upload.images.size_not_found")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def show
|
||||||
|
return render nothing: true, status: 404 unless Discourse.store.internal?
|
||||||
|
|
||||||
|
id = params[:id].to_i
|
||||||
|
url = request.fullpath
|
||||||
|
|
||||||
|
# the "url" parameter is here to prevent people from scanning the uploads using the id
|
||||||
|
upload = Upload.where(id: id, url: url).first
|
||||||
|
|
||||||
|
return render nothing: true, status: 404 unless upload
|
||||||
|
|
||||||
|
send_file(Discourse.store.path_for(upload), filename: upload.original_filename)
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -22,50 +22,60 @@ server {
|
||||||
sendfile on;
|
sendfile on;
|
||||||
|
|
||||||
keepalive_timeout 65;
|
keepalive_timeout 65;
|
||||||
|
|
||||||
|
# maximum file upload size (keep up to date when changing the corresponding site setting)
|
||||||
client_max_body_size 2m;
|
client_max_body_size 2m;
|
||||||
|
|
||||||
|
# path to discourse's public directory
|
||||||
|
set $public /var/www/discourse/public;
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
root /var/www/discourse/public;
|
root $public;
|
||||||
|
|
||||||
## optional upload anti-hotlinking rules
|
location ~ ^/assets/ {
|
||||||
#location ~ ^/uploads/ {
|
|
||||||
# valid_referers none blocked mysite.com *.mysite.com;
|
|
||||||
# if ($invalid_referer) {
|
|
||||||
# return 403;
|
|
||||||
# }
|
|
||||||
#}
|
|
||||||
|
|
||||||
## [LEGACY] this is deprecated, leaving it there for a small transition period
|
|
||||||
location ~ ^/t\/[0-9]+\/[0-9]+\/avatar {
|
|
||||||
expires 1d;
|
|
||||||
add_header Cache-Control public;
|
|
||||||
add_header ETag "";
|
|
||||||
}
|
|
||||||
|
|
||||||
location ~ ^/(assets|uploads)/ {
|
|
||||||
expires 1y;
|
expires 1y;
|
||||||
add_header Cache-Control public;
|
add_header Cache-Control public;
|
||||||
add_header ETag "";
|
add_header ETag "";
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
location ~ ^/uploads/ {
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
expires 1y;
|
||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
add_header Cache-Control public;
|
||||||
proxy_set_header Host $http_host;
|
add_header ETag "";
|
||||||
|
|
||||||
|
## optional upload anti-hotlinking rules
|
||||||
|
#valid_referers none blocked mysite.com *.mysite.com;
|
||||||
|
#if ($invalid_referer) {
|
||||||
|
# return 403;
|
||||||
|
#}
|
||||||
|
|
||||||
# If the file exists as a static file serve it directly without
|
# let NGINX serve images
|
||||||
# running all the other rewrite tests on it
|
location ~* \.(gif|png|jpg|jpeg|bmp|tif|tiff)$ { try_files $uri =404; }
|
||||||
if (-f $request_filename) {
|
location ~ /_optimized/ { try_files $uri =404; }
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!-f $request_filename) {
|
# attachments must go through the rails application to get the right content-disposition header
|
||||||
|
proxy_set_header X-Sendfile-Type X-Accel-Redirect;
|
||||||
|
proxy_set_header X-Accel-Mapping $public/=/downloads/;
|
||||||
proxy_pass http://discourse;
|
proxy_pass http://discourse;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try_files $uri @discourse;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /downloads/ {
|
||||||
|
internal;
|
||||||
|
alias $public/;
|
||||||
|
}
|
||||||
|
|
||||||
|
location @discourse {
|
||||||
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
|
proxy_set_header Host $http_host;
|
||||||
|
|
||||||
|
proxy_pass http://discourse;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -146,7 +146,8 @@ Discourse::Application.routes.draw do
|
||||||
get 'users/:username/activity' => 'users#show', constraints: {username: USERNAME_ROUTE_FORMAT}
|
get 'users/:username/activity' => 'users#show', constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||||
get 'users/:username/activity/:filter' => 'users#show', constraints: {username: USERNAME_ROUTE_FORMAT}
|
get 'users/:username/activity/:filter' => 'users#show', constraints: {username: USERNAME_ROUTE_FORMAT}
|
||||||
|
|
||||||
resources :uploads
|
get 'uploads/:site/:id/:sha.:extension' => 'uploads#show', constraints: {site: /\w+/, id: /\d+/, sha: /[a-z0-9]{15,16}/i, extension: /\w{2,}/}
|
||||||
|
post 'uploads' => 'uploads#create'
|
||||||
|
|
||||||
get 'posts/by_number/:topic_id/:post_number' => 'posts#by_number'
|
get 'posts/by_number/:topic_id/:post_number' => 'posts#by_number'
|
||||||
get 'posts/:id/reply-history' => 'posts#reply_history'
|
get 'posts/:id/reply-history' => 'posts#reply_history'
|
||||||
|
|
5
db/migrate/20130906171631_add_index_to_uploads.rb
Normal file
5
db/migrate/20130906171631_add_index_to_uploads.rb
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
class AddIndexToUploads < ActiveRecord::Migration
|
||||||
|
def change
|
||||||
|
add_index :uploads, [:id, :url]
|
||||||
|
end
|
||||||
|
end
|
|
@ -2,17 +2,15 @@ require 'spec_helper'
|
||||||
|
|
||||||
describe UploadsController do
|
describe UploadsController do
|
||||||
|
|
||||||
it 'requires you to be logged in' do
|
context '.create' do
|
||||||
-> { xhr :post, :create }.should raise_error(Discourse::NotLoggedIn)
|
|
||||||
end
|
|
||||||
|
|
||||||
context 'logged in' do
|
it 'requires you to be logged in' do
|
||||||
|
-> { xhr :post, :create }.should raise_error(Discourse::NotLoggedIn)
|
||||||
before do
|
|
||||||
@user = log_in :user
|
|
||||||
end
|
end
|
||||||
|
|
||||||
context '.create' do
|
context 'logged in' do
|
||||||
|
|
||||||
|
before { @user = log_in :user }
|
||||||
|
|
||||||
let(:logo) do
|
let(:logo) do
|
||||||
ActionDispatch::Http::UploadedFile.new({
|
ActionDispatch::Http::UploadedFile.new({
|
||||||
|
@ -97,4 +95,29 @@ describe UploadsController do
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context '.show' do
|
||||||
|
|
||||||
|
it "returns 404 when using external storage" do
|
||||||
|
store = stub(internal?: false)
|
||||||
|
Discourse.stubs(:store).returns(store)
|
||||||
|
Upload.expects(:where).never
|
||||||
|
get :show, site: "default", id: 1, sha: "1234567890abcdef", extension: "pdf"
|
||||||
|
response.response_code.should == 404
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns 404 when the upload doens't exist" do
|
||||||
|
Upload.expects(:where).with(id: 2, url: "/uploads/default/2/1234567890abcdef.pdf").returns [nil]
|
||||||
|
get :show, site: "default", id: 2, sha: "1234567890abcdef", extension: "pdf"
|
||||||
|
response.response_code.should == 404
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'uses send_file' do
|
||||||
|
Fabricate(:attachment)
|
||||||
|
controller.stubs(:render)
|
||||||
|
controller.expects(:send_file)
|
||||||
|
get :show, site: "default", id: 42, sha: "66b3ed1503efc936", extension: "zip"
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -9,8 +9,9 @@ Fabricator(:upload) do
|
||||||
end
|
end
|
||||||
|
|
||||||
Fabricator(:attachment, from: :upload) do
|
Fabricator(:attachment, from: :upload) do
|
||||||
|
id 42
|
||||||
user
|
user
|
||||||
original_filename "archive.zip"
|
original_filename "archive.zip"
|
||||||
filesize 1234
|
filesize 1234
|
||||||
url "/uploads/default/186/66b3ed1503efc936.zip"
|
url "/uploads/default/42/66b3ed1503efc936.zip"
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue