From cb13980db88c1d1ae8a5cd766ced4629c657010b Mon Sep 17 00:00:00 2001
From: Jacob Vosmaer <contact@jacobvosmaer.nl>
Date: Thu, 8 Oct 2015 17:12:00 +0200
Subject: [PATCH] Let gitlab-git-http-server handle archive downloads

This change relies on changes in gitlab_git and gitlab-git-http-server.
---
 .../projects/repositories_controller.rb       | 17 ++-----
 app/services/archive_repository_service.rb    | 45 ++-----------------
 lib/api/repositories.rb                       | 13 +-----
 lib/gitlab/backend/grack_auth.rb              |  9 +++-
 lib/support/nginx/gitlab                      | 20 ++++++++-
 lib/support/nginx/gitlab-ssl                  | 20 ++++++++-
 6 files changed, 54 insertions(+), 70 deletions(-)

diff --git a/app/controllers/projects/repositories_controller.rb b/app/controllers/projects/repositories_controller.rb
index c4a5e2d6359..ba9aea1c165 100644
--- a/app/controllers/projects/repositories_controller.rb
+++ b/app/controllers/projects/repositories_controller.rb
@@ -11,18 +11,9 @@ class Projects::RepositoriesController < Projects::ApplicationController
   end
 
   def archive
-    begin
-      file_path = ArchiveRepositoryService.new(@project, params[:ref], params[:format]).execute
-    rescue
-      return head :not_found
-    end
-
-    if file_path
-      # Send file to user
-      response.headers["Content-Length"] = File.open(file_path).size.to_s
-      send_file file_path
-    else
-      redirect_to request.fullpath
-    end
+    render json: ArchiveRepositoryService.new(@project, params[:ref], params[:format]).execute
+  rescue => ex
+    logger.error("#{self.class.name}: #{ex}")
+    return git_not_found!
   end
 end
diff --git a/app/services/archive_repository_service.rb b/app/services/archive_repository_service.rb
index e1b41527d8d..6414b5a0184 100644
--- a/app/services/archive_repository_service.rb
+++ b/app/services/archive_repository_service.rb
@@ -9,17 +9,10 @@ class ArchiveRepositoryService
   def execute(options = {})
     project.repository.clean_old_archives
 
-    raise "No archive file path" unless file_path
+    metadata = project.repository.archive_metadata(ref, storage_path, format)
+    raise "Repository or ref not found" if metadata.empty?
 
-    return file_path if archived?
-
-    unless archiving?
-      RepositoryArchiveWorker.perform_async(project.id, ref, format)
-    end
-
-    archived = wait_until_archived(options[:timeout] || 5.0)
-
-    file_path if archived
+    metadata
   end
 
   private
@@ -27,36 +20,4 @@ class ArchiveRepositoryService
   def storage_path
     Gitlab.config.gitlab.repository_downloads_path
   end
-
-  def file_path
-    @file_path ||= project.repository.archive_file_path(ref, storage_path, format)
-  end
-
-  def pid_file_path
-    @pid_file_path ||= project.repository.archive_pid_file_path(ref, storage_path, format)
-  end
-
-  def archived?
-    File.exist?(file_path)
-  end
-
-  def archiving?
-    File.exist?(pid_file_path)
-  end
-
-  def wait_until_archived(timeout = 5.0)
-    return archived? if timeout == 0.0
-    
-    t1 = Time.now
-
-    begin
-      sleep 0.1
-
-      success = archived?
-
-      t2 = Time.now
-    end until success || t2 - t1 >= timeout
-
-    success
-  end
 end
diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb
index 2d96c9666d2..20d568cf462 100644
--- a/lib/api/repositories.rb
+++ b/lib/api/repositories.rb
@@ -133,7 +133,7 @@ module API
         authorize! :download_code, user_project
 
         begin
-          file_path = ArchiveRepositoryService.new(
+          ArchiveRepositoryService.new(
             user_project,
             params[:sha],
             params[:format]
@@ -141,17 +141,6 @@ module API
         rescue
           not_found!('File')
         end
-
-        if file_path && File.exists?(file_path)
-          data = File.open(file_path, 'rb').read
-          basename = File.basename(file_path)
-          header['Content-Disposition'] = "attachment; filename=\"#{basename}\""
-          content_type MIME::Types.type_for(file_path).first.content_type
-          env['api.format'] = :binary
-          present data
-        else
-          redirect request.fullpath
-        end
       end
 
       # Compare two branches, tags or commits
diff --git a/lib/gitlab/backend/grack_auth.rb b/lib/gitlab/backend/grack_auth.rb
index 0353b3b7ed3..6830a916bcb 100644
--- a/lib/gitlab/backend/grack_auth.rb
+++ b/lib/gitlab/backend/grack_auth.rb
@@ -193,7 +193,14 @@ module Grack
     end
 
     def render_grack_auth_ok
-      [200, { "Content-Type" => "application/json" }, [JSON.dump({ 'GL_ID' => Gitlab::ShellEnv.gl_id(@user) })]]
+      [
+        200,
+        { "Content-Type" => "application/json" },
+        [JSON.dump({
+          'GL_ID' => Gitlab::ShellEnv.gl_id(@user),
+          'RepoPath' => project.repository.path_to_repo,
+        })]
+      ]
     end
 
     def render_not_found
diff --git a/lib/support/nginx/gitlab b/lib/support/nginx/gitlab
index 7218a4d2f20..ffc0eb0585c 100644
--- a/lib/support/nginx/gitlab
+++ b/lib/support/nginx/gitlab
@@ -113,7 +113,25 @@ server {
     proxy_pass http://gitlab;
   }
 
-  location ~ [-\/\w\.]+\.git\/ {
+  location ~ ^/[\w\.-]+/[\w\.-]+/(info/refs|git-upload-pack|git-receive-pack)$ {
+    # 'Error' 418 is a hack to re-use the @gitlab-git-http-server block
+    error_page 418 = @gitlab-git-http-server;
+    return 418;
+  }
+
+  location ~ ^/[\w\.-]+/[\w\.-]+/repository/archive {
+    # 'Error' 418 is a hack to re-use the @gitlab-git-http-server block
+    error_page 418 = @gitlab-git-http-server;
+    return 418;
+  }
+
+  location ~ ^/api/v3/projects/[0-9]+/repository/archive {
+    # 'Error' 418 is a hack to re-use the @gitlab-git-http-server block
+    error_page 418 = @gitlab-git-http-server;
+    return 418;
+  }
+
+  location @gitlab-git-http-server {
     ## If you use HTTPS make sure you disable gzip compression
     ## to be safe against BREACH attack.
     # gzip off;
diff --git a/lib/support/nginx/gitlab-ssl b/lib/support/nginx/gitlab-ssl
index 7dabfba87e2..c2e9f8864f8 100644
--- a/lib/support/nginx/gitlab-ssl
+++ b/lib/support/nginx/gitlab-ssl
@@ -160,7 +160,25 @@ server {
     proxy_pass http://gitlab;
   }
 
-  location ~ [-\/\w\.]+\.git\/ {
+  location ~ ^/[\w\.-]+/[\w\.-]+/(info/refs|git-upload-pack|git-receive-pack)$ {
+    # 'Error' 418 is a hack to re-use the @gitlab-git-http-server block
+    error_page 418 = @gitlab-git-http-server;
+    return 418;
+  }
+
+  location ~ ^/[\w\.-]+/[\w\.-]+/repository/archive {
+    # 'Error' 418 is a hack to re-use the @gitlab-git-http-server block
+    error_page 418 = @gitlab-git-http-server;
+    return 418;
+  }
+
+  location ~ ^/api/v3/projects/[0-9]+/repository/archive {
+    # 'Error' 418 is a hack to re-use the @gitlab-git-http-server block
+    error_page 418 = @gitlab-git-http-server;
+    return 418;
+  }
+
+  location @gitlab-git-http-server {
     ## If you use HTTPS make sure you disable gzip compression
     ## to be safe against BREACH attack.
     gzip off;
-- 
GitLab