/// <inheritdoc />
        public async Task <BatchTransfer> RequestBatchAsync(GitHost host, string repositoryName, BatchRequest request)
        {
            using (var client = new HttpClient())
            {
                client.DefaultRequestHeaders.Accept.Clear();
                client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/vnd.git-lfs+json"));
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("token", host.Token);

                using (var content = new StringContent(
                           this.requestSerialiser.ToString(request),
                           null,
                           "application/vnd.git-lfs+json"))
                {
                    HttpResponseMessage result = await client.PostAsync(GetLfsBatchUrl(host, repositoryName), content).ConfigureAwait(false);

                    if (!result.IsSuccessStatusCode)
                    {
                        await this.HandleErrorAsync(result).ConfigureAwait(false);
                    }

                    string returnContents = await result.Content.ReadAsStringAsync().ConfigureAwait(false);

                    return(this.transferSerialiser.TransferFromString(returnContents));
                }
            }
        }
        public async Task <IActionResult> Edit(int id, [Bind("Id,Href,Name,UserName,Token")] GitHost gitHost)
        {
            if (id != gitHost.Id)
            {
                return(this.NotFound());
            }

            if (this.ModelState.IsValid)
            {
                try
                {
                    this.context.Update(gitHost);
                    await this.context.SaveChangesAsync();
                }
                catch (DbUpdateConcurrencyException)
                {
                    if (!this.GitHostExists(gitHost.Id))
                    {
                        return(this.NotFound());
                    }

                    throw;
                }

                return(this.RedirectToAction("Index"));
            }

            return(this.View(gitHost));
        }
        /// <inheritdoc />
        public async Task <Stream> DownloadFileAsync(
            GitHost host,
            string repositoryName,
            ObjectId objectId,
            BatchObjectAction action)
        {
            using (var httpClient = new HttpClient())
            {
                SetClientHeaders(action, httpClient);

                this.logger.LogInformation(
                    $"Download from {action.HRef} with repository name {repositoryName}, request:{objectId.Hash.Substring(0, 10)}/{objectId.Size}");
                HttpResponseMessage result = await httpClient.GetAsync(action.HRef, HttpCompletionOption.ResponseHeadersRead).ConfigureAwait(false);

                if (!result.IsSuccessStatusCode)
                {
                    await this.HandleErrorAsync(result).ConfigureAwait(false);
                }

                this.logger.LogInformation(
                    $"Now saving to a file {repositoryName}, request:{objectId.Hash.Substring(0, 10)}/{objectId.Size}\"");

                return(this.fileManager.SaveFile(
                           out string fileName,
                           repositoryName,
                           objectId,
                           FileLocation.Permanent,
                           await result.Content.ReadAsStreamAsync().ConfigureAwait(false)));
            }
        }
        public async Task <IActionResult> DeleteConfirmed(int id)
        {
            GitHost gitHost = await this.context.GitHost.SingleOrDefaultAsync(m => m.Id == id);

            this.context.GitHost.Remove(gitHost);
            await this.context.SaveChangesAsync();

            return(this.RedirectToAction("Index"));
        }
        public async Task <IActionResult> UploadFile(int hostId, string repositoryName, string objectId, long size)
        {
            var fileObjectId = new ObjectId(objectId, size);

            try
            {
                GitHost host = await this.context.GitHost.FindAsync(hostId);

                if (host == null)
                {
                    this.logger.LogWarning("Not a valid host id");
                    return(this.NotFound(new ErrorResponse {
                        Message = "Not a valid host id"
                    }));
                }

                this.logger.LogInformation($"Saving the file to disk for {fileObjectId}");

                this.Response.Headers.Remove("transfer-encoding");

                if (!this.fileManager.IsFileStored(
                        repositoryName,
                        fileObjectId,
                        FileLocation.Metadata,
                        false,
                        "upload"))
                {
                    this.fileManager.DeleteFile(repositoryName, fileObjectId, FileLocation.Metadata, "upload");
                    return(this.Ok());
                }

                BatchObjectAction action = this.transferSerialiser.ObjectActionFromString(await this.fileManager.GetFileContentsAsync(repositoryName, fileObjectId, FileLocation.Metadata, "upload"));


                this.logger.LogInformation($"Starting file upload for {fileObjectId}");
                await this.lfsClient.UploadFile(action, this.Request.Body);

                this.logger.LogInformation($"Finished file upload for {fileObjectId}");

                this.fileManager.DeleteFile(repositoryName, fileObjectId, FileLocation.Metadata, "upload");
                return(this.Ok());
            }
            catch (ErrorResponseException ex)
            {
                this.logger.LogWarning(null, ex, $"Received a error response with message {ex.Message} for {fileObjectId}");
                this.fileManager.DeleteFile(repositoryName, fileObjectId, FileLocation.Temporary);
                return(this.StatusCode(ex.StatusCode.Value, ex.ErrorResponse));
            }
            catch (StatusCodeException ex)
            {
                this.logger.LogWarning(null, ex, $"Received a status code error with message {ex.Message} for {fileObjectId}");
                this.fileManager.DeleteFile(repositoryName, fileObjectId, FileLocation.Temporary);
                return(this.StatusCode(ex.StatusCode.Value, new ErrorResponse {
                    Message = ex.Message
                }));
            }
        }
        public async Task <IActionResult> Create([Bind("Id,Href,Name,UserName,Token")] GitHost gitHost)
        {
            if (this.ModelState.IsValid)
            {
                this.context.Add(gitHost);
                await this.context.SaveChangesAsync();

                return(this.RedirectToAction("Index"));
            }

            return(this.View(gitHost));
        }
Example #7
0
        public async Task <IActionResult> Create([Bind("Href,Id,Name,Token,UserName")] GitHost gitHost)
        {
            if (this.ModelState.IsValid)
            {
                this.context.Add(gitHost);
                await this.context.SaveChangesAsync().ConfigureAwait(false);

                return(this.RedirectToAction(nameof(this.Index)));
            }

            return(this.View(gitHost));
        }
        /// <summary>
        /// Deltes a GitHost object from the database with the specified ID.
        /// </summary>
        /// <param name="id">The ID to delete.</param>
        /// <returns>A action result to monitor the progress.</returns>
        public async Task <IActionResult> Delete(int?id)
        {
            if (id == null)
            {
                return(this.NotFound());
            }

            GitHost gitHost = await this.context.GitHost.SingleOrDefaultAsync(m => m.Id == id);

            if (gitHost == null)
            {
                return(this.NotFound());
            }

            return(this.View(gitHost));
        }
        public async Task <IActionResult> Verify(int hostId, string repositoryName, string objectId, long size)
        {
            var fileObjectId = new ObjectId(objectId, size);

            try
            {
                GitHost host = await this.context.GitHost.FindAsync(hostId);

                if (host == null)
                {
                    return(this.NotFound(new ErrorResponse {
                        Message = "Not a valid host id."
                    }));
                }

                this.fileManager.MoveFile(repositoryName, fileObjectId, FileLocation.Temporary, FileLocation.Permenant);

                if (this.fileManager.IsFileStored(repositoryName, fileObjectId, FileLocation.Metadata, false, "verify"))
                {
                    this.logger.LogInformation($"Starting verify for {fileObjectId}");
                    BatchObjectAction action = this.transferSerialiser.ObjectActionFromString(await this.fileManager.GetFileContentsAsync(repositoryName, fileObjectId, FileLocation.Metadata, "verify"));
                    await this.lfsClient.Verify(host, repositoryName, fileObjectId, action);

                    this.logger.LogInformation($"Ending verify for {fileObjectId}");
                }


                this.fileManager.DeleteFile(repositoryName, fileObjectId, FileLocation.Metadata, "verify");

                return(this.Ok());
            }
            catch (ErrorResponseException ex)
            {
                this.logger.LogWarning(null, ex, $"Received a error response with message {ex.Message} for {fileObjectId}");
                return(this.StatusCode(ex.StatusCode.Value, ex.ErrorResponse));
            }
            catch (StatusCodeException ex)
            {
                this.logger.LogWarning(null, ex, $"Received a status code error with message {ex.Message} for {fileObjectId}");
                return(this.StatusCode(ex.StatusCode.Value, new ErrorResponse {
                    Message = ex.Message
                }));
            }
        }
Example #10
0
        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            if (DesignerProperties.GetIsInDesignMode(this))
            {
                return;
            }

            if (!GitLocator.IsGitInstalled)
            {
                MessageBox.Show($"Git is not installed or not found at the default install path.\nSearch Path was: {GitLocator.GitPath}",
                                "Git not found", MessageBoxButton.OK, MessageBoxImage.Error);
            }

            if (_gitHost == null)
            {
                _gitHost = new GitHost(GitLocator.GitPath);
                RootGrid.Children.Clear();
                RootGrid.Children.Add(_gitHost);
            }
        }
        /// <inheritdoc />
        public async Task VerifyAsync(GitHost host, string repositoryName, ObjectId objectId, BatchObjectAction action)
        {
            using (var httpClient = new HttpClient())
            {
                SetClientHeaders(action, httpClient);

                using (var content = new StringContent(
                           this.verifySerialiser.ToString(objectId),
                           null,
                           "application/vnd.git-lfs+json"))
                {
                    this.logger.LogInformation(
                        $"Verify from {action.HRef} with repository name {repositoryName}, request:{objectId.Hash.Substring(0, 10)}/{objectId.Size}");
                    HttpResponseMessage result = await httpClient.PostAsync(action.HRef, content).ConfigureAwait(false);

                    if (!result.IsSuccessStatusCode)
                    {
                        await this.HandleErrorAsync(result).ConfigureAwait(false);
                    }
                }
            }
        }
        private async Task HandleHttpRequest(HttpContext context)
        {
            PathString path = context.Request.Path;

            if (path.ToString().Contains("lfs"))
            {
                await this.next(context);

                return;
            }

            var matchCriteria = new Regex("/api/([0-9]+)/([a-zA-Z0-9-\\.]*/?.*)");

            Match match = matchCriteria.Match(context.Request.Path.ToString());

            if (match.Success == false)
            {
                await this.next(context);

                return;
            }

            var dbContext = context.RequestServices.GetService <ApplicationDbContext>();

            if (int.TryParse(match.Groups[1].Value, out int hostIndex) == false)
            {
                await this.next(context);

                return;
            }

            GitHost gitHost = await dbContext.GitHost.SingleOrDefaultAsync(x => x.Id == hostIndex);

            if (gitHost == null)
            {
                await this.next(context);

                return;
            }

            var    requestMessage = new HttpRequestMessage();
            string requestMethod  = context.Request.Method;

            if (!HttpMethods.IsGet(requestMethod) && !HttpMethods.IsHead(requestMethod) &&
                !HttpMethods.IsDelete(requestMethod) && !HttpMethods.IsTrace(requestMethod))
            {
                var streamContent = new StreamContent(context.Request.Body);
                requestMessage.Content = streamContent;
            }

            // Copy the request headers
            foreach (KeyValuePair <string, StringValues> header in context.Request.Headers)
            {
                if (!requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray()) &&
                    requestMessage.Content != null)
                {
                    requestMessage.Content?.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
                }
            }

            string newPath = match.Groups[2].Value;

            var uri = new Uri($"{gitHost.Href}/{context.Request.PathBase}{newPath}{context.Request.QueryString}");

            requestMessage.Headers.Host = uri.Host;
            requestMessage.RequestUri   = uri;
            requestMessage.Method       = new HttpMethod(context.Request.Method);
            using (HttpResponseMessage responseMessage = await this.httpClient.SendAsync(
                       requestMessage,
                       HttpCompletionOption.ResponseHeadersRead,
                       context.RequestAborted))
            {
                context.Response.StatusCode = (int)responseMessage.StatusCode;
                foreach (KeyValuePair <string, IEnumerable <string> > header in responseMessage.Headers)
                {
                    context.Response.Headers[header.Key] = header.Value.ToArray();
                }

                foreach (KeyValuePair <string, IEnumerable <string> > header in responseMessage.Content.Headers)
                {
                    context.Response.Headers[header.Key] = header.Value.ToArray();
                }

                // SendAsync removes chunking from the response. This removes the header so it doesn't expect a chunked response.
                context.Response.Headers.Remove("transfer-encoding");
                await responseMessage.Content.CopyToAsync(context.Response.Body);
            }
        }
 private static Uri GetLfsBatchUrl(GitHost host, string repositoryName)
 {
     return(new Uri($"{host.Href}/{repositoryName}/info/lfs/objects/batch"));
 }
Example #14
0
        public async Task <IActionResult> DownloadFile(int hostId, string repositoryName, string objectId, long size)
        {
            var fileObjectId = new ObjectId(objectId, size);

            try
            {
                GitHost host = await this.context.GitHost.FindAsync(hostId).ConfigureAwait(false);

                if (host == null)
                {
                    return(this.NotFound(new ErrorResponse {
                        Message = "Not a valid host id."
                    }));
                }

                Stream stream = this.fileManager.GetFileStream(repositoryName, fileObjectId, FileLocation.Permanent);

                if (stream != null)
                {
                    this.logger.LogInformation($"Found local cache file: {fileObjectId}");
                    return(this.File(stream, "application/octet-stream"));
                }

                var actionStream = await this.fileManager.GetFileContentsAsync(repositoryName, fileObjectId, FileLocation.Metadata, "download").ConfigureAwait(false);

                if (actionStream == null)
                {
                    this.logger.LogWarning($"No valid batch request for {fileObjectId}");
                    return(this.NotFound(new ErrorResponse {
                        Message = $"No valid batch request for {fileObjectId}"
                    }));
                }

                BatchObjectAction action = this.transferSerialiser.ObjectActionFromString(actionStream);

                if (action == null)
                {
                    this.logger.LogWarning($"Unable to find file {objectId}");
                    return(this.NotFound(new ErrorResponse {
                        Message = $"Unable to find file {objectId}"
                    }));
                }

                if (action.Mode != BatchActionMode.Download)
                {
                    this.logger.LogWarning($"No download action associated with request: {objectId}");
                    return(this.StatusCode(
                               422,
                               new ErrorResponse {
                        Message = $"No download action associated with request: {objectId}"
                    }));
                }

                this.fileManager.DeleteFile(repositoryName, fileObjectId, FileLocation.Metadata, "download");

                return(this.File(
                           await this.lfsClient.DownloadFileAsync(
                               host,
                               repositoryName,
                               fileObjectId,
                               action).ConfigureAwait(false),
                           "application/octet-stream"));
            }
            catch (ErrorResponseException ex)
            {
                this.logger.LogWarning(null, ex, $"Received a error response with message {ex.Message} for {fileObjectId}");
                return(this.StatusCode(ex.StatusCode ?? DefaultErrorCode, ex.ErrorResponse));
            }
            catch (StatusCodeException ex)
            {
                this.logger.LogWarning(null, ex, $"Received a status code error with message {ex.Message}");
                return(this.StatusCode(ex.StatusCode ?? DefaultErrorCode, new ErrorResponse {
                    Message = ex.Message
                }));
            }
        }
Example #15
0
        public async Task <IActionResult> HandleBatchRequest(
            int hostId,
            string repositoryName,
            [FromBody] BatchRequest request)
        {
            GitHost host = await this.context.GitHost.FindAsync(hostId).ConfigureAwait(false);

            if (host == null)
            {
                return(this.NotFound(new ErrorResponse {
                    Message = "Not a valid host id."
                }));
            }

            var serverBatchRequest = new BatchRequest
            {
                Objects   = new List <ObjectId>(),
                Operation = request.Operation,
                Transfers = request.Transfers
            };

            foreach (ObjectId objectId in request.Objects)
            {
                if (request.Operation == BatchRequestMode.Download &&
                    this.fileManager.IsFileStored(repositoryName, objectId, FileLocation.Permanent))
                {
                    continue;
                }

                serverBatchRequest.Objects.Add(objectId);
            }

            try
            {
                IDictionary <ObjectId, IBatchObject> batchObjects = new Dictionary <ObjectId, IBatchObject>();
                if (serverBatchRequest.Objects.Count > 0)
                {
                    BatchTransfer serverResults =
                        await this.lfsClient.RequestBatchAsync(host, repositoryName, serverBatchRequest).ConfigureAwait(false);

                    foreach (IBatchObject serverResult in serverResults.Objects)
                    {
                        batchObjects.Add(serverResult.Id, serverResult);

                        if (serverResult is BatchObject batchObject)
                        {
                            foreach (BatchObjectAction action in batchObject.Actions)
                            {
                                await this.fileManager.SaveFileAsync(
                                    repositoryName,
                                    serverResult.Id,
                                    FileLocation.Metadata,
                                    this.transferSerialiser.ToString(action),
                                    action.Mode.ToString().ToLowerInvariant()).ConfigureAwait(false);
                            }
                        }
                    }
                }

                var returnResult = new BatchTransfer();
                returnResult.Mode    = TransferMode.Basic;
                returnResult.Objects = new List <IBatchObject>();

                foreach (ObjectId pendingObjectId in request.Objects)
                {
                    batchObjects.TryGetValue(pendingObjectId, out IBatchObject batchObjectBase);
                    var batchObject = batchObjectBase as BatchObject;

                    if (batchObjectBase is BatchObjectError errorResult)
                    {
                        returnResult.Objects.Add(errorResult);
                    }
                    else
                    {
                        switch (request.Operation)
                        {
                        case BatchRequestMode.Upload:
                            returnResult.Objects.Add(batchObject);
                            break;

                        case BatchRequestMode.Download:
                        {
                            var returnBatchObject = new BatchObject {
                                Id = pendingObjectId, Actions = new List <BatchObjectAction>()
                            };
                            var action = new BatchObjectAction
                            {
                                Mode = BatchActionMode.Download,
                                HRef =
                                    $"{this.Request.Scheme}://{this.Request.Host}/api/{hostId}/{repositoryName}/info/lfs/{pendingObjectId.Hash}/{pendingObjectId.Size}"
                            };

                            returnBatchObject.Actions.Add(action);
                            returnResult.Objects.Add(returnBatchObject);
                            break;
                        }
                        }
                    }
                }

                return(this.Ok(returnResult));
            }
            catch (ErrorResponseException ex)
            {
                this.logger.LogWarning(null, ex, $"Received a error response with message {ex.Message}");
                return(this.StatusCode(ex.StatusCode ?? DefaultErrorCode, ex.ErrorResponse));
            }
            catch (StatusCodeException ex)
            {
                this.logger.LogWarning(null, ex, $"Received a status code error with message {ex.Message}");
                return(this.StatusCode(ex.StatusCode ?? DefaultErrorCode, new ErrorResponse {
                    Message = ex.Message
                }));
            }
        }