Class: Gitlab::Middleware::CompressedJson

Inherits:
Object
  • Object
show all
Defined in:
lib/gitlab/middleware/compressed_json.rb

Constant Summary collapse

INSTANCE_PACKAGES_PATH =
%r{
  \A/api/v4/packages/npm/-/npm/v1/security/
  (?:(?:advisories/bulk)|(?:audits/quick))\z (?# end)
}xi
GROUP_PACKAGES_PATH =
%r{
  \A/api/v4/groups/
  (?<id>
  [a-zA-Z0-9%-._]{1,255}
  )/-/packages/npm/-/npm/v1/security/
  (?:(?:advisories/bulk)|(?:audits/quick))\z (?# end)
}xi
PROJECT_PACKAGES_PATH =
%r{
  \A/api/v4/projects/
  (?<id>
  [a-zA-Z0-9%-._]{1,255}
  )/packages/npm/-/npm/v1/security/
  (?:(?:advisories/bulk)|(?:audits/quick))\z (?# end)
}xi
MAXIMUM_BODY_SIZE =
200.kilobytes.to_i
UNSAFE_CHARACTERS =
%r{[!"#&'()*+,./:;<>=?@\[\]^`{}|~$]}xi

Instance Method Summary collapse

Constructor Details

#initialize(app) ⇒ CompressedJson

Returns a new instance of CompressedJson.



27
28
29
# File 'lib/gitlab/middleware/compressed_json.rb', line 27

def initialize(app)
  @app = app
end

Instance Method Details

#call(env) ⇒ Object



31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/gitlab/middleware/compressed_json.rb', line 31

def call(env)
  if compressed_et_request?(env)
    input = extract(env['rack.input'])

    if input.length > MAXIMUM_BODY_SIZE
      return too_large
    end

    env.delete('HTTP_CONTENT_ENCODING')
    env['CONTENT_LENGTH'] = input.length
    env['rack.input'] = StringIO.new(input)
  end

  @app.call(env)
end

#compressed_et_request?(env) ⇒ Boolean

Returns:

  • (Boolean)


47
48
49
50
51
52
# File 'lib/gitlab/middleware/compressed_json.rb', line 47

def compressed_et_request?(env)
  post_request?(env) &&
    gzip_encoding?(env) &&
    match_content_type?(env) &&
    match_path?(env)
end

#extract(input) ⇒ Object



62
63
64
# File 'lib/gitlab/middleware/compressed_json.rb', line 62

def extract(input)
  Zlib::GzipReader.new(input).read(MAXIMUM_BODY_SIZE + 1)
end

#gzip_encoding?(env) ⇒ Boolean

Returns:

  • (Boolean)


70
71
72
# File 'lib/gitlab/middleware/compressed_json.rb', line 70

def gzip_encoding?(env)
  env['HTTP_CONTENT_ENCODING'] == 'gzip'
end

#match_content_type?(env) ⇒ Boolean

Returns:

  • (Boolean)


74
75
76
77
78
# File 'lib/gitlab/middleware/compressed_json.rb', line 74

def match_content_type?(env)
  env['CONTENT_TYPE'].nil? ||
    env['CONTENT_TYPE'] == 'application/json' ||
    env['CONTENT_TYPE'] == 'application/x-sentry-envelope'
end

#match_packages_path?(env) ⇒ Boolean

Returns:

  • (Boolean)


84
85
86
87
88
89
90
91
92
93
94
# File 'lib/gitlab/middleware/compressed_json.rb', line 84

def match_packages_path?(env)
  path = env['PATH_INFO'].delete_prefix(relative_url)
  match_data = path.match(INSTANCE_PACKAGES_PATH) ||
    path.match(PROJECT_PACKAGES_PATH) ||
    path.match(GROUP_PACKAGES_PATH)
  return false unless match_data

  return true if match_data.names.empty? # instance level endpoint was matched

  url_encoded?(match_data[:id])
end

#match_path?(env) ⇒ Boolean

Returns:

  • (Boolean)


80
81
82
# File 'lib/gitlab/middleware/compressed_json.rb', line 80

def match_path?(env)
  match_packages_path?(env)
end

#post_request?(env) ⇒ Boolean

Returns:

  • (Boolean)


66
67
68
# File 'lib/gitlab/middleware/compressed_json.rb', line 66

def post_request?(env)
  env['REQUEST_METHOD'] == 'POST'
end

#relative_urlObject



58
59
60
# File 'lib/gitlab/middleware/compressed_json.rb', line 58

def relative_url
  File.join('', Gitlab.config.gitlab.relative_url_root).chomp('/')
end

#too_largeObject



54
55
56
# File 'lib/gitlab/middleware/compressed_json.rb', line 54

def too_large
  [413, { 'Content-Type' => 'text/plain' }, ['Payload Too Large']]
end

#url_encoded?(id) ⇒ Boolean

Returns:

  • (Boolean)


96
97
98
# File 'lib/gitlab/middleware/compressed_json.rb', line 96

def url_encoded?(id)
  id !~ UNSAFE_CHARACTERS
end