summaryrefslogtreecommitdiff
path: root/spec/support/helpers/workhorse_helpers.rb
blob: e0fba191deb68873ea6709e0855729a450448b86 (plain)
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
90
91
92
# frozen_string_literal: true

module WorkhorseHelpers
  extend self

  def workhorse_send_data
    @_workhorse_send_data ||= begin
      header = response.headers[Gitlab::Workhorse::SEND_DATA_HEADER]
      split_header = header.split(':')
      type = split_header.shift
      header = split_header.join(':')
      [
        type,
        JSON.parse(Base64.urlsafe_decode64(header))
      ]
    end
  end

  def workhorse_internal_api_request_header
    { 'HTTP_' + Gitlab::Workhorse::INTERNAL_API_REQUEST_HEADER.upcase.tr('-', '_') => jwt_token }
  end

  # workhorse_post_with_file will transform file_key inside params as if it was disk accelerated by workhorse
  def workhorse_post_with_file(url, file_key:, params:)
    workhorse_request_with_file(:post, url,
                                file_key: file_key,
                                params: params,
                                env: { 'CONTENT_TYPE' => 'multipart/form-data' },
                                send_rewritten_field: true
    )
  end

  # workhorse_finalize will transform file_key inside params as if it was the finalize call of an inline object storage upload.
  # note that based on the content of the params it can simulate a disc acceleration or an object storage upload
  def workhorse_finalize(url, method: :post, file_key:, params:, headers: {})
    workhorse_request_with_file(method, url,
                                file_key: file_key,
                                params: params,
                                extra_headers: headers,
                                send_rewritten_field: false
    )
  end

  def workhorse_request_with_file(method, url, file_key:, params:, env: {}, extra_headers: {}, send_rewritten_field:)
    workhorse_params = params.dup
    file = workhorse_params.delete(file_key)

    workhorse_params = workhorse_disk_accelerated_file_params(file_key, file).merge(workhorse_params)

    headers = if send_rewritten_field
                workhorse_rewritten_fields_header(file_key => file.path)
              else
                {}
              end

    headers.merge!(extra_headers)

    process(method, url, params: workhorse_params, headers: headers, env: env)
  end

  private

  def jwt_token(data = {})
    JWT.encode({ 'iss' => 'gitlab-workhorse' }.merge(data), Gitlab::Workhorse.secret, 'HS256')
  end

  def workhorse_rewritten_fields_header(fields)
    { Gitlab::Middleware::Multipart::RACK_ENV_KEY => jwt_token('rewritten_fields' => fields) }
  end

  def workhorse_disk_accelerated_file_params(key, file)
    return {} unless file

    {
      "#{key}.name" => file.original_filename,
      "#{key}.size" => file.size
    }.tap do |params|
      params["#{key}.path"] = file.path if file.path
      params["#{key}.remote_id"] = file.remote_id if file.respond_to?(:remote_id) && file.remote_id
    end
  end

  def fog_to_uploaded_file(file)
    filename = File.basename(file.key)

    UploadedFile.new(nil,
                     filename: filename,
                     remote_id: filename,
                     size: file.content_length
                    )
  end
end