From 2a76f5f2f9293f82f8762804853dc571d97af529 Mon Sep 17 00:00:00 2001 From: scherphy Date: Fri, 23 Oct 2015 09:42:48 +0900 Subject: [PATCH] =?UTF-8?q?x-sendfile=E3=81=AE=E6=9C=89=E5=8A=B9=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Issues #1 x-sendfileを有効にする への対応. --- roles/apache/tasks/main.yml | 22 ++ .../templates/attachments_controller.rb | 192 ++++++++++++++++++ roles/apache/templates/production.rb | 29 +++ roles/apache/templates/redmine.conf | 4 + 4 files changed, 247 insertions(+) create mode 100644 roles/apache/templates/attachments_controller.rb create mode 100644 roles/apache/templates/production.rb diff --git a/roles/apache/tasks/main.yml b/roles/apache/tasks/main.yml index 84c15ba..187126f 100644 --- a/roles/apache/tasks/main.yml +++ b/roles/apache/tasks/main.yml @@ -2,6 +2,28 @@ sudo: yes yum: name='httpd,httpd-devel' +- name: mod_xsendfile.cのダウンロード + get_url: + url=https://tn123.org/mod_xsendfile/mod_xsendfile.c + dest={{ work_dir }} + +- name: mod_xsendfile.cのコンパイル + sudo: yes + command: + /usr/bin/apxs -cia {{ work_dir }}/mod_xsendfile.c + +- name: attachment_controller.rbへの適用 + sudo: yes + template: + src=attachments_controller.rb + dest=/var/lib/redmine/app/controllers/attachments_controller.rb + +- name: production.rbへの適用 + sudo: yes + template: + src=production.rb + dest=/var/lib/redmine/config/environments/production.rb + - name: Redmineディレクトリ以下のオーナーを変更 sudo: yes command: diff --git a/roles/apache/templates/attachments_controller.rb b/roles/apache/templates/attachments_controller.rb new file mode 100644 index 0000000..6048cab --- /dev/null +++ b/roles/apache/templates/attachments_controller.rb @@ -0,0 +1,192 @@ +# Redmine - project management software +# Copyright (C) 2006-2015 Jean-Philippe Lang +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +class AttachmentsController < ApplicationController + before_filter :find_attachment, :only => [:show, :download, :thumbnail, :destroy] + before_filter :find_editable_attachments, :only => [:edit, :update] + before_filter :file_readable, :read_authorize, :only => [:show, :download, :thumbnail] + before_filter :delete_authorize, :only => :destroy + before_filter :authorize_global, :only => :upload + + accept_api_auth :show, :download, :thumbnail, :upload + + def show + respond_to do |format| + format.html { + if @attachment.is_diff? + @diff = File.new(@attachment.diskfile, "rb").read + @diff_type = params[:type] || User.current.pref[:diff_type] || 'inline' + @diff_type = 'inline' unless %w(inline sbs).include?(@diff_type) + # Save diff type as user preference + if User.current.logged? && @diff_type != User.current.pref[:diff_type] + User.current.pref[:diff_type] = @diff_type + User.current.preference.save + end + render :action => 'diff' + elsif @attachment.is_text? && @attachment.filesize <= Setting.file_max_size_displayed.to_i.kilobyte + @content = File.new(@attachment.diskfile, "rb").read + render :action => 'file' + else + download + end + } + format.api + end + end + + def download + if @attachment.container.is_a?(Version) || @attachment.container.is_a?(Project) + @attachment.increment_download + end + + if stale?(:etag => @attachment.digest) + # images are sent inline + send_file @attachment.diskfile, :filename => filename_for_content_disposition(@attachment.filename), + :type => detect_content_type(@attachment), + :disposition => (@attachment.image? ? 'inline' : 'attachment'), + :x_sendfile => true + end + end + + def thumbnail + if @attachment.thumbnailable? && tbnail = @attachment.thumbnail(:size => params[:size]) + if stale?(:etag => tbnail) + send_file tbnail, + :filename => filename_for_content_disposition(@attachment.filename), + :type => detect_content_type(@attachment), + :disposition => 'inline' + end + else + # No thumbnail for the attachment or thumbnail could not be created + render :nothing => true, :status => 404 + end + end + + def upload + # Make sure that API users get used to set this content type + # as it won't trigger Rails' automatic parsing of the request body for parameters + unless request.content_type == 'application/octet-stream' + render :nothing => true, :status => 406 + return + end + + @attachment = Attachment.new(:file => request.raw_post) + @attachment.author = User.current + @attachment.filename = params[:filename].presence || Redmine::Utils.random_hex(16) + @attachment.content_type = params[:content_type].presence + saved = @attachment.save + + respond_to do |format| + format.js + format.api { + if saved + render :action => 'upload', :status => :created + else + render_validation_errors(@attachment) + end + } + end + end + + def edit + end + + def update + if params[:attachments].is_a?(Hash) + if Attachment.update_attachments(@attachments, params[:attachments]) + redirect_back_or_default home_path + return + end + end + render :action => 'edit' + end + + def destroy + if @attachment.container.respond_to?(:init_journal) + @attachment.container.init_journal(User.current) + end + if @attachment.container + # Make sure association callbacks are called + @attachment.container.attachments.delete(@attachment) + else + @attachment.destroy + end + + respond_to do |format| + format.html { redirect_to_referer_or project_path(@project) } + format.js + end + end + + private + + def find_attachment + @attachment = Attachment.find(params[:id]) + # Show 404 if the filename in the url is wrong + raise ActiveRecord::RecordNotFound if params[:filename] && params[:filename] != @attachment.filename + @project = @attachment.project + rescue ActiveRecord::RecordNotFound + render_404 + end + + def find_editable_attachments + klass = params[:object_type].to_s.singularize.classify.constantize rescue nil + unless klass && klass.reflect_on_association(:attachments) + render_404 + return + end + + @container = klass.find(params[:object_id]) + if @container.respond_to?(:visible?) && !@container.visible? + render_403 + return + end + @attachments = @container.attachments.select(&:editable?) + if @container.respond_to?(:project) + @project = @container.project + end + render_404 if @attachments.empty? + rescue ActiveRecord::RecordNotFound + render_404 + end + + # Checks that the file exists and is readable + def file_readable + if @attachment.readable? + true + else + logger.error "Cannot send attachment, #{@attachment.diskfile} does not exist or is unreadable." + render_404 + end + end + + def read_authorize + @attachment.visible? ? true : deny_access + end + + def delete_authorize + @attachment.deletable? ? true : deny_access + end + + def detect_content_type(attachment) + content_type = attachment.content_type + if content_type.blank? || content_type == "application/octet-stream" + content_type = Redmine::MimeType.of(attachment.filename) + end + content_type.to_s + end +end diff --git a/roles/apache/templates/production.rb b/roles/apache/templates/production.rb new file mode 100644 index 0000000..03a8fb2 --- /dev/null +++ b/roles/apache/templates/production.rb @@ -0,0 +1,29 @@ +Rails.application.configure do + # Settings specified here will take precedence over those in config/application.rb + + config.log_level = :info + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + config.action_controller.perform_caching = true + + # Disable delivery errors + config.action_mailer.raise_delivery_errors = false + + # No email in production log + config.action_mailer.logger = nil + + # Print deprecation notices to the Rails logger. + config.active_support.deprecation = :log + + config.action_dispatch.x_sendfile_header = "X-Sendfile" +end diff --git a/roles/apache/templates/redmine.conf b/roles/apache/templates/redmine.conf index f011fb5..9075ffa 100644 --- a/roles/apache/templates/redmine.conf +++ b/roles/apache/templates/redmine.conf @@ -1,6 +1,10 @@ Require all granted + + XSendFilePath /var/lib/redmine/files + XSendFile on + {{ passenger_snippet_vars.stdout }}