summaryrefslogtreecommitdiff
path: root/lib/gitlab
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gitlab')
-rw-r--r--lib/gitlab/auth/request_authenticator.rb25
-rw-r--r--lib/gitlab/auth/user_auth_finders.rb109
-rw-r--r--lib/gitlab/background_migration/populate_merge_requests_latest_merge_request_diff_id.rb30
-rw-r--r--lib/gitlab/database/migration_helpers.rb9
-rw-r--r--lib/gitlab/ee_compat_check.rb6
-rw-r--r--lib/gitlab/git/repository_mirroring.rb4
-rw-r--r--lib/gitlab/git/wiki.rb56
-rw-r--r--lib/gitlab/gitaly_client/attributes_bag.rb31
-rw-r--r--lib/gitlab/gitaly_client/diff.rb16
-rw-r--r--lib/gitlab/gitaly_client/diff_stitcher.rb2
-rw-r--r--lib/gitlab/gitaly_client/wiki_file.rb12
-rw-r--r--lib/gitlab/gitaly_client/wiki_page.rb10
-rw-r--r--lib/gitlab/github_import/parallel_importer.rb4
-rw-r--r--lib/gitlab/hook_data/issue_builder.rb1
-rw-r--r--lib/gitlab/hook_data/merge_request_builder.rb1
-rw-r--r--lib/gitlab/import_export/importer.rb4
-rw-r--r--lib/gitlab/ldap/user.rb5
-rw-r--r--lib/gitlab/middleware/go.rb5
-rw-r--r--lib/gitlab/multi_collection_paginator.rb4
-rw-r--r--lib/gitlab/o_auth/user.rb2
-rw-r--r--lib/gitlab/regex.rb2
-rw-r--r--lib/gitlab/routing.rb6
22 files changed, 283 insertions, 61 deletions
diff --git a/lib/gitlab/auth/request_authenticator.rb b/lib/gitlab/auth/request_authenticator.rb
new file mode 100644
index 00000000000..46ec040ce92
--- /dev/null
+++ b/lib/gitlab/auth/request_authenticator.rb
@@ -0,0 +1,25 @@
+# Use for authentication only, in particular for Rack::Attack.
+# Does not perform authorization of scopes, etc.
+module Gitlab
+ module Auth
+ class RequestAuthenticator
+ include UserAuthFinders
+
+ attr_reader :request
+
+ def initialize(request)
+ @request = request
+ end
+
+ def user
+ find_sessionless_user || find_user_from_warden
+ end
+
+ def find_sessionless_user
+ find_user_from_access_token || find_user_from_rss_token
+ rescue Gitlab::Auth::AuthenticationError
+ nil
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/auth/user_auth_finders.rb b/lib/gitlab/auth/user_auth_finders.rb
new file mode 100644
index 00000000000..b4114a3ac96
--- /dev/null
+++ b/lib/gitlab/auth/user_auth_finders.rb
@@ -0,0 +1,109 @@
+module Gitlab
+ module Auth
+ #
+ # Exceptions
+ #
+
+ AuthenticationError = Class.new(StandardError)
+ MissingTokenError = Class.new(AuthenticationError)
+ TokenNotFoundError = Class.new(AuthenticationError)
+ ExpiredError = Class.new(AuthenticationError)
+ RevokedError = Class.new(AuthenticationError)
+ UnauthorizedError = Class.new(AuthenticationError)
+
+ class InsufficientScopeError < AuthenticationError
+ attr_reader :scopes
+ def initialize(scopes)
+ @scopes = scopes.map { |s| s.try(:name) || s }
+ end
+ end
+
+ module UserAuthFinders
+ include Gitlab::Utils::StrongMemoize
+
+ PRIVATE_TOKEN_HEADER = 'HTTP_PRIVATE_TOKEN'.freeze
+ PRIVATE_TOKEN_PARAM = :private_token
+
+ # Check the Rails session for valid authentication details
+ def find_user_from_warden
+ current_request.env['warden']&.authenticate if verified_request?
+ end
+
+ def find_user_from_rss_token
+ return unless current_request.path.ends_with?('.atom') || current_request.format.atom?
+
+ token = current_request.params[:rss_token].presence
+ return unless token
+
+ User.find_by_rss_token(token) || raise(UnauthorizedError)
+ end
+
+ def find_user_from_access_token
+ return unless access_token
+
+ validate_access_token!
+
+ access_token.user || raise(UnauthorizedError)
+ end
+
+ def validate_access_token!(scopes: [])
+ return unless access_token
+
+ case AccessTokenValidationService.new(access_token, request: request).validate(scopes: scopes)
+ when AccessTokenValidationService::INSUFFICIENT_SCOPE
+ raise InsufficientScopeError.new(scopes)
+ when AccessTokenValidationService::EXPIRED
+ raise ExpiredError
+ when AccessTokenValidationService::REVOKED
+ raise RevokedError
+ end
+ end
+
+ private
+
+ def access_token
+ strong_memoize(:access_token) do
+ find_oauth_access_token || find_personal_access_token
+ end
+ end
+
+ def find_personal_access_token
+ token =
+ current_request.params[PRIVATE_TOKEN_PARAM].presence ||
+ current_request.env[PRIVATE_TOKEN_HEADER].presence
+
+ return unless token
+
+ # Expiration, revocation and scopes are verified in `validate_access_token!`
+ PersonalAccessToken.find_by(token: token) || raise(UnauthorizedError)
+ end
+
+ def find_oauth_access_token
+ token = Doorkeeper::OAuth::Token.from_request(current_request, *Doorkeeper.configuration.access_token_methods)
+ return unless token
+
+ # Expiration, revocation and scopes are verified in `validate_access_token!`
+ oauth_token = OauthAccessToken.by_token(token)
+ raise UnauthorizedError unless oauth_token
+
+ oauth_token.revoke_previous_refresh_token!
+ oauth_token
+ end
+
+ # Check if the request is GET/HEAD, or if CSRF token is valid.
+ def verified_request?
+ Gitlab::RequestForgeryProtection.verified?(current_request.env)
+ end
+
+ def ensure_action_dispatch_request(request)
+ return request if request.is_a?(ActionDispatch::Request)
+
+ ActionDispatch::Request.new(request.env)
+ end
+
+ def current_request
+ @current_request ||= ensure_action_dispatch_request(request)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/background_migration/populate_merge_requests_latest_merge_request_diff_id.rb b/lib/gitlab/background_migration/populate_merge_requests_latest_merge_request_diff_id.rb
new file mode 100644
index 00000000000..7e109e96e73
--- /dev/null
+++ b/lib/gitlab/background_migration/populate_merge_requests_latest_merge_request_diff_id.rb
@@ -0,0 +1,30 @@
+module Gitlab
+ module BackgroundMigration
+ class PopulateMergeRequestsLatestMergeRequestDiffId
+ BATCH_SIZE = 1_000
+
+ class MergeRequest < ActiveRecord::Base
+ self.table_name = 'merge_requests'
+
+ include ::EachBatch
+ end
+
+ def perform(start_id, stop_id)
+ update = '
+ latest_merge_request_diff_id = (
+ SELECT MAX(id)
+ FROM merge_request_diffs
+ WHERE merge_requests.id = merge_request_diffs.merge_request_id
+ )'.squish
+
+ MergeRequest
+ .where(id: start_id..stop_id)
+ .where(latest_merge_request_diff_id: nil)
+ .each_batch(of: BATCH_SIZE) do |relation|
+
+ relation.update_all(update)
+ end
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/database/migration_helpers.rb b/lib/gitlab/database/migration_helpers.rb
index 2c35da8f1aa..c276c3566b4 100644
--- a/lib/gitlab/database/migration_helpers.rb
+++ b/lib/gitlab/database/migration_helpers.rb
@@ -220,6 +220,15 @@ module Gitlab
# column - The name of the column to update.
# value - The value for the column.
#
+ # The `value` argument is typically a literal. To perform a computed
+ # update, an Arel literal can be used instead:
+ #
+ # update_value = Arel.sql('bar * baz')
+ #
+ # update_column_in_batches(:projects, :foo, update_value) do |table, query|
+ # query.where(table[:some_column].eq('hello'))
+ # end
+ #
# Rubocop's Metrics/AbcSize metric is disabled for this method as Rubocop
# determines this method to be too complex while there's no way to make it
# less "complex" without introducing extra methods (which actually will
diff --git a/lib/gitlab/ee_compat_check.rb b/lib/gitlab/ee_compat_check.rb
index 0ea534a5fd0..efc2e46d289 100644
--- a/lib/gitlab/ee_compat_check.rb
+++ b/lib/gitlab/ee_compat_check.rb
@@ -193,7 +193,7 @@ module Gitlab
# Repository is initially cloned with a depth of 20 so we need to fetch
# deeper in the case the branch has more than 20 commits on top of master
fetch(branch: branch, depth: depth)
- fetch(branch: 'master', depth: depth)
+ fetch(branch: 'master', depth: depth, remote: DEFAULT_CE_PROJECT_URL)
merge_base_found?
end
@@ -201,10 +201,10 @@ module Gitlab
raise "\n#{branch} is too far behind master, please rebase it!\n" unless success
end
- def fetch(branch:, depth:)
+ def fetch(branch:, depth:, remote: 'origin')
step(
"Fetching deeper...",
- %W[git fetch --depth=#{depth} --prune origin +refs/heads/#{branch}:refs/remotes/origin/#{branch}]
+ %W[git fetch --depth=#{depth} --prune #{remote} +refs/heads/#{branch}:refs/remotes/origin/#{branch}]
) do |output, status|
raise "Fetch failed: #{output}" unless status.zero?
end
diff --git a/lib/gitlab/git/repository_mirroring.rb b/lib/gitlab/git/repository_mirroring.rb
index 637e7a0659c..4500482d68f 100644
--- a/lib/gitlab/git/repository_mirroring.rb
+++ b/lib/gitlab/git/repository_mirroring.rb
@@ -78,7 +78,7 @@ module Gitlab
def list_remote_tags(remote)
tag_list, exit_code, error = nil
- cmd = %W(#{Gitlab.config.git.bin_path} --git-dir=#{full_path} ls-remote --tags #{remote})
+ cmd = %W(#{Gitlab.config.git.bin_path} --git-dir=#{path} ls-remote --tags #{remote})
Open3.popen3(*cmd) do |stdin, stdout, stderr, wait_thr|
tag_list = stdout.read
@@ -88,7 +88,7 @@ module Gitlab
raise RemoteError, error unless exit_code.zero?
- tag_list.split('\n')
+ tag_list.split("\n")
end
end
end
diff --git a/lib/gitlab/git/wiki.rb b/lib/gitlab/git/wiki.rb
index 022d1f249a9..d4a53d32c28 100644
--- a/lib/gitlab/git/wiki.rb
+++ b/lib/gitlab/git/wiki.rb
@@ -58,12 +58,12 @@ module Gitlab
end
end
- def pages
- @repository.gitaly_migrate(:wiki_get_all_pages) do |is_enabled|
+ def pages(limit: nil)
+ @repository.gitaly_migrate(:wiki_get_all_pages, status: Gitlab::GitalyClient::MigrationStatus::DISABLED) do |is_enabled|
if is_enabled
gitaly_get_all_pages
else
- gollum_get_all_pages
+ gollum_get_all_pages(limit: limit)
end
end
end
@@ -88,14 +88,23 @@ module Gitlab
end
end
- def page_versions(page_path)
+ # options:
+ # :page - The Integer page number.
+ # :per_page - The number of items per page.
+ # :limit - Total number of items to return.
+ def page_versions(page_path, options = {})
current_page = gollum_page_by_path(page_path)
- current_page.versions.map do |gollum_git_commit|
- gollum_page = gollum_wiki.page(current_page.title, gollum_git_commit.id)
- new_version(gollum_page, gollum_git_commit.id)
+
+ commits_from_page(current_page, options).map do |gitlab_git_commit|
+ gollum_page = gollum_wiki.page(current_page.title, gitlab_git_commit.id)
+ Gitlab::Git::WikiPageVersion.new(gitlab_git_commit, gollum_page&.format)
end
end
+ def count_page_versions(page_path)
+ @repository.count_commits(ref: 'HEAD', path: page_path)
+ end
+
def preview_slug(title, format)
# Adapted from gollum gem (Gollum::Wiki#preview_page) to avoid
# using Rugged through a Gollum::Wiki instance
@@ -110,6 +119,22 @@ module Gitlab
private
+ # options:
+ # :page - The Integer page number.
+ # :per_page - The number of items per page.
+ # :limit - Total number of items to return.
+ def commits_from_page(gollum_page, options = {})
+ unless options[:limit]
+ options[:offset] = ([1, options.delete(:page).to_i].max - 1) * Gollum::Page.per_page
+ options[:limit] = (options.delete(:per_page) || Gollum::Page.per_page).to_i
+ end
+
+ @repository.log(ref: gollum_page.last_version.id,
+ path: gollum_page.path,
+ limit: options[:limit],
+ offset: options[:offset])
+ end
+
def gollum_wiki
@gollum_wiki ||= Gollum::Wiki.new(@repository.path)
end
@@ -126,8 +151,17 @@ module Gitlab
end
def new_version(gollum_page, commit_id)
- commit = Gitlab::Git::Commit.find(@repository, commit_id)
- Gitlab::Git::WikiPageVersion.new(commit, gollum_page&.format)
+ Gitlab::Git::WikiPageVersion.new(version(commit_id), gollum_page&.format)
+ end
+
+ def version(commit_id)
+ commit_find_proc = -> { Gitlab::Git::Commit.find(@repository, commit_id) }
+
+ if RequestStore.active?
+ RequestStore.fetch([:wiki_version_commit, commit_id]) { commit_find_proc.call }
+ else
+ commit_find_proc.call
+ end
end
def assert_type!(object, klass)
@@ -185,8 +219,8 @@ module Gitlab
Gitlab::Git::WikiFile.new(gollum_file)
end
- def gollum_get_all_pages
- gollum_wiki.pages.map { |gollum_page| new_page(gollum_page) }
+ def gollum_get_all_pages(limit: nil)
+ gollum_wiki.pages(limit: limit).map { |gollum_page| new_page(gollum_page) }
end
def gitaly_write_page(name, format, content, commit_details)
diff --git a/lib/gitlab/gitaly_client/attributes_bag.rb b/lib/gitlab/gitaly_client/attributes_bag.rb
new file mode 100644
index 00000000000..198a1de91c7
--- /dev/null
+++ b/lib/gitlab/gitaly_client/attributes_bag.rb
@@ -0,0 +1,31 @@
+module Gitlab
+ module GitalyClient
+ # This module expects an `ATTRS` const to be defined on the subclass
+ # See GitalyClient::WikiFile for an example
+ module AttributesBag
+ extend ActiveSupport::Concern
+
+ included do
+ attr_accessor(*const_get(:ATTRS))
+ end
+
+ def initialize(params)
+ params = params.with_indifferent_access
+
+ attributes.each do |attr|
+ instance_variable_set("@#{attr}", params[attr])
+ end
+ end
+
+ def ==(other)
+ attributes.all? do |field|
+ instance_variable_get("@#{field}") == other.instance_variable_get("@#{field}")
+ end
+ end
+
+ def attributes
+ self.class.const_get(:ATTRS)
+ end
+ end
+ end
+end
diff --git a/lib/gitlab/gitaly_client/diff.rb b/lib/gitlab/gitaly_client/diff.rb
index 54df6304865..d98a0ce988f 100644
--- a/lib/gitlab/gitaly_client/diff.rb
+++ b/lib/gitlab/gitaly_client/diff.rb
@@ -1,21 +1,9 @@
module Gitlab
module GitalyClient
class Diff
- FIELDS = %i(from_path to_path old_mode new_mode from_id to_id patch overflow_marker collapsed).freeze
+ ATTRS = %i(from_path to_path old_mode new_mode from_id to_id patch overflow_marker collapsed).freeze
- attr_accessor(*FIELDS)
-
- def initialize(params)
- params.each do |key, val|
- public_send(:"#{key}=", val) # rubocop:disable GitlabSecurity/PublicSend
- end
- end
-
- def ==(other)
- FIELDS.all? do |field|
- public_send(field) == other.public_send(field) # rubocop:disable GitlabSecurity/PublicSend
- end
- end
+ include AttributesBag
end
end
end
diff --git a/lib/gitlab/gitaly_client/diff_stitcher.rb b/lib/gitlab/gitaly_client/diff_stitcher.rb
index 65d81dc5d46..da243ee2d1a 100644
--- a/lib/gitlab/gitaly_client/diff_stitcher.rb
+++ b/lib/gitlab/gitaly_client/diff_stitcher.rb
@@ -12,7 +12,7 @@ module Gitlab
@rpc_response.each do |diff_msg|
if current_diff.nil?
- diff_params = diff_msg.to_h.slice(*GitalyClient::Diff::FIELDS)
+ diff_params = diff_msg.to_h.slice(*GitalyClient::Diff::ATTRS)
# gRPC uses frozen strings by default, and we need to have an unfrozen string as it
# gets processed further down the line. So we unfreeze the first chunk of the patch
# in case it's the only chunk we receive for this diff.
diff --git a/lib/gitlab/gitaly_client/wiki_file.rb b/lib/gitlab/gitaly_client/wiki_file.rb
index a2e415864e6..47c60c92484 100644
--- a/lib/gitlab/gitaly_client/wiki_file.rb
+++ b/lib/gitlab/gitaly_client/wiki_file.rb
@@ -1,17 +1,9 @@
module Gitlab
module GitalyClient
class WikiFile
- FIELDS = %i(name mime_type path raw_data).freeze
+ ATTRS = %i(name mime_type path raw_data).freeze
- attr_accessor(*FIELDS)
-
- def initialize(params)
- params = params.with_indifferent_access
-
- FIELDS.each do |field|
- instance_variable_set("@#{field}", params[field])
- end
- end
+ include AttributesBag
end
end
end
diff --git a/lib/gitlab/gitaly_client/wiki_page.rb b/lib/gitlab/gitaly_client/wiki_page.rb
index 98d96fe6211..7339468e911 100644
--- a/lib/gitlab/gitaly_client/wiki_page.rb
+++ b/lib/gitlab/gitaly_client/wiki_page.rb
@@ -1,16 +1,12 @@
module Gitlab
module GitalyClient
class WikiPage
- FIELDS = %i(title format url_path path name historical raw_data).freeze
+ ATTRS = %i(title format url_path path name historical raw_data).freeze
- attr_accessor(*FIELDS)
+ include AttributesBag
def initialize(params)
- params = params.with_indifferent_access
-
- FIELDS.each do |field|
- instance_variable_set("@#{field}", params[field])
- end
+ super
# All gRPC strings in a response are frozen, so we get an unfrozen
# version here so appending to `raw_data` doesn't blow up.
diff --git a/lib/gitlab/github_import/parallel_importer.rb b/lib/gitlab/github_import/parallel_importer.rb
index 81739834b41..6da11e6ef08 100644
--- a/lib/gitlab/github_import/parallel_importer.rb
+++ b/lib/gitlab/github_import/parallel_importer.rb
@@ -11,6 +11,10 @@ module Gitlab
true
end
+ def self.imports_repository?
+ true
+ end
+
def initialize(project)
@project = project
end
diff --git a/lib/gitlab/hook_data/issue_builder.rb b/lib/gitlab/hook_data/issue_builder.rb
index 196f2b6b34c..e29dd0d5b0e 100644
--- a/lib/gitlab/hook_data/issue_builder.rb
+++ b/lib/gitlab/hook_data/issue_builder.rb
@@ -28,6 +28,7 @@ module Gitlab
SAFE_HOOK_RELATIONS = %i[
assignees
labels
+ total_time_spent
].freeze
attr_accessor :issue
diff --git a/lib/gitlab/hook_data/merge_request_builder.rb b/lib/gitlab/hook_data/merge_request_builder.rb
index 503452c8ff3..ae9b68eb648 100644
--- a/lib/gitlab/hook_data/merge_request_builder.rb
+++ b/lib/gitlab/hook_data/merge_request_builder.rb
@@ -33,6 +33,7 @@ module Gitlab
SAFE_HOOK_RELATIONS = %i[
assignee
labels
+ total_time_spent
].freeze
attr_accessor :merge_request
diff --git a/lib/gitlab/import_export/importer.rb b/lib/gitlab/import_export/importer.rb
index fbdd74788bc..c14646b0611 100644
--- a/lib/gitlab/import_export/importer.rb
+++ b/lib/gitlab/import_export/importer.rb
@@ -1,6 +1,10 @@
module Gitlab
module ImportExport
class Importer
+ def self.imports_repository?
+ true
+ end
+
def initialize(project)
@archive_file = project.import_source
@current_user = project.creator
diff --git a/lib/gitlab/ldap/user.rb b/lib/gitlab/ldap/user.rb
index 4d5c67ed892..3945df27eed 100644
--- a/lib/gitlab/ldap/user.rb
+++ b/lib/gitlab/ldap/user.rb
@@ -9,11 +9,8 @@ module Gitlab
class User < Gitlab::OAuth::User
class << self
def find_by_uid_and_provider(uid, provider)
- uid = Gitlab::LDAP::Person.normalize_dn(uid)
+ identity = ::Identity.with_extern_uid(provider, uid).take
- identity = ::Identity
- .where(provider: provider)
- .where(extern_uid: uid).last
identity && identity.user
end
end
diff --git a/lib/gitlab/middleware/go.rb b/lib/gitlab/middleware/go.rb
index d87e3a17914..c6a56277922 100644
--- a/lib/gitlab/middleware/go.rb
+++ b/lib/gitlab/middleware/go.rb
@@ -42,12 +42,11 @@ module Gitlab
project_url = URI.join(config.gitlab.url, path)
import_prefix = strip_url(project_url.to_s)
- repository_url = case current_application_settings.enabled_git_access_protocol
- when 'ssh'
+ repository_url = if current_application_settings.enabled_git_access_protocol == 'ssh'
shell = config.gitlab_shell
port = ":#{shell.ssh_port}" unless shell.ssh_port == 22
"ssh://#{shell.ssh_user}@#{shell.ssh_host}#{port}/#{path}.git"
- when 'http', nil
+ else
"#{project_url}.git"
end
diff --git a/lib/gitlab/multi_collection_paginator.rb b/lib/gitlab/multi_collection_paginator.rb
index eb3c9002710..c22d0a84860 100644
--- a/lib/gitlab/multi_collection_paginator.rb
+++ b/lib/gitlab/multi_collection_paginator.rb
@@ -55,7 +55,9 @@ module Gitlab
def first_collection_last_page_size
return @first_collection_last_page_size if defined?(@first_collection_last_page_size)
- @first_collection_last_page_size = paginated_first_collection(first_collection_page_count).count
+ @first_collection_last_page_size = paginated_first_collection(first_collection_page_count)
+ .except(:select)
+ .size
end
end
end
diff --git a/lib/gitlab/o_auth/user.rb b/lib/gitlab/o_auth/user.rb
index b4b3b00c84d..552133234a3 100644
--- a/lib/gitlab/o_auth/user.rb
+++ b/lib/gitlab/o_auth/user.rb
@@ -157,7 +157,7 @@ module Gitlab
end
def find_by_uid_and_provider
- identity = Identity.find_by(provider: auth_hash.provider, extern_uid: auth_hash.uid)
+ identity = Identity.with_extern_uid(auth_hash.provider, auth_hash.uid).take
identity && identity.user
end
diff --git a/lib/gitlab/regex.rb b/lib/gitlab/regex.rb
index bd677ec4bf3..2c7b8af83f2 100644
--- a/lib/gitlab/regex.rb
+++ b/lib/gitlab/regex.rb
@@ -25,7 +25,7 @@ module Gitlab
# See https://github.com/docker/distribution/blob/master/reference/regexp.go.
#
def container_repository_name_regex
- @container_repository_regex ||= %r{\A[a-z0-9]+(?:[-._/][a-z0-9]+)*\Z}
+ @container_repository_regex ||= %r{\A[a-z0-9]+((?:[._/]|__|[-])[a-z0-9]+)*\Z}
end
##
diff --git a/lib/gitlab/routing.rb b/lib/gitlab/routing.rb
index 910533076b0..2c994536060 100644
--- a/lib/gitlab/routing.rb
+++ b/lib/gitlab/routing.rb
@@ -46,10 +46,10 @@ module Gitlab
# Only replace the last occurence of `path`.
#
# `request.fullpath` includes the querystring
- path = request.path.sub(%r{/#{path}/*(?!.*#{path})}, "/-/#{path}/")
- path << "?#{request.query_string}" if request.query_string.present?
+ new_path = request.path.sub(%r{/#{path}(/*)(?!.*#{path})}, "/-/#{path}\\1")
+ new_path << "?#{request.query_string}" if request.query_string.present?
- path
+ new_path
end
paths.each do |path|