Пример #1
0
        public bool TrySetCacheServerUrlConfig()
        {
            GitProcess git         = new Git.GitProcess(this);
            string     settingName = Enlistment.GetCacheConfigSettingName(this.RepoUrl);

            return(!git.SetInLocalConfig(settingName, this.CacheServerUrl).HasErrors);
        }
Пример #2
0
        /// <summary>
        /// Uses a <see cref="PrefetchPacksDeserializer"/> to read the packs from the stream.
        /// </summary>
        private RetryWrapper <GitObjectsHttpRequestor.GitObjectTaskResult> .CallbackResult DeserializePrefetchPacks(
            GitEndPointResponseData response,
            ref long latestTimestamp,
            ref long bytesDownloaded,
            ref List <string> packIndexes,
            GitProcess gitProcess)
        {
            if (packIndexes == null)
            {
                packIndexes = new List <string>();
            }

            using (ITracer activity = this.Tracer.StartActivity("DeserializePrefetchPacks", EventLevel.Informational))
            {
                PrefetchPacksDeserializer deserializer = new PrefetchPacksDeserializer(response.Stream);

                string tempPackFolderPath = Path.Combine(this.Enlistment.GitPackRoot, TempPackFolder);
                this.fileSystem.CreateDirectory(tempPackFolderPath);

                List <TempPrefetchPackAndIdx> tempPacks = new List <TempPrefetchPackAndIdx>();
                foreach (PrefetchPacksDeserializer.PackAndIndex pack in deserializer.EnumeratePacks())
                {
                    // The advertised size may not match the actual, on-disk size.
                    long indexLength = 0;
                    long packLength;

                    // Write the temp and index to a temp folder to avoid putting corrupt files in the pack folder
                    // Once the files are validated and flushed they can be moved to the pack folder
                    string packName     = string.Format("{0}-{1}-{2}.pack", GVFSConstants.PrefetchPackPrefix, pack.Timestamp, pack.UniqueId);
                    string packTempPath = Path.Combine(tempPackFolderPath, packName);
                    string idxName      = string.Format("{0}-{1}-{2}.idx", GVFSConstants.PrefetchPackPrefix, pack.Timestamp, pack.UniqueId);
                    string idxTempPath  = Path.Combine(tempPackFolderPath, idxName);

                    EventMetadata data = CreateEventMetadata();
                    data["timestamp"] = pack.Timestamp.ToString();
                    data["uniqueId"]  = pack.UniqueId;
                    activity.RelatedEvent(EventLevel.Informational, "Receiving Pack/Index", data);

                    // Write the pack
                    // If it fails, TryWriteTempFile cleans up the file and we retry the prefetch
                    Task packFlushTask;
                    if (!this.TryWriteTempFile(activity, pack.PackStream, packTempPath, out packLength, out packFlushTask))
                    {
                        bytesDownloaded += packLength;
                        return(new RetryWrapper <GitObjectsHttpRequestor.GitObjectTaskResult> .CallbackResult(null, true));
                    }

                    bytesDownloaded += packLength;

                    // We will try to build an index if the server does not send one
                    if (pack.IndexStream == null)
                    {
                        GitProcess.Result result;
                        if (!this.TryBuildIndex(activity, packTempPath, out result, gitProcess))
                        {
                            if (packFlushTask != null)
                            {
                                packFlushTask.Wait();
                            }

                            // Move whatever has been successfully downloaded so far
                            Exception moveException;
                            this.TryFlushAndMoveTempPacks(tempPacks, ref latestTimestamp, out moveException);

                            return(new RetryWrapper <GitObjectsHttpRequestor.GitObjectTaskResult> .CallbackResult(null, true));
                        }

                        tempPacks.Add(new TempPrefetchPackAndIdx(pack.Timestamp, packName, packTempPath, packFlushTask, idxName, idxTempPath, idxFlushTask: null));
                    }
                    else
                    {
                        Task indexFlushTask;
                        if (this.TryWriteTempFile(activity, pack.IndexStream, idxTempPath, out indexLength, out indexFlushTask))
                        {
                            tempPacks.Add(new TempPrefetchPackAndIdx(pack.Timestamp, packName, packTempPath, packFlushTask, idxName, idxTempPath, indexFlushTask));
                        }
                        else
                        {
                            bytesDownloaded += indexLength;

                            // Try to build the index manually, then retry the prefetch
                            GitProcess.Result result;
                            if (this.TryBuildIndex(activity, packTempPath, out result, gitProcess))
                            {
                                // If we were able to recreate the failed index
                                // we can start the prefetch at the next timestamp
                                tempPacks.Add(new TempPrefetchPackAndIdx(pack.Timestamp, packName, packTempPath, packFlushTask, idxName, idxTempPath, idxFlushTask: null));
                            }
                            else
                            {
                                if (packFlushTask != null)
                                {
                                    packFlushTask.Wait();
                                }
                            }

                            // Move whatever has been successfully downloaded so far
                            Exception moveException;
                            this.TryFlushAndMoveTempPacks(tempPacks, ref latestTimestamp, out moveException);

                            // The download stream will not be in a good state if the index download fails.
                            // So we have to restart the prefetch
                            return(new RetryWrapper <GitObjectsHttpRequestor.GitObjectTaskResult> .CallbackResult(null, true));
                        }
                    }

                    bytesDownloaded += indexLength;
                }

                Exception exception = null;
                if (!this.TryFlushAndMoveTempPacks(tempPacks, ref latestTimestamp, out exception))
                {
                    return(new RetryWrapper <GitObjectsHttpRequestor.GitObjectTaskResult> .CallbackResult(exception, true));
                }

                foreach (TempPrefetchPackAndIdx tempPack in tempPacks)
                {
                    packIndexes.Add(tempPack.IdxName);
                }

                return(new RetryWrapper <GitObjectsHttpRequestor.GitObjectTaskResult> .CallbackResult(
                           new GitObjectsHttpRequestor.GitObjectTaskResult(success: true)));
            }
        }
Пример #3
0
        private GitProcess.Result TryAddPackFile(Stream contents, bool unpackObjects, GitProcess gitProcess)
        {
            GitProcess.Result result;

            this.fileSystem.CreateDirectory(this.Enlistment.GitPackRoot);

            if (unpackObjects)
            {
                result = new GitProcess(this.Enlistment).UnpackObjects(contents);
            }
            else
            {
                string tempPackPath = this.WriteTempPackFile(contents);
                return(this.IndexTempPackFile(tempPackPath, gitProcess));
            }

            return(result);
        }
Пример #4
0
        public virtual GitProcess.Result IndexPackFile(string packfilePath, GitProcess gitProcess)
        {
            string tempIdxPath = Path.ChangeExtension(packfilePath, TempIdxExtension);
            string idxPath     = Path.ChangeExtension(packfilePath, ".idx");

            Exception indexPackException = null;

            try
            {
                if (gitProcess == null)
                {
                    gitProcess = new GitProcess(this.Enlistment);
                }

                GitProcess.Result result = gitProcess.IndexPack(packfilePath, tempIdxPath);
                if (result.ExitCodeIsFailure)
                {
                    Exception exception;
                    if (!this.fileSystem.TryDeleteFile(tempIdxPath, exception: out exception))
                    {
                        EventMetadata metadata = CreateEventMetadata(exception);
                        metadata.Add("tempIdxPath", tempIdxPath);
                        this.Tracer.RelatedWarning(metadata, $"{nameof(this.IndexPackFile)}: Failed to cleanup temp idx file after index pack failure");
                    }
                }
                else
                {
                    if (this.Enlistment.FlushFileBuffersForPacks)
                    {
                        Exception exception;
                        string    error;
                        if (!this.TryFlushFileBuffers(tempIdxPath, out exception, out error))
                        {
                            EventMetadata metadata = CreateEventMetadata(exception);
                            metadata.Add("packfilePath", packfilePath);
                            metadata.Add("tempIndexPath", tempIdxPath);
                            metadata.Add("error", error);
                            this.Tracer.RelatedWarning(metadata, $"{nameof(this.IndexPackFile)}: Failed to flush temp idx file buffers");
                        }
                    }

                    this.fileSystem.MoveAndOverwriteFile(tempIdxPath, idxPath);
                }

                return(result);
            }
            catch (Win32Exception e)
            {
                indexPackException = e;
            }
            catch (IOException e)
            {
                indexPackException = e;
            }
            catch (UnauthorizedAccessException e)
            {
                indexPackException = e;
            }

            EventMetadata failureMetadata = CreateEventMetadata(indexPackException);

            failureMetadata.Add("packfilePath", packfilePath);
            failureMetadata.Add("tempIdxPath", tempIdxPath);
            failureMetadata.Add("idxPath", idxPath);

            this.fileSystem.TryDeleteFile(tempIdxPath, metadataKey: nameof(tempIdxPath), metadata: failureMetadata);
            this.fileSystem.TryDeleteFile(idxPath, metadataKey: nameof(idxPath), metadata: failureMetadata);

            this.Tracer.RelatedWarning(failureMetadata, $"{nameof(this.IndexPackFile): Exception caught while trying to index pack file}");

            return(new GitProcess.Result(
                       string.Empty,
                       indexPackException != null ? indexPackException.Message : "Failed to index pack file",
                       GitProcess.Result.GenericFailureCode));
        }
Пример #5
0
        public void ConfigureHttpClientHandlerSslIfNeeded(ITracer tracer, HttpClientHandler httpClientHandler, GitProcess gitProcess)
        {
            X509Certificate2 cert = this.GitSsl?.GetCertificate(tracer, gitProcess);

            if (cert != null)
            {
                if (this.GitSsl != null && !this.GitSsl.ShouldVerify)
                {
                    httpClientHandler.ServerCertificateCustomValidationCallback =
                        (httpRequestMessage, c, cetChain, policyErrors) =>
                    {
                        return(true);
                    };
                }

                httpClientHandler.ClientCertificateOptions = ClientCertificateOption.Manual;
                httpClientHandler.ClientCertificates.Add(cert);
            }
        }
Пример #6
0
 public GitAuthentication(GitProcess git, string repoUrl)
 {
     this.git     = git;
     this.repoUrl = repoUrl;
 }
Пример #7
0
        private GitEndPointResponseData SendRequest(
            Uri requestUri,
            HttpMethod httpMethod,
            string requestContent,
            MediaTypeWithQualityHeaderValue acceptType = null)
        {
            string authString;

            if (!this.TryGetCredentials(out authString))
            {
                string message =
                    this.authRetryBackoff == DateTime.MinValue
                    ? "Authorization failed."
                    : "Authorization failed. No retries will be made until: " + this.authRetryBackoff;

                return(new GitEndPointResponseData(
                           HttpStatusCode.Unauthorized,
                           new HttpGitObjectsException(HttpStatusCode.Unauthorized, message),
                           shouldRetry: false));
            }

            HttpRequestMessage request = new HttpRequestMessage(httpMethod, requestUri);

            request.Headers.UserAgent.Add(this.userAgentHeader);
            request.Headers.Authorization = new AuthenticationHeaderValue("Basic", authString);

            if (acceptType != null)
            {
                request.Headers.Accept.Add(acceptType);
            }

            if (requestContent != null)
            {
                request.Content = new StringContent(requestContent, Encoding.UTF8, "application/json");
            }

            try
            {
                HttpResponseMessage response = client.SendAsync(request, HttpCompletionOption.ResponseHeadersRead).Result;
                if (response.StatusCode == HttpStatusCode.OK)
                {
                    string contentType = string.Empty;
                    IEnumerable <string> values;
                    if (response.Content.Headers.TryGetValues("Content-Type", out values))
                    {
                        contentType = values.First();
                    }

                    this.credentialHasBeenRevoked = false;
                    Stream responseStream = response.Content.ReadAsStreamAsync().Result;
                    return(new GitEndPointResponseData(response.StatusCode, contentType, responseStream));
                }
                else
                {
                    string errorMessage = response.Content.ReadAsStringAsync().Result;
                    int    statusInt    = (int)response.StatusCode;

                    if (string.IsNullOrWhiteSpace(errorMessage))
                    {
                        if (response.StatusCode == HttpStatusCode.Unauthorized)
                        {
                            lock (this.gitAuthorizationLock)
                            {
                                // Wipe the username and password so we can try recovering if applicable.
                                this.gitAuthorization = null;
                                if (!this.credentialHasBeenRevoked)
                                {
                                    GitProcess.RevokeCredential(this.enlistment);
                                    this.credentialHasBeenRevoked = true;
                                    return(new GitEndPointResponseData(
                                               response.StatusCode,
                                               new HttpGitObjectsException(response.StatusCode, "Server returned error code 401 (Unauthorized). Your PAT may be expired."),
                                               shouldRetry: true));
                                }
                                else
                                {
                                    this.authRetryBackoff = DateTime.MaxValue;
                                    return(new GitEndPointResponseData(
                                               response.StatusCode,
                                               new HttpGitObjectsException(response.StatusCode, "Server returned error code 401 (Unauthorized) after successfully renewing your PAT. You may not have access to this repo"),
                                               shouldRetry: false));
                                }
                            }
                        }
                        else
                        {
                            errorMessage = string.Format("Server returned error code {0} ({1})", statusInt, response.StatusCode);
                        }
                    }

                    return(new GitEndPointResponseData(response.StatusCode, new HttpGitObjectsException(response.StatusCode, errorMessage), ShouldRetry(response.StatusCode)));
                }
            }
            catch (TaskCanceledException)
            {
                string errorMessage = string.Format("Request to {0} timed out", requestUri);
                return(new GitEndPointResponseData(HttpStatusCode.RequestTimeout, new HttpGitObjectsException(HttpStatusCode.RequestTimeout, errorMessage), shouldRetry: true));
            }
            catch (WebException ex)
            {
                return(new GitEndPointResponseData(HttpStatusCode.InternalServerError, ex, shouldRetry: true));
            }
        }
Пример #8
0
 public GitAuthentication(GitProcess git)
 {
     this.git = git;
 }