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); }
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); }
/// <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))); }
private static bool EtagEquals(HttpRequestMessage request, EntityTagHeaderValue currentEtag) { return(request.Headers.IfNoneMatch != null && request.Headers.IfNoneMatch.Any(etag => currentEtag.Equals(etag))); }
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)); }
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); }
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)); }
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)); } }