send_file_upload.rb 2.21 KB
Newer Older
1
2
# frozen_string_literal: true

3
module SendFileUpload
4
  def send_upload(file_upload, send_params: {}, redirect_params: {}, attachment: nil, proxy: false, disposition: 'attachment')
5
    if attachment
6
      response_disposition = ::Gitlab::ContentDisposition.format(disposition: disposition, filename: attachment)
Stan Hu's avatar
Stan Hu committed
7

8
9
10
      # Response-Content-Type will not override an existing Content-Type in
      # Google Cloud Storage, so the metadata needs to be cleared on GCS for
      # this to work. However, this override works with AWS.
Stan Hu's avatar
Stan Hu committed
11
      redirect_params[:query] = { "response-content-disposition" => response_disposition,
12
                                  "response-content-type" => guess_content_type(attachment) }
13
14
15
16
      # By default, Rails will send uploads with an extension of .js with a
      # content-type of text/javascript, which will trigger Rails'
      # cross-origin JavaScript protection.
      send_params[:content_type] = 'text/plain' if File.extname(attachment) == '.js'
Stan Hu's avatar
Stan Hu committed
17
18

      send_params.merge!(filename: attachment, disposition: utf8_encoded_disposition(disposition, attachment))
19
20
21
22
    end

    if file_upload.file_storage?
      send_file file_upload.path, send_params
23
    elsif file_upload.class.proxy_download_enabled? || proxy
Micaël Bergeron's avatar
Micaël Bergeron committed
24
25
      headers.store(*Gitlab::Workhorse.send_url(file_upload.url(**redirect_params)))
      head :ok
26
27
28
29
    else
      redirect_to file_upload.url(**redirect_params)
    end
  end
30

Stan Hu's avatar
Stan Hu committed
31
32
33
34
35
36
37
38
39
40
41
42
  # Since Rails 5 doesn't properly support support non-ASCII filenames,
  # we have to add our own to ensure RFC 5987 compliance. However, Rails
  # 5 automatically appends `filename#{filename}` here:
  # https://github.com/rails/rails/blob/v5.0.7/actionpack/lib/action_controller/metal/data_streaming.rb#L137
  # Rails 6 will have https://github.com/rails/rails/pull/33829, so we
  # can get rid of this special case handling when we upgrade.
  def utf8_encoded_disposition(disposition, filename)
    content = ::Gitlab::ContentDisposition.new(disposition: disposition, filename: filename)

    "#{disposition}; #{content.utf8_filename}"
  end

43
44
45
46
47
48
49
50
51
  def guess_content_type(filename)
    types = MIME::Types.type_for(filename)

    if types.present?
      types.first.content_type
    else
      "application/octet-stream"
    end
  end
52
end