File: send_file_upload.rb

package info (click to toggle)
gitlab 17.6.5-19
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 629,368 kB
  • sloc: ruby: 1,915,304; javascript: 557,307; sql: 60,639; xml: 6,509; sh: 4,567; makefile: 1,239; python: 406
file content (89 lines) | stat: -rw-r--r-- 3,018 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
# frozen_string_literal: true

module SendFileUpload
  def send_upload(
    file_upload, send_params: {}, redirect_params: {}, attachment: nil, proxy: false,
    disposition: 'attachment')
    content_type = content_type_for(attachment)

    if attachment
      response_disposition = ActionDispatch::Http::ContentDisposition.format(disposition: disposition,
        filename: attachment)

      # 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.
      redirect_params[:query] = { "response-content-disposition" => response_disposition,
                                  "response-content-type" => content_type }
      # 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'

      send_params.merge!(filename: attachment, disposition: disposition)
    end

    if image_scaling_request?(file_upload)
      location = file_upload.file_storage? ? file_upload.path : file_upload.url
      headers.store(*Gitlab::Workhorse.send_scaled_image(location, params[:width].to_i, content_type))
      head :ok
    elsif file_upload.file_storage?
      send_file file_upload.path, send_params
    elsif file_upload.proxy_download_enabled? || proxy
      headers.store(*Gitlab::Workhorse.send_url(file_upload.url(**redirect_params)))
      head :ok
    else
      file_url = ObjectStorage::CDN::FileUrl.new(
        file: file_upload,
        ip_address: request.remote_ip,
        redirect_params: redirect_params)
      redirect_to file_url.url
    end
  end

  def content_type_for(attachment)
    return '' unless attachment

    guess_content_type(attachment)
  end

  def guess_content_type(filename)
    types = MIME::Types.type_for(filename)

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

  private

  def image_scaling_request?(file_upload)
    avatar_safe_for_scaling?(file_upload) || pwa_icon_safe_for_scaling?(file_upload)
  end

  def pwa_icon_safe_for_scaling?(file_upload)
    file_upload.try(:image_safe_for_scaling?) &&
      mounted_as_pwa_icon?(file_upload) &&
      valid_image_scaling_width?(Appearance::ALLOWED_PWA_ICON_SCALER_WIDTHS)
  end

  def avatar_safe_for_scaling?(file_upload)
    file_upload.try(:image_safe_for_scaling?) &&
      mounted_as_avatar?(file_upload) &&
      valid_image_scaling_width?(Avatarable::ALLOWED_IMAGE_SCALER_WIDTHS)
  end

  def mounted_as_avatar?(file_upload)
    file_upload.try(:mounted_as)&.to_sym == :avatar
  end

  def mounted_as_pwa_icon?(file_upload)
    file_upload.try(:mounted_as)&.to_sym == :pwa_icon
  end

  def valid_image_scaling_width?(allowed_scalar_widths)
    allowed_scalar_widths.include?(params[:width]&.to_i)
  end
end