public HttpResponseMessage GetDeployResults()
        {
            HttpResponseMessage  response;
            EntityTagHeaderValue currentEtag       = null;
            DeploymentsCacheItem cachedDeployments = _cachedDeployments;

            using (_tracer.Step("DeploymentService.GetCurrentEtag"))
            {
                currentEtag = GetCurrentEtag(Request);
                _tracer.Trace("Current Etag: {0}, Cached Etag: {1}", currentEtag, cachedDeployments.Etag);
            }

            if (EtagEquals(Request, currentEtag))
            {
                response = Request.CreateResponse(HttpStatusCode.NotModified);
            }
            else
            {
                using (_tracer.Step("DeploymentService.GetDeployResults"))
                {
                    if (!currentEtag.Equals(cachedDeployments.Etag))
                    {
                        cachedDeployments = new DeploymentsCacheItem
                        {
                            Results = GetResults(Request).ToList(),
                            Etag    = currentEtag
                        };

                        _cachedDeployments = cachedDeployments;
                    }

                    response = Request.CreateResponse(HttpStatusCode.OK, ArmUtils.AddEnvelopeOnArmRequest(cachedDeployments.Results, Request));
                }
            }

            // return etag
            response.Headers.ETag = currentEtag;

            return(response);
        }
Beispiel #2
0
        public void Equals_UseSameAndDifferentETags_EqualOrNotEqualNoExceptions()
        {
            EntityTagHeaderValue etag1 = new EntityTagHeaderValue("\"tag\"");
            EntityTagHeaderValue etag2 = new EntityTagHeaderValue("\"TAG\"");
            EntityTagHeaderValue etag3 = new EntityTagHeaderValue("\"tag\"", true);
            EntityTagHeaderValue etag4 = new EntityTagHeaderValue("\"tag1\"");
            EntityTagHeaderValue etag5 = new EntityTagHeaderValue("\"tag\"");
            EntityTagHeaderValue etag6 = EntityTagHeaderValue.Any;

            Assert.False(etag1.Equals(etag2));
            Assert.False(etag2.Equals(etag1));
            Assert.False(etag1.Equals(null));
            Assert.False(etag1.Equals(etag3));
            Assert.False(etag3.Equals(etag1));
            Assert.False(etag1.Equals(etag4));
            Assert.False(etag1.Equals(etag6));
            Assert.True(etag1.Equals(etag5));
        }
        private bool TryGetCachedLatestDeployment(EntityTagHeaderValue latestEtag, out HttpResponseMessage cachedResponse)
        {
            cachedResponse = null;

            var cachedLatestDeployment = _cachedLatestDeployment;

            if (latestEtag != null &&
                cachedLatestDeployment != null &&
                !cachedLatestDeployment.Expired &&
                latestEtag.Equals(cachedLatestDeployment.Etag) &&
                (ArmUtils.IsAzureResourceManagerUserAgent(Request) || ArmUtils.IsVSTSDevOpsUserAgent(Request)))
            {
                var result = cachedLatestDeployment.Result;
                switch (result.Status)
                {
                case DeployStatus.Building:
                case DeployStatus.Deploying:
                case DeployStatus.Pending:
                    cachedResponse = Request.CreateResponse(HttpStatusCode.Accepted, ArmUtils.AddEnvelopeOnArmRequest(result, Request));
                    cachedResponse.Headers.Location   = GetResponseLocation(Request);
                    cachedResponse.Headers.RetryAfter = new RetryConditionHeaderValue(TimeSpan.FromSeconds(ScmHostingConfigurations.ArmRetryAfterSeconds));
                    break;

                case DeployStatus.Failed:
                case DeployStatus.Success:
                    cachedResponse = Request.CreateResponse(HttpStatusCode.OK, ArmUtils.AddEnvelopeOnArmRequest(result, Request));
                    break;

                default:
                    cachedResponse = null;
                    break;
                }
            }

            return(cachedResponse != null);
        }
        public static ETag GetETag(this HttpRequestMessage request, EntityTagHeaderValue entityTagHeaderValue)
        {
            if (request == null)
            {
                throw Error.ArgumentNull("request");
            }

            if (entityTagHeaderValue != null)
            {
                if (entityTagHeaderValue.Equals(EntityTagHeaderValue.Any))
                {
                    return(new ETag {
                        IsAny = true
                    });
                }

                HttpConfiguration configuration = request.GetConfiguration();
                if (configuration == null)
                {
                    throw Error.InvalidOperation(SRResources.RequestMustContainConfiguration);
                }

                // get the etag handler, and parse the etag
                IDictionary <string, object> properties =
                    configuration.GetETagHandler().ParseETag(entityTagHeaderValue) ?? new Dictionary <string, object>();
                IList <object> parsedETagValues = properties.Select(property => property.Value).AsList();

                // get property names from request
                ODataPath            odataPath = request.ODataProperties().Path;
                IEdmModel            model     = request.ODataProperties().Model;
                IEdmNavigationSource source    = odataPath.NavigationSource;
                if (model != null && source != null)
                {
                    IList <IEdmStructuralProperty> concurrencyProperties = model.GetConcurrencyProperties(source).ToList();
                    IList <string> concurrencyPropertyNames = concurrencyProperties.OrderBy(c => c.Name).Select(c => c.Name).AsList();
                    ETag           etag = new ETag();

                    if (parsedETagValues.Count != concurrencyPropertyNames.Count)
                    {
                        etag.IsWellFormed = false;
                    }

                    IEnumerable <KeyValuePair <string, object> > nameValues = concurrencyPropertyNames.Zip(
                        parsedETagValues,
                        (name, value) => new KeyValuePair <string, object>(name, value));
                    foreach (var nameValue in nameValues)
                    {
                        IEdmStructuralProperty property = concurrencyProperties.SingleOrDefault(e => e.Name == nameValue.Key);
                        Contract.Assert(property != null);

                        Type clrType = EdmLibHelpers.GetClrType(property.Type, model);
                        Contract.Assert(clrType != null);

                        if (nameValue.Value != null)
                        {
                            Type valueType = nameValue.Value.GetType();
                            etag[nameValue.Key] = valueType != clrType
                                ? Convert.ChangeType(nameValue.Value, clrType, CultureInfo.InvariantCulture)
                                : nameValue.Value;
                        }
                        else
                        {
                            etag[nameValue.Key] = nameValue.Value;
                        }
                    }

                    return(etag);
                }
            }

            return(null);
        }
Beispiel #5
0
 /// <summary>
 /// Indicates whether this is a If-None-Match request with a matching etag.
 /// </summary>
 protected bool IsIfNoneMatchRequest(EntityTagHeaderValue currentEtag)
 {
     return(currentEtag != null && Request.Headers.IfNoneMatch != null &&
            Request.Headers.IfNoneMatch.Any(entityTag => currentEtag.Equals(entityTag)));
 }
Beispiel #6
0
 private static bool EtagEquals(HttpRequestMessage request, EntityTagHeaderValue currentEtag)
 {
     return(request.Headers.IfNoneMatch != null &&
            request.Headers.IfNoneMatch.Any(etag => currentEtag.Equals(etag)));
 }
Beispiel #7
0
        protected override Task <HttpResponseMessage> CreateFileDeleteResponse(FileInfoBase info)
        {
            // Existing resources require an etag to be updated.
            if (Request.Headers.IfMatch == null)
            {
                HttpResponseMessage conflictDirectoryResponse = Request.CreateErrorResponse(
                    HttpStatusCode.PreconditionFailed, Resources.VfsController_MissingIfMatch);
                return(Task.FromResult(conflictDirectoryResponse));
            }

            // Get current etag
            EntityTagHeaderValue currentEtag = CreateEntityTag(info);
            bool isMatch = Request.Headers.IfMatch.Any(etag => etag == EntityTagHeaderValue.Any || currentEtag.Equals(etag));

            if (!isMatch)
            {
                HttpResponseMessage conflictFileResponse = Request.CreateErrorResponse(
                    HttpStatusCode.PreconditionFailed, Resources.VfsController_EtagMismatch);
                conflictFileResponse.Headers.ETag = currentEtag;
                return(Task.FromResult(conflictFileResponse));
            }

            return(base.CreateFileDeleteResponse(info));
        }
Beispiel #8
0
        protected override async Task <HttpResponseMessage> CreateItemPutResponse(FileSystemInfoBase info, string localFilePath, bool itemExists)
        {
            // Check that we have a matching conditional If-Match request for existing resources
            if (itemExists)
            {
                // Get current etag
                EntityTagHeaderValue currentEtag = CreateEntityTag(info);

                // Existing resources require an etag to be updated.
                if (Request.Headers.IfMatch == null)
                {
                    HttpResponseMessage missingIfMatchResponse = Request.CreateErrorResponse(
                        HttpStatusCode.PreconditionFailed, Resources.VfsController_MissingIfMatch);
                    return(missingIfMatchResponse);
                }

                bool isMatch = false;
                foreach (EntityTagHeaderValue etag in Request.Headers.IfMatch)
                {
                    if (currentEtag.Equals(etag) || etag == EntityTagHeaderValue.Any)
                    {
                        isMatch = true;
                        break;
                    }
                }

                if (!isMatch)
                {
                    HttpResponseMessage conflictFileResponse = Request.CreateErrorResponse(
                        HttpStatusCode.PreconditionFailed, Resources.VfsController_EtagMismatch);
                    conflictFileResponse.Headers.ETag = currentEtag;
                    return(conflictFileResponse);
                }
            }

            // 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.Message),
                            ex);

                        return(conflictResponse);
                    }
                }

                // Return either 204 No Content or 201 Created response
                HttpResponseMessage successFileResponse =
                    Request.CreateResponse(itemExists ? HttpStatusCode.NoContent : HttpStatusCode.Created);

                // Set updated etag for the file
                info.Refresh();
                successFileResponse.Headers.ETag = CreateEntityTag(info);
                return(successFileResponse);
            }
            catch (Exception ex)
            {
                Tracer.TraceError(ex);
                HttpResponseMessage errorResponse =
                    Request.CreateErrorResponse(HttpStatusCode.Conflict,
                                                RS.Format(Resources.VfsController_WriteConflict, localFilePath, ex.Message), ex);

                return(errorResponse);
            }
        }
        private void ComputeRange()
        {
            // 14.35 Range
            // http://tools.ietf.org/html/draft-ietf-httpbis-p5-range-24

            // A server MUST ignore a Range header field received with a request method other
            // than GET.
            if (!_isGet)
            {
                return;
            }

            var rawRangeHeader = _request.Headers[HeaderNames.Range];

            if (StringValues.IsNullOrEmpty(rawRangeHeader))
            {
                return;
            }

            // Perf: Check for a single entry before parsing it
            if (rawRangeHeader.Count > 1 || rawRangeHeader[0].IndexOf(',') >= 0)
            {
                // The spec allows for multiple ranges but we choose not to support them because the client may request
                // very strange ranges (e.g. each byte separately, overlapping ranges, etc.) that could negatively
                // impact the server. Ignore the header and serve the response normally.
                _logger.LogMultipleFileRanges(rawRangeHeader.ToString());
                return;
            }

            var rangeHeader = _requestHeaders.Range;

            if (rangeHeader == null)
            {
                // Invalid
                return;
            }

            // Already verified above
            Debug.Assert(rangeHeader.Ranges.Count == 1);

            // 14.27 If-Range
            var ifRangeHeader = _requestHeaders.IfRange;

            if (ifRangeHeader != null)
            {
                // If the validator given in the If-Range header field matches the
                // current validator for the selected representation of the target
                // resource, then the server SHOULD process the Range header field as
                // requested.  If the validator does not match, the server MUST ignore
                // the Range header field.
                bool ignoreRangeHeader = false;
                if (ifRangeHeader.LastModified.HasValue)
                {
                    if (_lastModified > ifRangeHeader.LastModified)
                    {
                        ignoreRangeHeader = true;
                    }
                }
                else if (ifRangeHeader.EntityTag != null && !_etag.Equals(ifRangeHeader.EntityTag))
                {
                    ignoreRangeHeader = true;
                }
                if (ignoreRangeHeader)
                {
                    return;
                }
            }

            _ranges = RangeHelpers.NormalizeRanges(rangeHeader.Ranges, _length);
        }
Beispiel #10
0
        protected override Task <IActionResult> CreateFileDeleteResponse(FileInfoBase info)
        {
            // Existing resources require an etag to be updated.
            var requestHeaders = Request.GetTypedHeaders();

            // CORE TODO double check semantics of what you get from GetTypedHeaders() (empty strings vs null, etc.)
            if (requestHeaders.IfMatch == null)
            {
                return(Task.FromResult((IActionResult)StatusCode(StatusCodes.Status412PreconditionFailed, Resources.VfsController_MissingIfMatch)));
            }

            // Get current etag
            EntityTagHeaderValue currentEtag = CreateEntityTag(info);
            bool isMatch = requestHeaders.IfMatch.Any(etag => etag == EntityTagHeaderValue.Any || currentEtag.Equals(etag));

            if (!isMatch)
            {
                Response.GetTypedHeaders().ETag = currentEtag;
                return(Task.FromResult((IActionResult)StatusCode(StatusCodes.Status409Conflict, Resources.VfsController_EtagMismatch)));
            }

            return(base.CreateFileDeleteResponse(info));
        }
Beispiel #11
0
        protected override Task <HttpResponseMessage> CreateItemPutResponse(FileSystemInfo info, string localFilePath, bool itemExists)
        {
            // Check that we have a matching conditional If-Match request for existing resources
            if (itemExists)
            {
                // Get current etag
                EntityTagHeaderValue currentEtag = GetCurrentEtag(info);

                // Existing resources require an etag to be updated.
                if (Request.Headers.IfMatch == null)
                {
                    HttpResponseMessage missingIfMatchResponse = Request.CreateErrorResponse(
                        HttpStatusCode.PreconditionFailed, Resources.VfsController_MissingIfMatch);
                    return(Task.FromResult(missingIfMatchResponse));
                }

                bool isMatch = false;
                foreach (EntityTagHeaderValue etag in Request.Headers.IfMatch)
                {
                    if (currentEtag.Equals(etag) || etag == EntityTagHeaderValue.Any)
                    {
                        isMatch = true;
                        break;
                    }
                }

                if (!isMatch)
                {
                    HttpResponseMessage conflictFileResponse = Request.CreateErrorResponse(
                        HttpStatusCode.PreconditionFailed, Resources.VfsController_EtagMismatch);
                    conflictFileResponse.Headers.ETag = currentEtag;
                    return(Task.FromResult(conflictFileResponse));
                }
            }

            // Save file
            Stream fileStream = null;

            try
            {
                fileStream = GetFileWriteStream(localFilePath, fileExists: itemExists);
                return(Request.Content.CopyToAsync(fileStream)
                       .Then(() =>
                {
                    // Successfully saved the file
                    fileStream.Close();
                    fileStream = null;

                    // Return either 204 No Content or 201 Created response
                    HttpResponseMessage successFileResponse =
                        Request.CreateResponse(itemExists ? HttpStatusCode.NoContent : HttpStatusCode.Created);

                    // Set updated etag for the file
                    successFileResponse.Headers.ETag = GetUpdatedEtag(localFilePath);
                    return successFileResponse;
                })
                       .Catch((catchInfo) =>
                {
                    Tracer.TraceError(catchInfo.Exception);
                    HttpResponseMessage conflictResponse = Request.CreateErrorResponse(
                        HttpStatusCode.Conflict,
                        RS.Format(Resources.VfsController_WriteConflict, localFilePath),
                        catchInfo.Exception);

                    if (fileStream != null)
                    {
                        fileStream.Close();
                    }

                    return catchInfo.Handled(conflictResponse);
                }));
            }
            catch (Exception e)
            {
                Tracer.TraceError(e);
                HttpResponseMessage errorResponse =
                    Request.CreateErrorResponse(HttpStatusCode.Conflict,
                                                RS.Format(Resources.VfsController_WriteConflict, localFilePath), e);
                if (fileStream != null)
                {
                    fileStream.Close();
                }
                return(Task.FromResult(errorResponse));
            }
        }