summaryrefslogtreecommitdiff
path: root/lib/gitlab/import_export/after_export_strategies/web_upload_strategy.rb
blob: fe0ab01e4fdb0279d61299219735abcfbf301675 (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
93
94
95
# frozen_string_literal: true

module Gitlab
  module ImportExport
    module AfterExportStrategies
      class WebUploadStrategy < BaseAfterExportStrategy
        PUT_METHOD = 'PUT'
        POST_METHOD = 'POST'
        INVALID_HTTP_METHOD = 'invalid. Only PUT and POST methods allowed.'

        validates :url, addressable_url: true

        validate do
          unless [PUT_METHOD, POST_METHOD].include?(http_method.upcase)
            errors.add(:http_method, INVALID_HTTP_METHOD)
          end
        end

        def initialize(url:, http_method: PUT_METHOD)
          super
        end

        protected

        def strategy_execute
          log_info(message: "Started uploading project", export_size: export_size)

          upload_duration = Benchmark.realtime do
            if project.export_file.file_storage?
              handle_response_error(send_file)
            else
              upload_project_as_remote_stream
            end
          end

          log_info(message: "Finished uploading project", export_size: export_size, upload_duration: upload_duration)
        end

        def handle_response_error(response)
          unless response.success?
            raise StrategyError, "Error uploading the project. Code #{response.code}: #{response.message}"
          end
        end

        def delete_export?
          false
        end

        private

        def send_file
          Gitlab::HTTP.public_send(http_method.downcase, url, send_file_options) # rubocop:disable GitlabSecurity/PublicSend
        ensure
          export_file.close if export_file
        end

        def upload_project_as_remote_stream
          Gitlab::ImportExport::RemoteStreamUpload.new(
            download_url: project.export_file.url,
            upload_url: url,
            options: {
              upload_method: http_method.downcase.to_sym,
              upload_content_type: 'application/gzip'
            }).execute
        rescue Gitlab::ImportExport::RemoteStreamUpload::StreamError => e
          log_error(message: e.message, response_body: e.response_body.truncate(3000))

          raise
        end

        def export_file
          @export_file ||= project.export_file.open
        end

        def send_file_options
          {
            body_stream: export_file,
            headers: headers
          }
        end

        def headers
          {
            'Content-Type' => 'application/gzip',
            'Content-Length' => export_size.to_s
          }
        end

        def export_size
          project.export_file.file.size
        end
      end
    end
  end
end