public bool TrySetCacheServerUrlConfig() { GitProcess git = new Git.GitProcess(this); string settingName = Enlistment.GetCacheConfigSettingName(this.RepoUrl); return(!git.SetInLocalConfig(settingName, this.CacheServerUrl).HasErrors); }
/// <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))); } }
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); }
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)); }
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); } }
public GitAuthentication(GitProcess git, string repoUrl) { this.git = git; this.repoUrl = repoUrl; }
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)); } }
public GitAuthentication(GitProcess git) { this.git = git; }