Esempio n. 1
0
        public void GetMediaType_HandlesUnknownMediaTypes(string extension)
        {
            MediaTypeMap         map = new MediaTypeMap();
            MediaTypeHeaderValue expectedMediaType = new MediaTypeHeaderValue("application/octet-stream");

            Assert.Equal(expectedMediaType, map.GetMediaType(extension));
        }
Esempio n. 2
0
        public void GetMediaType_HandlesKnownMediaTypes(string extension, string expectedMediaType)
        {
            MediaTypeMap         map      = new MediaTypeMap();
            MediaTypeHeaderValue expected = new MediaTypeHeaderValue(expectedMediaType);

            Assert.Equal(expected, map.GetMediaType(extension));
        }
        public void GetMediaType_HandlesUnknownMediaTypes(string extension)
        {
            MediaTypeMap map = new MediaTypeMap();
            MediaTypeHeaderValue expectedMediaType = new MediaTypeHeaderValue("application/octet-stream");

            Assert.Equal(expectedMediaType, map.GetMediaType(extension));
        }
Esempio n. 4
0
        public void GetMediaType_Guards()
        {
            MediaTypeMap          map = new MediaTypeMap();
            ArgumentNullException ex  = Assert.Throws <ArgumentNullException>(() => map.GetMediaType(null));

            Assert.Equal("fileExtension", ex.ParamName);
        }
Esempio n. 5
0
        protected override Task <IActionResult> CreateItemGetResponse(FileSystemInfoBase info, string localFilePath)
        {
            // CORE TODO Similar to VfsController: File() apparently has built in support for range requests and etags. From a cursory glance
            // that renders bascially all of this obsolete. Will need checking to ensure proper behavior. Can we use PhysicalFile instead?
            var stream = new RepositoryItemStream(this, GetFileReadStream(localFilePath));

            return(Task.FromResult(
                       (IActionResult)File(stream, MediaTypeMap.GetMediaType(info.Extension).ToString(), info.LastWriteTime, _currentEtag)));

            //// Check whether we have a conditional If-None-Match request
            //if (IsIfNoneMatchRequest(_currentEtag))
            //{
            //    var result = StatusCode(StatusCodes.Status304NotModified);
            //    // CORE TODO make sure this works properly
            //    Response.GetTypedHeaders().ETag = _currentEtag;
            //    return Task.FromResult((IActionResult)result);
            //}

            //// Check whether we have a conditional range request containing both a Range and If-Range header field
            //bool isRangeRequest = IsRangeRequest(_currentEtag);

            //// Generate file response
            //try
            //{
            //    _readStream = new RepositoryItemStream(this, GetFileReadStream(localFilePath));
            //    MediaTypeHeaderValue mediaType = MediaTypeMap.GetMediaType(info.Extension);
            //    HttpResponseMessage successFileResponse = Request.CreateResponse(isRangeRequest ? HttpStatusCode.PartialContent : HttpStatusCode.OK);

            //    if (isRangeRequest)
            //    {
            //        successFileResponse.Content = new ByteRangeStreamContent(_readStream, Request.Headers.Range, mediaType, BufferSize);
            //    }
            //    else
            //    {
            //        successFileResponse.Content = new StreamContent(_readStream, BufferSize);
            //        successFileResponse.Content.Headers.ContentType = mediaType;
            //    }

            //    // Set etag for the file
            //    successFileResponse.Headers.ETag = _currentEtag;
            //    return Task.FromResult(successFileResponse);
            //}
            //catch (InvalidByteRangeException invalidByteRangeException)
            //{
            //    // The range request had no overlap with the current extend of the resource so generate a 416 (Requested Range Not Satisfiable)
            //    // including a Content-Range header with the current size.
            //    Tracer.TraceError(invalidByteRangeException);
            //    HttpResponseMessage invalidByteRangeResponse = Request.CreateErrorResponse(invalidByteRangeException);
            //    CloseReadStream();
            //    return Task.FromResult(invalidByteRangeResponse);
            //}
            //catch (Exception ex)
            //{
            //    // Could not read the file
            //    Tracer.TraceError(ex);
            //    HttpResponseMessage errorResponse = Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
            //    CloseReadStream();
            //    return Task.FromResult(errorResponse);
            //}
        }
Esempio n. 6
0
        protected override Task <IActionResult> CreateItemGetResponse(FileSystemInfoBase info, string localFilePath)
        {
            var fileStream = GetFileReadStream(localFilePath);

            return(Task.FromResult(
                       (IActionResult)File(fileStream, MediaTypeMap.GetMediaType(info.Extension).ToString(), info.LastWriteTime, CreateEntityTag(info))));
        }
Esempio n. 7
0
        protected override Task <HttpResponseMessage> CreateItemGetResponse(FileSystemInfoBase info, string localFilePath)
        {
            // Check whether we have a conditional If-None-Match request
            if (IsIfNoneMatchRequest(_currentEtag))
            {
                HttpResponseMessage notModifiedResponse = Request.CreateResponse(HttpStatusCode.NotModified);
                notModifiedResponse.Headers.ETag = _currentEtag;
                return(Task.FromResult(notModifiedResponse));
            }

            // Check whether we have a conditional range request containing both a Range and If-Range header field
            bool isRangeRequest = IsRangeRequest(_currentEtag);

            // Generate file response
            try
            {
                _readStream = new RepositoryItemStream(this, GetFileReadStream(localFilePath));
                MediaTypeHeaderValue mediaType           = MediaTypeMap.GetMediaType(info.Extension);
                HttpResponseMessage  successFileResponse = Request.CreateResponse(isRangeRequest ? HttpStatusCode.PartialContent : HttpStatusCode.OK);

                if (isRangeRequest)
                {
                    successFileResponse.Content = new ByteRangeStreamContent(_readStream, Request.Headers.Range, mediaType, BufferSize);
                }
                else
                {
                    successFileResponse.Content = new StreamContent(_readStream, BufferSize);
                    successFileResponse.Content.Headers.ContentType = mediaType;
                }

                // Set etag for the file
                successFileResponse.Headers.ETag = _currentEtag;
                return(Task.FromResult(successFileResponse));
            }
            catch (InvalidByteRangeException invalidByteRangeException)
            {
                // The range request had no overlap with the current extend of the resource so generate a 416 (Requested Range Not Satisfiable)
                // including a Content-Range header with the current size.
                Tracer.TraceError(invalidByteRangeException);
                HttpResponseMessage invalidByteRangeResponse = Request.CreateErrorResponse(invalidByteRangeException);
                CloseReadStream();
                return(Task.FromResult(invalidByteRangeResponse));
            }
            catch (Exception ex)
            {
                // Could not read the file
                Tracer.TraceError(ex);
                HttpResponseMessage errorResponse = Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
                CloseReadStream();
                return(Task.FromResult(errorResponse));
            }
        }
Esempio n. 8
0
        protected override async Task <IActionResult> CreateItemPutResponse(FileSystemInfoBase info, string localFilePath, bool itemExists)
        {
            // If repository is empty then there is no commit id and no master branch so we don't create any branch; we just init the repo.
            if (_currentEtag != null)
            {
                if (!PrepareBranch(itemExists, out IActionResult errorResponse))
                {
                    return(errorResponse);
                }
            }
            else
            {
                // Initialize or re-initialize repository
                _repository.Initialize();
            }

            // Save file
            try
            {
                // Get the query parameters
                QueryParameters parameters = new QueryParameters(this.Request);

                using (Stream fileStream = GetFileWriteStream(localFilePath, fileExists: itemExists))
                {
                    try
                    {
                        await Request.Body.CopyToAsync(fileStream);
                    }
                    catch (Exception ex)
                    {
                        Tracer.TraceError(ex);
                        return(StatusCode(StatusCodes.Status409Conflict, RS.Format(Resources.VfsController_WriteConflict, localFilePath, ex.Message)));
                    }
                }

                // Use to track whether our rebase applied updates from master.
                bool updateBranchIsUpToDate = true;

                // Commit to local branch
                bool commitResult = _repository.Commit(parameters.Message, authorName: null, emailAddress: null);
                if (!commitResult)
                {
                    // TODO this is janky here, we return an actionresult but set the etag on the response directly
                    Response.GetTypedHeaders().ETag = CreateEtag(_repository.CurrentId);
                    return(NoContent());
                }

                bool rebasing = false;
                if (_currentEtag != null)
                {
                    try
                    {
                        // Only rebase if VFS branch isn't up-to-date already
                        if (!_repository.DoesBranchContainCommit(VfsUpdateBranch, MasterBranch))
                        {
                            // Rebase to get updates from master while checking whether we get a conflict
                            rebasing = true;
                            updateBranchIsUpToDate = _repository.Rebase(MasterBranch);
                        }

                        // Switch content back to master
                        _repository.UpdateRef(VfsUpdateBranch);
                    }
                    catch (CommandLineException commandLineException)
                    {
                        Tracer.TraceError(commandLineException);

                        if (rebasing)
                        {
                            // The rebase resulted in a conflict. We send the conflicted version to the client so that the user
                            // can see the conflicts and resubmit.
                            _cleanupRebaseConflict = true;

                            // CORE TODO not sure this works; I'm not sure you can set StatusCode for a File result
                            Response.StatusCode = StatusCodes.Status409Conflict;
                            _readStream         = new RepositoryItemStream(this, GetFileReadStream(localFilePath));
                            // CORE TODO make sure mediatype.tostring works as intended here
                            return(File(_readStream, _conflictMediaType.ToString()));

                            //HttpResponseMessage conflictResponse = Request.CreateResponse(HttpStatusCode.Conflict);
                            //_readStream = new RepositoryItemStream(this, GetFileReadStream(localFilePath));
                            //conflictResponse.Content = new StreamContent(_readStream, BufferSize);
                            //conflictResponse.Content.Headers.ContentType = _conflictMediaType;
                            //return conflictResponse;
                        }
                        else
                        {
                            return(StatusCode(StatusCodes.Status500InternalServerError,
                                              RS.Format(Resources.VfsScmUpdate_Error, commandLineException.Message)));
                        }
                    }
                }

                // If item does not already exist then we return 201 Created. Otherwise, as a successful commit could result
                // in a non-conflicting merge we send back the committed version so that a client
                // can get the latest bits. This means we use a 200 OK response instead of a 204 response.
                IActionResult successFileResponse = null;
                if (itemExists)
                {
                    if (updateBranchIsUpToDate)
                    {
                        successFileResponse = NoContent();
                    }
                    else
                    {
                        _readStream         = new RepositoryItemStream(this, GetFileReadStream(localFilePath));
                        successFileResponse = File(_readStream, MediaTypeMap.GetMediaType(info.Extension).ToString());
                    }
                }
                else
                {
                    successFileResponse = StatusCode(StatusCodes.Status201Created);
                }

                // Get current commit ID
                string currentId = _repository.CurrentId;

                // Deploy changes unless request indicated to not deploy
                if (!parameters.NoDeploy)
                {
                    DeployResult result = await DeployChangesAsync(currentId);

                    if (result != null && result.Status != DeployStatus.Success)
                    {
                        return(StatusCode(StatusCodes.Status500InternalServerError, RS.Format(Resources.VfsScmController_DeploymentError, result.StatusText)));
                    }
                }

                // Set updated etag for the file
                Response.GetTypedHeaders().ETag = CreateEtag(currentId);
                return(successFileResponse);
            }
            catch (Exception ex)
            {
                Tracer.TraceError(ex);
                return(StatusCode(StatusCodes.Status409Conflict, RS.Format(Resources.VfsController_WriteConflict, localFilePath, ex.Message)));
            }
        }
Esempio n. 9
0
        protected override Task <HttpResponseMessage> CreateItemGetResponse(FileSystemInfoBase info, string localFilePath)
        {
            // Get current etag
            EntityTagHeaderValue currentEtag = CreateEntityTag(info);

            // Check whether we have a range request (taking If-Range condition into account)
            bool isRangeRequest = IsRangeRequest(currentEtag);

            // Check whether we have a conditional If-None-Match request
            // Unless it is a range request (see RFC2616 sec 14.35.2 Range Retrieval Requests)
            if (!isRangeRequest && IsIfNoneMatchRequest(currentEtag))
            {
                HttpResponseMessage notModifiedResponse = Request.CreateResponse(HttpStatusCode.NotModified);
                notModifiedResponse.Headers.ETag = currentEtag;
                return(Task.FromResult(notModifiedResponse));
            }

            // Generate file response
            Stream fileStream = null;

            try
            {
                fileStream = GetFileReadStream(localFilePath);
                MediaTypeHeaderValue mediaType           = MediaTypeMap.GetMediaType(info.Extension);
                HttpResponseMessage  successFileResponse = Request.CreateResponse(isRangeRequest ? HttpStatusCode.PartialContent : HttpStatusCode.OK);

                if (isRangeRequest)
                {
                    successFileResponse.Content = new ByteRangeStreamContent(fileStream, Request.Headers.Range, mediaType, BufferSize);
                }
                else
                {
                    successFileResponse.Content = new StreamContent(fileStream, BufferSize);
                    successFileResponse.Content.Headers.ContentType = mediaType;
                }

                // Set etag for the file
                successFileResponse.Headers.ETag = currentEtag;
                return(Task.FromResult(successFileResponse));
            }
            catch (InvalidByteRangeException invalidByteRangeException)
            {
                // The range request had no overlap with the current extend of the resource so generate a 416 (Requested Range Not Satisfiable)
                // including a Content-Range header with the current size.
                Tracer.TraceError(invalidByteRangeException);
                HttpResponseMessage invalidByteRangeResponse = Request.CreateErrorResponse(invalidByteRangeException);
                if (fileStream != null)
                {
                    fileStream.Close();
                }
                return(Task.FromResult(invalidByteRangeResponse));
            }
            catch (Exception ex)
            {
                // Could not read the file
                Tracer.TraceError(ex);
                HttpResponseMessage errorResponse = Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
                if (fileStream != null)
                {
                    fileStream.Close();
                }
                return(Task.FromResult(errorResponse));
            }
        }
 public void GetMediaType_HandlesKnownMediaTypes(string extension, string expectedMediaType)
 {
     MediaTypeMap map = new MediaTypeMap();
     MediaTypeHeaderValue expected = new MediaTypeHeaderValue(expectedMediaType);
     Assert.Equal(expected, map.GetMediaType(extension));
 }
 public void GetMediaType_Guards()
 {
     MediaTypeMap map = new MediaTypeMap();
     ArgumentNullException ex = Assert.Throws<ArgumentNullException>(() => map.GetMediaType(null));
     Assert.Equal("fileExtension", ex.ParamName);
 }
        protected override async Task <HttpResponseMessage> CreateItemPutResponse(FileSystemInfo info, string localFilePath, bool itemExists)
        {
            // If repository is empty then there is no commit id and no master branch so we don't create any branch; we just init the repo.
            if (_currentEtag != null)
            {
                HttpResponseMessage errorResponse;
                if (!PrepareBranch(itemExists, out errorResponse))
                {
                    return(errorResponse);
                }
            }
            else
            {
                // Initialize or re-initialize repository
                _repository.Initialize();
            }

            // Save file
            try
            {
                using (Stream fileStream = GetFileWriteStream(localFilePath, fileExists: itemExists))
                {
                    try
                    {
                        await Request.Content.CopyToAsync(fileStream);
                    }
                    catch (Exception ex)
                    {
                        Tracer.TraceError(ex);
                        HttpResponseMessage conflictResponse = Request.CreateErrorResponse(
                            HttpStatusCode.Conflict, RS.Format(Resources.VfsController_WriteConflict, localFilePath),
                            ex);
                        return(conflictResponse);
                    }
                }


                // Use to track whether our rebase applied updates from master.
                bool updateBranchIsUpToDate = false;

                // Commit to local branch
                bool commitResult = _repository.Commit(String.Format("Committing update from request {0}", Request.RequestUri), authorName: null);
                if (!commitResult)
                {
                    HttpResponseMessage noChangeResponse = Request.CreateResponse(HttpStatusCode.NoContent);
                    noChangeResponse.Headers.ETag = CreateEtag(_repository.CurrentId);
                    return(noChangeResponse);
                }

                if (_currentEtag != null)
                {
                    try
                    {
                        // Rebase to get updates from master while checking whether we get a conflict
                        updateBranchIsUpToDate = _repository.Rebase(MasterBranch);

                        // Switch content back to master
                        _repository.UpdateRef(VfsUpdateBranch);
                    }
                    catch (CommandLineException commandLineException)
                    {
                        Tracer.TraceError(commandLineException);

                        // The rebase resulted in a conflict. We send the conflicted version to the client so that the user
                        // can see the conflicts and resubmit.
                        _cleanupRebaseConflict = true;
                        HttpResponseMessage conflictResponse = Request.CreateResponse(HttpStatusCode.Conflict);
                        _readStream = new RepositoryItemStream(this, GetFileReadStream(localFilePath));
                        conflictResponse.Content = new StreamContent(_readStream, BufferSize);
                        conflictResponse.Content.Headers.ContentType = _conflictMediaType;
                        return(conflictResponse);
                    }
                }

                // If item does not already exist then we return 201 Created. Otherwise, as a successful commit could result
                // in a non-conflicting merge we send back the committed version so that a client
                // can get the latest bits. This means we use a 200 OK response instead of a 204 response.
                HttpResponseMessage successFileResponse = null;
                if (itemExists)
                {
                    if (updateBranchIsUpToDate)
                    {
                        successFileResponse = Request.CreateResponse(HttpStatusCode.NoContent);
                    }
                    else
                    {
                        successFileResponse         = Request.CreateResponse(HttpStatusCode.OK);
                        _readStream                 = new RepositoryItemStream(this, GetFileReadStream(localFilePath));
                        successFileResponse.Content = new StreamContent(_readStream, BufferSize);
                        successFileResponse.Content.Headers.ContentType = MediaTypeMap.GetMediaType(info.Extension);
                    }
                }
                else
                {
                    successFileResponse = Request.CreateResponse(HttpStatusCode.Created);
                }

                // Deploy changes
                DeployResult result = DeployChanges();
                if (result != null && result.Status != DeployStatus.Success)
                {
                    HttpResponseMessage deploymentErrorResponse =
                        Request.CreateErrorResponse(HttpStatusCode.InternalServerError, RS.Format(Resources.VfsScmController_DeploymentError, result.StatusText));
                    return(deploymentErrorResponse);
                }

                // Set updated etag for the file
                successFileResponse.Headers.ETag = CreateEtag(_repository.CurrentId);
                return(successFileResponse);
            }
            catch (Exception e)
            {
                Tracer.TraceError(e);
                HttpResponseMessage errorResponse = Request.CreateErrorResponse(HttpStatusCode.Conflict,
                                                                                RS.Format(Resources.VfsController_WriteConflict, localFilePath), e);
                return(errorResponse);
            }
        }
Esempio n. 13
0
        protected override Task <IActionResult> CreateItemGetResponse(FileSystemInfoBase info, string localFilePath)
        {
            // CORE TODO File() apparently has built in support for range requests and etags. From a cursory glance
            // that renders bascially all of commented implementation belowthis obsolete. Will need checking to ensure proper behavior.
            var fileStream = GetFileReadStream(localFilePath);

            return(Task.FromResult(
                       (IActionResult)File(fileStream, MediaTypeMap.GetMediaType(info.Extension).ToString(), info.LastWriteTime, CreateEntityTag(info))));

            /*
             * // Get current etag
             * EntityTagHeaderValue currentEtag = CreateEntityTag(info);
             * DateTime lastModified = info.LastWriteTimeUtc;
             *
             * // Check whether we have a range request (taking If-Range condition into account)
             * bool isRangeRequest = IsRangeRequest(currentEtag);
             *
             * // Check whether we have a conditional If-None-Match request
             * // Unless it is a range request (see RFC2616 sec 14.35.2 Range Retrieval Requests)
             * if (!isRangeRequest && IsIfNoneMatchRequest(currentEtag))
             * {
             *  Response.SetEntityTagHeader(currentEtag, lastModified);
             *  return Task.FromResult((IActionResult)StatusCode(StatusCodes.Status304NotModified)));
             * }
             *
             * // Generate file response
             * Stream fileStream = null;
             * try
             * {
             *  fileStream = GetFileReadStream(localFilePath);
             *  MediaTypeHeaderValue mediaType = MediaTypeMap.GetMediaType(info.Extension);
             *  HttpResponseMessage successFileResponse = Request.CreateResponse(isRangeRequest ? HttpStatusCode.PartialContent : HttpStatusCode.OK);
             *
             *  if (isRangeRequest)
             *  {
             *      successFileResponse.Content = new ByteRangeStreamContent(fileStream, Request.Headers.Range, mediaType, BufferSize);
             *  }
             *  else
             *  {
             *      successFileResponse.Content = new StreamContent(fileStream, BufferSize);
             *      successFileResponse.Content.Headers.ContentType = mediaType;
             *  }
             *
             *  // Set etag for the file
             *  successFileResponse.SetEntityTagHeader(currentEtag, lastModified);
             *  return Task.FromResult(successFileResponse);
             * }
             * catch (InvalidByteRangeException invalidByteRangeException)
             * {
             *  // The range request had no overlap with the current extend of the resource so generate a 416 (Requested Range Not Satisfiable)
             *  // including a Content-Range header with the current size.
             *  Tracer.TraceError(invalidByteRangeException);
             *  HttpResponseMessage invalidByteRangeResponse = Request.CreateErrorResponse(invalidByteRangeException);
             *  if (fileStream != null)
             *  {
             *      fileStream.Close();
             *  }
             *  return Task.FromResult(invalidByteRangeResponse);
             * }
             * catch (Exception ex)
             * {
             *  // Could not read the file
             *  Tracer.TraceError(ex);
             *  HttpResponseMessage errorResponse = Request.CreateErrorResponse(HttpStatusCode.NotFound, ex);
             *  if (fileStream != null)
             *  {
             *      fileStream.Close();
             *  }
             *  return Task.FromResult(errorResponse);
             * }
             */
        }