Line data Source code
1 : // Copyright (C) 2008 The Android Open Source Project 2 : // 3 : // Licensed under the Apache License, Version 2.0 (the "License"); 4 : // you may not use this file except in compliance with the License. 5 : // You may obtain a copy of the License at 6 : // 7 : // http://www.apache.org/licenses/LICENSE-2.0 8 : // 9 : // Unless required by applicable law or agreed to in writing, software 10 : // distributed under the License is distributed on an "AS IS" BASIS, 11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 : // See the License for the specific language governing permissions and 13 : // limitations under the License. 14 : 15 : package com.google.gerrit.sshd.commands; 16 : 17 : import com.google.common.collect.ImmutableList; 18 : import com.google.common.collect.Lists; 19 : import com.google.gerrit.extensions.registration.DynamicSet; 20 : import com.google.gerrit.extensions.restapi.AuthException; 21 : import com.google.gerrit.server.RequestInfo; 22 : import com.google.gerrit.server.RequestListener; 23 : import com.google.gerrit.server.git.PermissionAwareRepositoryManager; 24 : import com.google.gerrit.server.git.TracingHook; 25 : import com.google.gerrit.server.git.TransferConfig; 26 : import com.google.gerrit.server.git.UploadPackInitializer; 27 : import com.google.gerrit.server.git.UsersSelfAdvertiseRefsHook; 28 : import com.google.gerrit.server.git.validators.UploadValidationException; 29 : import com.google.gerrit.server.git.validators.UploadValidators; 30 : import com.google.gerrit.server.logging.TraceContext; 31 : import com.google.gerrit.server.permissions.PermissionBackend; 32 : import com.google.gerrit.server.permissions.PermissionBackendException; 33 : import com.google.gerrit.server.permissions.ProjectPermission; 34 : import com.google.gerrit.server.plugincontext.PluginSetContext; 35 : import com.google.gerrit.sshd.AbstractGitCommand; 36 : import com.google.inject.Inject; 37 : import java.io.IOException; 38 : import java.util.List; 39 : import org.eclipse.jgit.lib.Repository; 40 : import org.eclipse.jgit.storage.pack.PackStatistics; 41 : import org.eclipse.jgit.transport.PostUploadHook; 42 : import org.eclipse.jgit.transport.PostUploadHookChain; 43 : import org.eclipse.jgit.transport.PreUploadHook; 44 : import org.eclipse.jgit.transport.PreUploadHookChain; 45 : import org.eclipse.jgit.transport.UploadPack; 46 : 47 : /** Publishes Git repositories over SSH using the Git upload-pack protocol. */ 48 3 : final class Upload extends AbstractGitCommand { 49 : @Inject private TransferConfig config; 50 : @Inject private DynamicSet<PreUploadHook> preUploadHooks; 51 : @Inject private DynamicSet<PostUploadHook> postUploadHooks; 52 : @Inject private DynamicSet<UploadPackInitializer> uploadPackInitializers; 53 : @Inject private PluginSetContext<RequestListener> requestListeners; 54 : @Inject private UploadValidators.Factory uploadValidatorsFactory; 55 : @Inject private PermissionBackend permissionBackend; 56 : @Inject private UsersSelfAdvertiseRefsHook usersSelfAdvertiseRefsHook; 57 : 58 : private PackStatistics stats; 59 : 60 : @Override 61 : protected void runImpl() throws IOException, Failure { 62 3 : PermissionBackend.ForProject perm = 63 3 : permissionBackend.user(user).project(projectState.getNameKey()); 64 : try { 65 3 : perm.check(ProjectPermission.RUN_UPLOAD_PACK); 66 0 : } catch (AuthException e) { 67 0 : throw new Failure(1, "fatal: upload-pack not permitted on this server", e); 68 0 : } catch (PermissionBackendException e) { 69 0 : throw new Failure(1, "fatal: unable to check permissions ", e); 70 3 : } 71 : 72 3 : Repository permissionAwareRepo = PermissionAwareRepositoryManager.wrap(repo, perm); 73 3 : UploadPack up = new UploadPack(permissionAwareRepo); 74 : 75 3 : up.setPackConfig(config.getPackConfig()); 76 3 : up.setTimeout(config.getTimeout()); 77 3 : up.setPostUploadHook(PostUploadHookChain.newChain(Lists.newArrayList(postUploadHooks))); 78 3 : if (projectState.isAllUsers()) { 79 0 : up.setAdvertiseRefsHook(usersSelfAdvertiseRefsHook); 80 : } 81 3 : if (extraParameters != null) { 82 3 : up.setExtraParameters(ImmutableList.copyOf(extraParameters)); 83 : } 84 : 85 3 : List<PreUploadHook> allPreUploadHooks = Lists.newArrayList(preUploadHooks); 86 3 : allPreUploadHooks.add( 87 3 : uploadValidatorsFactory.create( 88 3 : project, permissionAwareRepo, session.getRemoteAddressAsString())); 89 3 : up.setPreUploadHook(PreUploadHookChain.newChain(allPreUploadHooks)); 90 3 : for (UploadPackInitializer initializer : uploadPackInitializers) { 91 0 : initializer.init(projectState.getNameKey(), up); 92 0 : } 93 3 : try (TraceContext traceContext = TraceContext.open(); 94 3 : TracingHook tracingHook = new TracingHook()) { 95 3 : RequestInfo requestInfo = 96 3 : RequestInfo.builder(RequestInfo.RequestType.GIT_UPLOAD, user, traceContext) 97 3 : .project(projectState.getNameKey()) 98 3 : .build(); 99 3 : requestListeners.runEach(l -> l.onRequest(requestInfo)); 100 3 : up.setProtocolV2Hook(tracingHook); 101 3 : up.upload(in, out, err); 102 3 : session.setPeerAgent(up.getPeerUserAgent()); 103 3 : stats = up.getStatistics(); 104 0 : } catch (UploadValidationException e) { 105 : // UploadValidationException is used by the UploadValidators to 106 : // stop the uploadPack. We do not want this exception to go beyond this 107 : // point otherwise it would print a stacktrace in the logs and return an 108 : // internal server error to the client. 109 0 : if (!e.isOutput()) { 110 0 : up.sendMessage(e.getMessage()); 111 : } 112 3 : } 113 3 : } 114 : 115 : @Override 116 : protected void onExit(int rc) { 117 3 : exit.onExit( 118 : rc, 119 3 : stats != null 120 2 : ? stats.getTimeNegotiating() 121 : + "ms " 122 2 : + stats.getTimeSearchingForReuse() 123 : + "ms " 124 2 : + stats.getTimeSearchingForSizes() 125 : + "ms " 126 2 : + stats.getTimeCounting() 127 : + "ms " 128 2 : + stats.getTimeCompressing() 129 : + "ms " 130 2 : + stats.getTimeWriting() 131 : + "ms " 132 2 : + stats.getTimeTotal() 133 : + "ms " 134 2 : + stats.getBitmapIndexMisses() 135 : + " " 136 2 : + stats.getTotalDeltas() 137 : + " " 138 2 : + stats.getTotalObjects() 139 : + " " 140 2 : + stats.getTotalBytes() 141 2 : : "-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1"); 142 3 : if (cleanup != null) { 143 3 : cleanup.run(); 144 : } 145 3 : } 146 : }