Пример #1
0
		public static bool TryParse (string input, out EntityTagHeaderValue parsedValue)
		{
			parsedValue = null;

			var lexer = new Lexer (input);
			var t = lexer.Scan ();
			bool is_weak = false;

			if (t == Token.Type.Token) {
				if (lexer.GetStringValue (t) != "W" || lexer.PeekChar () != '/')
					return false;

				is_weak = true;
				lexer.EatChar ();
				t = lexer.Scan ();
			}

			if (t != Token.Type.QuotedString)
				return false;

			if (lexer.Scan () != Token.Type.End)
				return false;

			parsedValue = new EntityTagHeaderValue ();
			parsedValue.Tag = lexer.GetStringValue (t);
			parsedValue.IsWeak = is_weak;
			return true;
		}
Пример #2
0
        protected virtual (RangeItemHeaderValue range, long rangeLength, bool serveBody) SetHeadersAndLog(
            ActionContext context,
            FileResult result,
            long?fileLength,
            bool enableRangeProcessing,
            DateTimeOffset?lastModified = null,
            EntityTagHeaderValue etag   = null)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }
            if (result == null)
            {
                throw new ArgumentNullException(nameof(result));
            }

            SetContentType(context, result);
            SetContentDispositionHeader(context, result);

            var request            = context.HttpContext.Request;
            var httpRequestHeaders = request.GetTypedHeaders();
            var preconditionState  = GetPreconditionState(httpRequestHeaders, lastModified, etag);

            var response = context.HttpContext.Response;

            SetLastModifiedAndEtagHeaders(response, lastModified, etag);

            // Short circuit if the preconditional headers process to 304 (NotModified) or 412 (PreconditionFailed)
            if (preconditionState == PreconditionState.NotModified)
            {
                response.StatusCode = StatusCodes.Status304NotModified;
                return(range : null, rangeLength : 0, serveBody : false);
            }
            else if (preconditionState == PreconditionState.PreconditionFailed)
            {
                response.StatusCode = StatusCodes.Status412PreconditionFailed;
                return(range : null, rangeLength : 0, serveBody : false);
            }

            if (fileLength.HasValue)
            {
                // Assuming the request is not a range request, and the response body is not empty, the Content-Length header is set to
                // the length of the entire file.
                // If the request is a valid range request, this header is overwritten with the length of the range as part of the
                // range processing (see method SetContentLength).

                response.ContentLength = fileLength.Value;

                // Handle range request
                if (enableRangeProcessing)
                {
                    SetAcceptRangeHeader(response);

                    // If the request method is HEAD or GET, PreconditionState is Unspecified or ShouldProcess, and IfRange header is valid,
                    // range should be processed and Range headers should be set
                    if ((HttpMethods.IsHead(request.Method) || HttpMethods.IsGet(request.Method)) &&
                        (preconditionState == PreconditionState.Unspecified || preconditionState == PreconditionState.ShouldProcess) &&
                        (IfRangeValid(httpRequestHeaders, lastModified, etag)))
                    {
                        return(SetRangeHeaders(context, httpRequestHeaders, fileLength.Value));
                    }
                }
                else
                {
                    Logger.NotEnabledForRangeProcessing();
                }
            }

            return(range : null, rangeLength : 0, serveBody : !HttpMethods.IsHead(request.Method));
        }
Пример #3
0
        // Internal for testing
        internal PreconditionState GetPreconditionState(
            RequestHeaders httpRequestHeaders,
            DateTimeOffset?lastModified = null,
            EntityTagHeaderValue etag   = null)
        {
            var ifMatchState           = PreconditionState.Unspecified;
            var ifNoneMatchState       = PreconditionState.Unspecified;
            var ifModifiedSinceState   = PreconditionState.Unspecified;
            var ifUnmodifiedSinceState = PreconditionState.Unspecified;

            // 14.24 If-Match
            var ifMatch = httpRequestHeaders.IfMatch;

            if (etag != null)
            {
                ifMatchState = GetEtagMatchState(
                    etagHeader: ifMatch,
                    etag: etag,
                    matchFoundState: PreconditionState.ShouldProcess,
                    matchNotFoundState: PreconditionState.PreconditionFailed);

                if (ifMatchState == PreconditionState.PreconditionFailed)
                {
                    Logger.IfMatchPreconditionFailed(etag);
                }
            }

            // 14.26 If-None-Match
            var ifNoneMatch = httpRequestHeaders.IfNoneMatch;

            if (etag != null)
            {
                ifNoneMatchState = GetEtagMatchState(
                    etagHeader: ifNoneMatch,
                    etag: etag,
                    matchFoundState: PreconditionState.NotModified,
                    matchNotFoundState: PreconditionState.ShouldProcess);
            }

            var now = DateTimeOffset.UtcNow;

            // 14.25 If-Modified-Since
            var ifModifiedSince = httpRequestHeaders.IfModifiedSince;

            if (lastModified.HasValue && ifModifiedSince.HasValue && ifModifiedSince <= now)
            {
                var modified = ifModifiedSince < lastModified;
                ifModifiedSinceState = modified ? PreconditionState.ShouldProcess : PreconditionState.NotModified;
            }

            // 14.28 If-Unmodified-Since
            var ifUnmodifiedSince = httpRequestHeaders.IfUnmodifiedSince;

            if (lastModified.HasValue && ifUnmodifiedSince.HasValue && ifUnmodifiedSince <= now)
            {
                var unmodified = ifUnmodifiedSince >= lastModified;
                ifUnmodifiedSinceState = unmodified ? PreconditionState.ShouldProcess : PreconditionState.PreconditionFailed;

                if (ifUnmodifiedSinceState == PreconditionState.PreconditionFailed)
                {
                    Logger.IfUnmodifiedSincePreconditionFailed(lastModified, ifUnmodifiedSince);
                }
            }

            var state = GetMaxPreconditionState(ifMatchState, ifNoneMatchState, ifModifiedSinceState, ifUnmodifiedSinceState);

            return(state);
        }
Пример #4
0
        private static void SetLastModifiedAndEtagHeaders(HttpResponse response, DateTimeOffset?lastModified, EntityTagHeaderValue etag)
        {
            var httpResponseHeaders = response.GetTypedHeaders();

            if (lastModified.HasValue)
            {
                httpResponseHeaders.LastModified = lastModified;
            }
            if (etag != null)
            {
                httpResponseHeaders.ETag = etag;
            }
        }
Пример #5
0
        private async Task <FileOperationResult <Image> > GetImageFileOperation(string type, string regionUrn, Guid id,
                                                                                int?width, int?height, Func <Task <FileOperationResult <Image> > > action, EntityTagHeaderValue etag = null)
        {
            try
            {
                var sw     = Stopwatch.StartNew();
                var result = (await CacheManager.GetAsync($"urn:{type}_by_id_operation:{id}", action, regionUrn))
                             .Adapt <FileOperationResult <Image> >();
                if (!result.IsSuccess)
                {
                    return(new FileOperationResult <Image>(result.IsNotFoundResult, result.Messages));
                }
                if (result.ETag == etag)
                {
                    return(new FileOperationResult <Image>(OperationMessages.NotModified));
                }
                if ((width.HasValue || height.HasValue) && result?.Data?.Bytes != null)
                {
                    result.Data.Bytes   = ImageHelper.ResizeImage(result?.Data?.Bytes, width.Value, height.Value);
                    result.ETag         = EtagHelper.GenerateETag(HttpEncoder, result.Data.Bytes);
                    result.LastModified = DateTime.UtcNow;
                    if (width.Value != Configuration.ThumbnailImageSize.Width ||
                        height.Value != Configuration.ThumbnailImageSize.Height)
                    {
                        Logger.LogTrace($"{type}: Resized [{id}], Width [{width.Value}], Height [{height.Value}]");
                    }
                }

                sw.Stop();
                return(new FileOperationResult <Image>(result.Messages)
                {
                    Data = result.Data,
                    ETag = result.ETag,
                    LastModified = result.LastModified,
                    ContentType = result.ContentType,
                    Errors = result?.Errors,
                    IsSuccess = result?.IsSuccess ?? false,
                    OperationTime = sw.ElapsedMilliseconds
                });
            }
            catch (Exception ex)
            {
                Logger.LogError(ex, $"GetImageFileOperation Error, Type [{type}], id [{id}]");
            }

            return(new FileOperationResult <Image>("System Error"));
        }
Пример #6
0
 /// <summary>
 /// Gets the EntityTagHeaderValue ETag>.
 /// </summary>
 /// <remarks>This signature uses types that are AspNetCore-specific.</remarks>
 internal override ETag GetETag(EntityTagHeaderValue etagHeaderValue)
 {
     return(InternalRequest.GetETag <TEntity>(etagHeaderValue));
 }
        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.GetModel();
                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>
 /// 基于服务器虚拟路径路径的ResumePhysicalFileResult
 /// </summary>
 /// <param name="fileName">文件全路径</param>
 /// <param name="contentType">Content-Type</param>
 /// <param name="etag">ETag</param>
 public ResumeVirtualFileResult(string fileName, MediaTypeHeaderValue contentType, EntityTagHeaderValue etag = null) : base(fileName, contentType)
 {
     EntityTag             = etag;
     EnableRangeProcessing = true;
 }
Пример #9
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));
            }
        }
Пример #10
0
    protected override Task ExecuteAsync(HttpContext httpContext, string path, string contentType, DateTimeOffset?lastModified = null, EntityTagHeaderValue entityTag = null, bool enableRangeProcessing = false)
    {
        var webHostEnvironment = httpContext.RequestServices.GetRequiredService <IWebHostEnvironment>();

        httpContext.RequestServices = new ServiceCollection()
                                      .AddSingleton(webHostEnvironment)
                                      .AddTransient <IActionResultExecutor <VirtualFileResult>, VirtualFileResultExecutor>()
                                      .AddTransient <ILoggerFactory, NullLoggerFactory>()
                                      .BuildServiceProvider();

        var actionContext = new ActionContext(httpContext, new(), new());
        var result        = new VirtualFileResult(path, contentType)
        {
            LastModified          = lastModified,
            EntityTag             = entityTag,
            EnableRangeProcessing = enableRangeProcessing,
        };

        return(result.ExecuteResultAsync(actionContext));
    }
Пример #11
0
        protected override Task <HttpResponseMessage> CreateItemGetResponse(FileSystemInfo info, string localFilePath)
        {
            // Get current etag
            EntityTagHeaderValue currentEtag = GetCurrentEtag(info);

            // 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
            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 e)
            {
                // Could not read the file
                Tracer.TraceError(e);
                HttpResponseMessage errorResponse = Request.CreateErrorResponse(HttpStatusCode.NotFound, e);
                if (fileStream != null)
                {
                    fileStream.Close();
                }
                return(Task.FromResult(errorResponse));
            }
        }
Пример #12
0
 public async Task <FileOperationResult <Image> > ArtistSecondaryImage(Guid id, int imageId, int?width,
                                                                       int?height, EntityTagHeaderValue etag = null)
 {
     return(await GetImageFileOperation($"ArtistSecondaryThumbnail-{imageId}",
                                        data.Release.CacheRegionUrn(id),
                                        id,
                                        width,
                                        height,
                                        async() => { return await ArtistSecondaryImageAction(id, imageId, etag); },
                                        etag));
 }
Пример #13
0
        private Task <FileOperationResult <Image> > ReleaseSecondaryImageAction(Guid id, int imageId,
                                                                                EntityTagHeaderValue etag = null)
        {
            try
            {
                var release = GetRelease(id);
                if (release == null)
                {
                    return(Task.FromResult(new FileOperationResult <Image>(true,
                                                                           string.Format("Release Not Found [{0}]", id))));
                }
                byte[] imageBytes    = null;
                string artistFolder  = null;
                string releaseFolder = null;
                try
                {
                    // See if cover art file exists in release folder
                    artistFolder = release.Artist.ArtistFileFolder(Configuration, Configuration.LibraryFolder);
                    if (!Directory.Exists(artistFolder))
                    {
                        Logger.LogWarning($"Artist Folder [{artistFolder}], Not Found For Artist `{release.Artist}`");
                    }
                    else
                    {
                        releaseFolder = release.ReleaseFileFolder(artistFolder);
                        if (!Directory.Exists(releaseFolder))
                        {
                            Logger.LogWarning($"Release Folder [{releaseFolder}], Not Found For Release `{release}`");
                        }
                        else
                        {
                            var releaseSecondaryImages = ImageHelper
                                                         .FindImageTypeInDirectory(new DirectoryInfo(releaseFolder), ImageType.ReleaseSecondary)
                                                         .ToArray();
                            if (releaseSecondaryImages.Length >= imageId && releaseSecondaryImages[imageId] != null)
                            {
                                imageBytes = File.ReadAllBytes(releaseSecondaryImages[imageId].FullName);
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Logger.LogError(ex,
                                    $"Error Reading Release Folder [{releaseFolder}] Artist Folder [{artistFolder}] For Artist `{release.Artist.Id}`");
                }

                var image = new data.Image
                {
                    Bytes       = imageBytes,
                    CreatedDate = release.CreatedDate,
                    LastUpdated = release.LastUpdated
                };
                return(Task.FromResult(GenerateFileOperationResult(id, image, etag)));
            }
            catch (Exception ex)
            {
                Logger.LogError($"Error fetching Release Thumbnail [{id}]", ex);
            }

            return(Task.FromResult(new FileOperationResult <Image>(OperationMessages.ErrorOccured)));
        }
        /**************************************************************************/

        private void ProcessResponseHttpHeaders(MacroscopeHttpTwoClientResponse Response)
        {
            HttpResponseMessage ResponseMessage = Response.GetResponse();
            HttpResponseHeaders ResponseHeaders = ResponseMessage.Headers;
            HttpContentHeaders  ContentHeaders  = ResponseMessage.Content.Headers;

            /** Status Code ------------------------------------------------------ **/

            this.SetStatusCode(ResponseMessage.StatusCode);

            this.SetErrorCondition(ResponseMessage.ReasonPhrase);

            try
            {
                switch (this.GetStatusCode())
                {
                // 200 Range

                case HttpStatusCode.OK:
                    this.SetIsNotRedirect();
                    break;

                // 300 Range

                case HttpStatusCode.Moved:
                    this.SetErrorCondition(HttpStatusCode.Moved.ToString());
                    this.SetIsRedirect();
                    break;

                case HttpStatusCode.SeeOther:
                    this.SetErrorCondition(HttpStatusCode.SeeOther.ToString());
                    this.SetIsRedirect();
                    break;

                case HttpStatusCode.Found:
                    this.SetErrorCondition(HttpStatusCode.Redirect.ToString());
                    this.SetIsRedirect();
                    break;

                // 400 Range

                case HttpStatusCode.BadRequest:
                    this.SetErrorCondition(HttpStatusCode.BadRequest.ToString());
                    this.SetIsNotRedirect();
                    break;

                case HttpStatusCode.Unauthorized:
                    this.SetErrorCondition(HttpStatusCode.Unauthorized.ToString());
                    this.SetIsNotRedirect();
                    break;

                case HttpStatusCode.PaymentRequired:
                    this.SetErrorCondition(HttpStatusCode.PaymentRequired.ToString());
                    this.SetIsNotRedirect();
                    break;

                case HttpStatusCode.Forbidden:
                    this.SetErrorCondition(HttpStatusCode.Forbidden.ToString());
                    this.SetIsNotRedirect();
                    break;

                case HttpStatusCode.NotFound:
                    this.SetErrorCondition(HttpStatusCode.NotFound.ToString());
                    this.SetIsNotRedirect();
                    break;

                case HttpStatusCode.MethodNotAllowed:
                    this.SetErrorCondition(HttpStatusCode.MethodNotAllowed.ToString());
                    this.SetIsNotRedirect();
                    break;

                case HttpStatusCode.Gone:
                    this.SetErrorCondition(HttpStatusCode.Gone.ToString());
                    this.SetIsNotRedirect();
                    break;

                case HttpStatusCode.RequestUriTooLong:
                    this.SetErrorCondition(HttpStatusCode.RequestUriTooLong.ToString());
                    this.SetIsNotRedirect();
                    break;

                // Unhandled

                default:
                    throw new MacroscopeDocumentException("Unhandled HttpStatusCode Type");
                }
            }
            catch (MacroscopeDocumentException ex)
            {
                this.DebugMsg(string.Format("MacroscopeDocumentException: {0}", ex.Message));
            }

            /** Raw HTTP Headers ------------------------------------------------- **/

            this.SetHttpResponseStatusLine(Response: Response);

            this.SetHttpResponseHeaders(Response: Response);

            /** Server Information ----------------------------------------------- **/

            /*{
             * this.ServerName = ResponseHeaders.Server.First().ToString();
             * }*/

            /** PROBE HTTP HEADERS ----------------------------------------------- **/

            /** Server HTTP Header ----------------------------------------------- **/
            try
            {
                HttpHeaderValueCollection <ProductInfoHeaderValue> HeaderValue = ResponseHeaders.Server;
                if (HeaderValue != null)
                {
                    if (HeaderValue.FirstOrDefault() != null)
                    {
                        this.SetServerName(HeaderValue.FirstOrDefault().ToString());
                    }
                }
            }
            catch (Exception ex)
            {
                this.DebugMsg(ex.Message);
                FindHttpResponseHeaderCallback Callback = delegate(IEnumerable <string> HeaderValues)
                {
                    this.SetServerName(HeaderValues.First().ToString());
                    return(true);
                };
                if (!this.FindHttpResponseHeader(ResponseHeaders: ResponseHeaders, HeaderName: "server", Callback: Callback))
                {
                    this.FindHttpContentHeader(ContentHeaders: ContentHeaders, HeaderName: "server", Callback: Callback);
                }
            }

            this.DebugMsg(string.Format("this.ServerName: {0}", this.ServerName));

            /** Content-Type HTTP Header ----------------------------------------- **/
            try
            {
                MediaTypeHeaderValue HeaderValue = ContentHeaders.ContentType;
                if (HeaderValue != null)
                {
                    this.DebugMsg(string.Format("HeaderValue: {0}", HeaderValue));
                    this.MimeType = HeaderValue.MediaType;
                    if (HeaderValue.CharSet != null)
                    {
                        this.SetCharacterSet(HeaderValue.CharSet);
                        // TODO: Implement character set probing
                        this.SetCharacterEncoding(NewEncoding: new UTF8Encoding());
                    }
                }
            }
            catch (Exception ex)
            {
                this.DebugMsg(string.Format("MediaType Exception: {0}", ex.Message));
                this.MimeType = MacroscopeConstants.DefaultMimeType;
            }

            this.DebugMsg(string.Format("this.MimeType: {0}", this.MimeType));

            /** Content-Length HTTP Header --------------------------------------- **/
            try
            {
                long?HeaderValue = null;
                if (ContentHeaders.Contains("Content-Length"))
                {
                    HeaderValue = ContentHeaders.ContentLength;
                }
                if (HeaderValue != null)
                {
                    this.ContentLength = HeaderValue;
                }
                else
                {
                    this.ContentLength = 0;
                }
            }
            catch (Exception ex)
            {
                this.DebugMsg(ex.Message);
                this.SetContentLength(Length: 0);
                FindHttpResponseHeaderCallback Callback = delegate(IEnumerable <string> HeaderValues)
                {
                    this.SetContentLength(Length: long.Parse(HeaderValues.FirstOrDefault()));
                    return(true);
                };
                if (!this.FindHttpResponseHeader(ResponseHeaders: ResponseHeaders, HeaderName: "content-length", Callback: Callback))
                {
                    this.FindHttpContentHeader(ContentHeaders: ContentHeaders, HeaderName: "content-length", Callback: Callback);
                }
            }

            this.DebugMsg(string.Format("this.GetContentLength(): {0}", this.GetContentLength()));

            /** Content-Encoding HTTP Header ------------------------------------- **/
            try
            {
                ICollection <string> HeaderValue = ContentHeaders.ContentEncoding;
                if (HeaderValue != null)
                {
                    this.ContentEncoding = HeaderValue.FirstOrDefault();
                }
            }
            catch (Exception ex)
            {
                this.DebugMsg(ex.Message);
                FindHttpResponseHeaderCallback Callback = delegate(IEnumerable <string> HeaderValues)
                {
                    this.ContentEncoding = HeaderValues.FirstOrDefault();
                    return(true);
                };
                if (!this.FindHttpResponseHeader(ResponseHeaders: ResponseHeaders, HeaderName: "content-encoding", Callback: Callback))
                {
                    this.FindHttpContentHeader(ContentHeaders: ContentHeaders, HeaderName: "content-encoding", Callback: Callback);
                }
            }

            if (string.IsNullOrEmpty(this.CompressionMethod) && (!string.IsNullOrEmpty(this.ContentEncoding)))
            {
                this.IsCompressed      = true;
                this.CompressionMethod = this.ContentEncoding;
            }

            this.DebugMsg(string.Format("this.ContentEncoding: {0}", this.ContentEncoding));
            this.DebugMsg(string.Format("this.CompressionMethod: {0}", this.CompressionMethod));

            /** Date HTTP Header ------------------------------------------------- **/
            try
            {
                DateTimeOffset?HeaderValue = ResponseHeaders.Date;
                if (HeaderValue != null)
                {
                    this.DateServer = MacroscopeDateTools.ParseHttpDate(DateString: HeaderValue.ToString());
                }
            }
            catch (Exception ex)
            {
                this.DebugMsg(ex.Message);
                this.DateServer = new DateTime();
                FindHttpResponseHeaderCallback Callback = delegate(IEnumerable <string> HeaderValues)
                {
                    this.DateServer = MacroscopeDateTools.ParseHttpDate(DateString: HeaderValues.First().ToString());
                    return(true);
                };
                if (!this.FindHttpResponseHeader(ResponseHeaders: ResponseHeaders, HeaderName: "date", Callback: Callback))
                {
                    this.FindHttpContentHeader(ContentHeaders: ContentHeaders, HeaderName: "date", Callback: Callback);
                }
            }

            this.DebugMsg(string.Format("this.DateServer: {0}", this.DateServer));

            /** Last-Modified HTTP Header ---------------------------------------- **/
            try
            {
                DateTimeOffset?HeaderValue = ContentHeaders.LastModified;
                if (HeaderValue != null)
                {
                    this.DateModified = MacroscopeDateTools.ParseHttpDate(DateString: HeaderValue.ToString());
                }
            }
            catch (Exception ex)
            {
                this.DebugMsg(ex.Message);
                this.DateModified = new DateTime();
                FindHttpResponseHeaderCallback Callback = delegate(IEnumerable <string> HeaderValues)
                {
                    this.DateModified = MacroscopeDateTools.ParseHttpDate(DateString: HeaderValues.First().ToString());
                    return(true);
                };
                if (!this.FindHttpResponseHeader(ResponseHeaders: ResponseHeaders, HeaderName: "last-modified", Callback: Callback))
                {
                    this.FindHttpContentHeader(ContentHeaders: ContentHeaders, HeaderName: "last-modified", Callback: Callback);
                }
            }

            this.DebugMsg(string.Format("this.DateModified: {0}", this.DateModified));

            /** Expires HTTP Header ---------------------------------------------- **/
            try
            {
                DateTimeOffset?HeaderValue = ContentHeaders.Expires;
                if (HeaderValue != null)
                {
                    this.DateExpires = MacroscopeDateTools.ParseHttpDate(DateString: HeaderValue.ToString());
                }
            }
            catch (Exception ex)
            {
                this.DebugMsg(ex.Message);
                this.DateExpires = new DateTime();
                FindHttpResponseHeaderCallback Callback = delegate(IEnumerable <string> HeaderValues)
                {
                    this.DateExpires = MacroscopeDateTools.ParseHttpDate(DateString: HeaderValues.First().ToString());
                    return(true);
                };
                if (!this.FindHttpResponseHeader(ResponseHeaders: ResponseHeaders, HeaderName: "expires", Callback: Callback))
                {
                    this.FindHttpContentHeader(ContentHeaders: ContentHeaders, HeaderName: "expires", Callback: Callback);
                }
            }

            this.DebugMsg(string.Format("this.DateExpires: {0}", this.DateExpires));

            /** HTST Policy HTTP Header ------------------------------------------ **/
            // https://www.owasp.org/index.php/HTTP_Strict_Transport_Security_Cheat_Sheet
            // Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
            {
                FindHttpResponseHeaderCallback Callback = delegate(IEnumerable <string> HeaderValues)
                {
                    this.HypertextStrictTransportPolicy = true;
                    return(true);
                };
                if (!this.FindHttpResponseHeader(ResponseHeaders: ResponseHeaders, HeaderName: "strict-transport-security", Callback: Callback))
                {
                    this.FindHttpContentHeader(ContentHeaders: ContentHeaders, HeaderName: "strict-transport-security", Callback: Callback);
                }
            }

            this.DebugMsg(string.Format("this.HypertextStrictTransportPolicy: {0}", this.HypertextStrictTransportPolicy));

            /** Location (Redirect) HTTP Header ---------------------------------- **/
            try
            {
                Uri HeaderValue = ResponseHeaders.Location;
                if (HeaderValue != null)
                {
                    this.SetUrlRedirectTo(Url: HeaderValue.ToString());
                }
            }
            catch (Exception ex)
            {
                this.DebugMsg(ex.Message);
                FindHttpResponseHeaderCallback Callback = delegate(IEnumerable <string> HeaderValues)
                {
                    this.SetUrlRedirectTo(Url: HeaderValues.FirstOrDefault().ToString());
                    return(true);
                };
                if (!this.FindHttpResponseHeader(ResponseHeaders: ResponseHeaders, HeaderName: "location", Callback: Callback))
                {
                    this.FindHttpContentHeader(ContentHeaders: ContentHeaders, HeaderName: "location", Callback: Callback);
                }
            }

            this.DebugMsg(string.Format("this.GetIsRedirect(): {0}", this.GetIsRedirect()));
            this.DebugMsg(string.Format("this.GetUrlRedirectTo(): {0}", this.GetUrlRedirectTo()));

            /** Link HTTP Headers ------------------------------------------------ **/
            {
                FindHttpResponseHeaderCallback Callback = delegate(IEnumerable <string> HeaderValues)
                {
                    foreach (string HeaderValue in HeaderValues)
                    {
                        this.DebugMsg(string.Format("HeaderValue: {0}", HeaderValue));
                        this.ProcessHttpLinkHeader(HttpLinkHeader: HeaderValue);
                    }
                    return(true);
                };
                if (!this.FindHttpResponseHeader(ResponseHeaders: ResponseHeaders, HeaderName: "link", Callback: Callback))
                {
                    this.FindHttpContentHeader(ContentHeaders: ContentHeaders, HeaderName: "link", Callback: Callback);
                }
            }

            /** ETag HTTP Header ------------------------------------------------- **/
            try
            {
                EntityTagHeaderValue HeaderValue = ResponseHeaders.ETag;
                if (HeaderValue != null)
                {
                    string ETagValue = HeaderValue.Tag;
                    if (!string.IsNullOrEmpty(ETagValue))
                    {
                        this.SetEtag(HeaderValue.Tag);
                    }
                }
            }
            catch (Exception ex)
            {
                this.DebugMsg(ex.Message);
                FindHttpResponseHeaderCallback Callback = delegate(IEnumerable <string> HeaderValues)
                {
                    string HeaderValue = HeaderValues.FirstOrDefault();
                    if (HeaderValue != null)
                    {
                        if (!string.IsNullOrEmpty(HeaderValue))
                        {
                            this.SetEtag(HeaderValue);
                        }
                    }
                    return(true);
                };
                if (!this.FindHttpResponseHeader(ResponseHeaders: ResponseHeaders, HeaderName: "etag", Callback: Callback))
                {
                    this.FindHttpContentHeader(ContentHeaders: ContentHeaders, HeaderName: "etag", Callback: Callback);
                }
            }

            this.DebugMsg(string.Format("this.Etag: {0}", this.Etag));

            /** WWW-AUTHENTICATE HTTP Header ------------------------------------- **/
            // Reference: http://httpbin.org/basic-auth/user/passwd
            try
            {
                HttpHeaderValueCollection <AuthenticationHeaderValue> HeaderValue = ResponseHeaders.WwwAuthenticate;
                if (HeaderValue != null)
                {
                    string Scheme = null;
                    string Realm  = null;
                    foreach (AuthenticationHeaderValue AuthenticationValue in HeaderValue)
                    {
                        Scheme = AuthenticationValue.Scheme;
                        string Parameter = AuthenticationValue.Parameter;
                        Match  Matched   = Regex.Match(Parameter, "^[^\"]+\"([^\"]+)\"");
                        if (Matched.Success)
                        {
                            Realm = Matched.Groups[1].Value;
                        }
                    }
                    if (!string.IsNullOrEmpty(Scheme) && !string.IsNullOrEmpty(Realm))
                    {
                        if (Scheme.ToLower() == "basic")
                        {
                            this.SetAuthenticationType(MacroscopeConstants.AuthenticationType.BASIC);
                            this.SetAuthenticationRealm(Realm);
                        }
                        else
                        {
                            this.SetAuthenticationType(MacroscopeConstants.AuthenticationType.UNSUPPORTED);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                this.DebugMsg(ex.Message);
            }
            this.DebugMsg(string.Format("WwwAuthenticate: \"{0}\", Realm: \"{1}\"", this.GetAuthenticationType(), this.GetAuthenticationRealm()));

            /** Process Dates ---------------------------------------------------- **/
            {
                if (this.DateServer.Date == new DateTime().Date)
                {
                    this.DateServer = DateTime.UtcNow;
                }
                if (this.DateModified.Date == new DateTime().Date)
                {
                    this.DateModified = this.DateServer;
                }
            }

            /** Process MIME Type ------------------------------------------------ **/
            {
                Regex reIsHtml       = new Regex(@"^(text/html|application/xhtml+xml)", RegexOptions.IgnoreCase);
                Regex reIsCss        = new Regex(@"^text/css", RegexOptions.IgnoreCase);
                Regex reIsJavascript = new Regex(@"^(application/javascript|text/javascript)", RegexOptions.IgnoreCase);
                Regex reIsImage      = new Regex(@"^image/(gif|png|jpeg|bmp|webp|vnd.microsoft.icon|x-icon)", RegexOptions.IgnoreCase);
                Regex reIsPdf        = new Regex(@"^application/pdf", RegexOptions.IgnoreCase);
                Regex reIsAudio      = new Regex(@"^audio/[a-z0-9]+", RegexOptions.IgnoreCase);
                Regex reIsVideo      = new Regex(@"^video/[a-z0-9]+", RegexOptions.IgnoreCase);
                Regex reIsXml        = new Regex(@"^(application|text)/(atom\+xml|xml)", RegexOptions.IgnoreCase);
                Regex reIsText       = new Regex(@"^(text)/(plain)", RegexOptions.IgnoreCase);

                if (reIsHtml.IsMatch(this.MimeType))
                {
                    this.SetDocumentType(Type: MacroscopeConstants.DocumentType.HTML);
                }
                else
                if (reIsCss.IsMatch(this.MimeType))
                {
                    this.SetDocumentType(Type: MacroscopeConstants.DocumentType.CSS);
                }
                else
                if (reIsJavascript.IsMatch(this.MimeType))
                {
                    this.SetDocumentType(Type: MacroscopeConstants.DocumentType.JAVASCRIPT);
                }
                else
                if (reIsImage.IsMatch(this.MimeType))
                {
                    this.SetDocumentType(Type: MacroscopeConstants.DocumentType.IMAGE);
                }
                else
                if (reIsPdf.IsMatch(this.MimeType))
                {
                    this.SetDocumentType(Type: MacroscopeConstants.DocumentType.PDF);
                }
                else
                if (reIsAudio.IsMatch(this.MimeType))
                {
                    this.SetDocumentType(Type: MacroscopeConstants.DocumentType.AUDIO);
                }
                else
                if (reIsVideo.IsMatch(this.MimeType))
                {
                    this.SetDocumentType(Type: MacroscopeConstants.DocumentType.VIDEO);
                }
                else
                if (reIsXml.IsMatch(this.MimeType))
                {
                    this.SetDocumentType(Type: MacroscopeConstants.DocumentType.XML);
                }
                else
                if (reIsText.IsMatch(this.MimeType))
                {
                    this.SetDocumentType(Type: MacroscopeConstants.DocumentType.TEXT);
                }
                else
                {
                    this.SetDocumentType(Type: MacroscopeConstants.DocumentType.BINARY);
                }
            }

            /** Process Cookies -------------------------------------------------- **/
            // https://stackoverflow.com/questions/29224734/how-to-read-cookies-from-httpresponsemessage
            {
                try
                {
                    CookieContainer  CookieMonster = MacroscopeHttpTwoClient.GetCookieMonster();
                    CookieCollection Biscuits      = CookieMonster.GetCookies(uri: this.GetUri());
                    this.AddCookies(Cookies: Biscuits);
                    this.DebugMsg("cookies");


//          CookieContainer CookieTin = MacroscopeHttpTwoClient.GetCookieMonster();
//          string LimpBizkit = tin.GetCookieHeader( uri: Request.RequestUri );
                }
                catch (Exception ex)
                {
                    this.DebugMsg(ex.Message);
                }
            }

            return;
        }
        /// <summary>
        /// Gets the <see cref="ETag{TEntity}"/> from the given request.
        /// </summary>
        /// <param name="request">The request.</param>
        /// <param name="entityTagHeaderValue">The entity tag header value.</param>
        /// <returns>The parsed <see cref="ETag{TEntity}"/>.</returns>
        public static ETag <TEntity> GetETag <TEntity>(this HttpRequestMessage request, EntityTagHeaderValue entityTagHeaderValue)
        {
            ETag etag = request.GetETag(entityTagHeaderValue);

            return(etag != null
                ? new ETag <TEntity>
            {
                ConcurrencyProperties = etag.ConcurrencyProperties,
                IsWellFormed = etag.IsWellFormed,
                IsAny = etag.IsAny,
            }
                : null);
        }
 /// <summary>
 /// 基于服务器虚拟路径路径的ResumePhysicalFileResult
 /// </summary>
 /// <param name="fileName">文件全路径</param>
 /// <param name="contentType">Content-Type</param>
 /// <param name="etag">ETag</param>
 public ResumeVirtualFileResult(string fileName, string contentType, string etag = null) : this(fileName, MediaTypeHeaderValue.Parse(contentType), !string.IsNullOrEmpty(etag) ? EntityTagHeaderValue.Parse(etag) : null)
 {
 }
        public virtual async Task RunIntegrationTest()
        {
            string dir        = Guid.NewGuid().ToString("N");
            string dirAddress = BaseAddress + _segmentDelimiter + dir;
            string dirAddressWithTerminatingSlash = dirAddress + _segmentDelimiter;

            // The %2520 is there to test that we can accept those characters. Here, %2520 is the URL encoded form,
            // and the actual file name has %20 (and not a space character!)
            string file        = Guid.NewGuid().ToString("N") + "%2520" + ".txt";
            string fileAddress = dirAddressWithTerminatingSlash + file;
            string fileAddressWithTerminatingSlash = fileAddress + _segmentDelimiter;

            string query = "?foo=bar";
            string baseAddressWithQuery = BaseAddress + _segmentDelimiter + query;
            string dirAddressWithQuery  = dirAddressWithTerminatingSlash + query;
            string fileAddressWithQuery = fileAddress + query;

            string deploymentFileAddress       = null;
            string customDeploymentFileAddress = null;

            if (DeploymentClient != null)
            {
                deploymentFileAddress       = string.Format("{0}{1}site{1}wwwroot{1}{2}{1}{3}", DeploymentBaseAddress, _segmentDelimiter, dir, file);
                customDeploymentFileAddress = string.Format("{0}{1}site{1}wwwroot{1}test{1}{2}{1}{3}", DeploymentBaseAddress, _segmentDelimiter, dir, file);
            }

            TestTracer.Trace("Starting RunIntegrationTest");
            TestTracer.Trace("Dir - {0}", dirAddress);
            TestTracer.Trace("File - {0}", fileAddress);
            TestTracer.Trace("DeploymentFileAddress - {0}", deploymentFileAddress);

            HttpResponseMessage response;

            // Check not found file responses
            TestTracer.Trace("==== Check not found file responses");
            response = await HttpGetAsync(dirAddress);

            Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);

            response = await HttpGetAsync(dirAddressWithTerminatingSlash);

            Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);

            response = await HttpGetAsync(fileAddress);

            Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);

            response = await HttpGetAsync(fileAddressWithTerminatingSlash);

            Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);

            // Check create file results in 201 response with etag
            TestTracer.Trace("==== Check create file results in 201 response with etag");
            response = await HttpPutAsync(fileAddress, CreateUploadContent(_fileContent0));
            await VerifyDeploymentAsync(deploymentFileAddress, HttpStatusCode.OK, _fileContent0);

            Assert.Equal(HttpStatusCode.Created, response.StatusCode);
            EntityTagHeaderValue originalEtag = response.Headers.ETag;

            Assert.NotNull(originalEtag);

            DateTimeOffset?lastModified = response.Content.Headers.LastModified;

            if (!_isScmEditorTest)
            {
                Assert.NotNull(lastModified);
            }

            // Check query string
            TestTracer.Trace("==== Check handle query string");
            response = await HttpGetAsync(baseAddressWithQuery);

            Assert.Equal(HttpStatusCode.OK, response.StatusCode);
            response = await HttpGetAsync(dirAddressWithQuery);

            Assert.Equal(HttpStatusCode.OK, response.StatusCode);
            response = await HttpGetAsync(fileAddressWithQuery);

            Assert.Equal(HttpStatusCode.OK, response.StatusCode);

            // Check that we get a 200 (OK) on created file with the correct etag
            TestTracer.Trace("==== Check that we get a 200 (OK) on created file with the correct etag");
            response = await HttpGetAsync(fileAddress);

            Assert.Equal(HttpStatusCode.OK, response.StatusCode);
            Assert.Equal(originalEtag, response.Headers.ETag);
            Assert.Equal(lastModified, response.Content.Headers.LastModified);
            Assert.Equal(_fileMediaType, response.Content.Headers.ContentType);

            // Check that we get a 200 (OK) on created file using HEAD with the correct etag
            TestTracer.Trace("==== Check that we get a 200 (OK) on created file using HEAD with the correct etag");
            using (HttpRequestMessage headReq = new HttpRequestMessage())
            {
                headReq.Method     = HttpMethod.Head;
                headReq.RequestUri = new Uri(fileAddress);
                response           = await Client.SendAsync(headReq);

                Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                Assert.Equal(originalEtag, response.Headers.ETag);
                Assert.Equal(_fileMediaType, response.Content.Headers.ContentType);
            }

            // Check that we get a 304 (Not Modified) response if matching If-None-Match
            TestTracer.Trace("==== Check that we get a 304 (Not Modified) response if matching If-None-Match");
            using (HttpRequestMessage ifNoneMatchReq = new HttpRequestMessage())
            {
                ifNoneMatchReq.RequestUri = new Uri(fileAddress);
                ifNoneMatchReq.Headers.IfNoneMatch.Add(originalEtag);
                response = await HttpSendAsync(ifNoneMatchReq);

                Assert.Equal(HttpStatusCode.NotModified, response.StatusCode);
                Assert.Equal(originalEtag, response.Headers.ETag);
            }

            // Check that we get a 200 (OK) response if not matching If-None-Match
            TestTracer.Trace("==== Check that we get a 200 (OK) response if not matching If-None-Match");
            using (HttpRequestMessage ifNoneMatchReqBadEtag = new HttpRequestMessage())
            {
                ifNoneMatchReqBadEtag.RequestUri = new Uri(fileAddress);
                ifNoneMatchReqBadEtag.Headers.IfNoneMatch.Add(new EntityTagHeaderValue("\"NotMatching\""));
                response = await HttpSendAsync(ifNoneMatchReqBadEtag);

                Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                Assert.Equal(originalEtag, response.Headers.ETag);
            }

            // Check that If-Range request with range returns 206 (Partial Content)
            TestTracer.Trace("==== Check that If-Range request with range returns 206 (Partial Content)");
            using (HttpRequestMessage ifRangeReq = new HttpRequestMessage())
            {
                ifRangeReq.RequestUri      = new Uri(fileAddress);
                ifRangeReq.Headers.IfRange = new RangeConditionHeaderValue(originalEtag);
                ifRangeReq.Headers.Range   = new RangeHeaderValue(0, 0)
                {
                    Unit = "bytes"
                };
                response = await HttpSendAsync(ifRangeReq);

                Assert.Equal(HttpStatusCode.PartialContent, response.StatusCode);
                Assert.Equal(originalEtag, response.Headers.ETag);
                Assert.Equal(1, response.Content.Headers.ContentLength);
                Assert.Equal(new ContentRangeHeaderValue(0, 0, _fileContent0.Length), response.Content.Headers.ContentRange);
            }

            // Check that If-Range request with no range returns 200 (OK)
            TestTracer.Trace("==== Check that If-Range request with no range returns 200 (OK)");
            using (HttpRequestMessage ifRangeReqNoRange = new HttpRequestMessage())
            {
                ifRangeReqNoRange.RequestUri      = new Uri(fileAddress);
                ifRangeReqNoRange.Headers.IfRange = new RangeConditionHeaderValue(originalEtag);
                response = await HttpSendAsync(ifRangeReqNoRange);

                Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                Assert.Equal(originalEtag, response.Headers.ETag);
            }

            // Check that If-Range request with bad range returns 416 (Requested Range Not Satisfiable)
            // including a Content-Range header
            TestTracer.Trace("==== Check that If-Range request with bad range returns 416 (Requested Range Not Satisfiable)");
            using (HttpRequestMessage ifRangeReqBadRange = new HttpRequestMessage())
            {
                ifRangeReqBadRange.RequestUri      = new Uri(fileAddress);
                ifRangeReqBadRange.Headers.IfRange = new RangeConditionHeaderValue(originalEtag);
                ifRangeReqBadRange.Headers.Range   = new RangeHeaderValue(100, 100)
                {
                    Unit = "bytes"
                };
                response = await HttpSendAsync(ifRangeReqBadRange);

                Assert.Equal(HttpStatusCode.RequestedRangeNotSatisfiable, response.StatusCode);
                Assert.Equal(_fileContentRange, response.Content.Headers.ContentRange);
            }

            // Check that we get a root directory view
            TestTracer.Trace("==== Check that we get a root directory view");
            response = await HttpGetAsync(BaseAddress);

            Assert.Equal(_dirMediaType, response.Content.Headers.ContentType);

            // Check that we get a directory view from folder
            TestTracer.Trace("==== Check that we get a directory view from folder");
            response = await HttpGetAsync(dirAddress);

            Assert.Equal(_dirMediaType, response.Content.Headers.ContentType);

            // Check various redirects between files and folders
            HttpClientHandler redirectHandler = HttpClientHelper.CreateClientHandler(BaseAddress, KuduClient.Credentials);

            redirectHandler.AllowAutoRedirect = false;
            using (HttpClient redirectClient = HttpClientHelper.CreateClient(BaseAddress, KuduClient.Credentials, redirectHandler))
            {
                // Ensure that requests to root without slash is redirected to one with slash
                TestTracer.Trace("==== Ensure that requests to root without slash is redirected to one with slash");
                response = await HttpGetAsync(BaseAddress, redirectClient);

                Assert.Equal(HttpStatusCode.TemporaryRedirect, response.StatusCode);
                Assert.Equal(BaseAddress + _segmentDelimiter, response.Headers.Location.AbsoluteUri);

                // Ensure that requests to directory without slash is redirected to one with slash
                TestTracer.Trace("==== Ensure that requests to directory without slash is redirected to one with slash");
                response = await HttpGetAsync(dirAddress, redirectClient);

                Assert.Equal(HttpStatusCode.TemporaryRedirect, response.StatusCode);
                Assert.Equal(dirAddressWithTerminatingSlash, response.Headers.Location.AbsoluteUri);

                // Ensure that requests to file with slash is redirected to one without slash
                TestTracer.Trace("==== Ensure that requests to file with slash is redirected to one without slash");
                response = await HttpGetAsync(fileAddressWithTerminatingSlash, redirectClient);

                Assert.Equal(HttpStatusCode.TemporaryRedirect, response.StatusCode);
                Assert.Equal(fileAddress, response.Headers.Location.AbsoluteUri);
            }

            // Check that 2nd create attempt fails
            TestTracer.Trace("==== Check that 2nd create attempt fails");
            response = await HttpPutAsync(fileAddress, CreateUploadContent(_fileContent0));

            Assert.Equal(HttpStatusCode.PreconditionFailed, response.StatusCode);
            Assert.Equal(originalEtag, response.Headers.ETag);

            // Check that we can't update a directory
            TestTracer.Trace("==== Check that we can't update a directory");
            response = await HttpPutAsync(dirAddress, CreateUploadContent(_fileContent0));

            Assert.Equal(HttpStatusCode.Conflict, response.StatusCode);

            // Check that we can't delete a non-empty directory
            TestTracer.Trace("==== Check that we can't delete a non-empty directory");
            response = await HttpDeleteAsync(dirAddress);

            Assert.Equal(HttpStatusCode.Conflict, response.StatusCode);

            EntityTagHeaderValue updatedEtag;

            if (_testConflictingUpdates)
            {
                // Update file with first edit based on original etag
                TestTracer.Trace("==== Update file with first edit based on original etag");
                using (HttpRequestMessage update1 = new HttpRequestMessage())
                {
                    update1.Method     = HttpMethod.Put;
                    update1.RequestUri = new Uri(fileAddress);
                    update1.Headers.IfMatch.Add(originalEtag);
                    update1.Content = CreateUploadContent(_fileContent1);

                    response = await HttpSendAsync(update1);
                    await VerifyDeploymentAsync(deploymentFileAddress, HttpStatusCode.OK, _fileContent1);

                    Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
                    Assert.NotNull(response.Headers.ETag);
                    Assert.NotEqual(originalEtag, response.Headers.ETag);
                    updatedEtag = response.Headers.ETag;
                }

                // Update file with second edit based on original etag (non-conflicting merge)
                TestTracer.Trace("==== Update file with second edit based on original etag (non-conflicting merge)");
                using (HttpRequestMessage update2 = new HttpRequestMessage())
                {
                    update2.Method     = HttpMethod.Put;
                    update2.RequestUri = new Uri(fileAddress);
                    update2.Headers.IfMatch.Add(originalEtag);
                    update2.Content = CreateUploadContent(_fileContent2);

                    response = await HttpSendAsync(update2);
                    await VerifyDeploymentAsync(deploymentFileAddress, HttpStatusCode.OK, _fileContent3);

                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                    Assert.NotNull(response.Headers.ETag);
                    Assert.NotEqual(updatedEtag, response.Headers.ETag);
                    Assert.Equal(_fileMediaType, response.Content.Headers.ContentType);
                    updatedEtag = response.Headers.ETag;
                }

                // Update file with third edit based on original etag (non-conflicting merge)
                TestTracer.Trace("==== Update file with third edit based on original etag (non-conflicting merge)");
                using (HttpRequestMessage update3 = new HttpRequestMessage())
                {
                    update3.Method     = HttpMethod.Put;
                    update3.RequestUri = new Uri(fileAddress);
                    update3.Headers.IfMatch.Add(originalEtag);
                    update3.Content = CreateUploadContent(_fileContent3);

                    response = await HttpSendAsync(update3);
                    await VerifyDeploymentAsync(deploymentFileAddress, HttpStatusCode.OK, _fileContent3);

                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                    Assert.NotNull(response.Headers.ETag);
                    Assert.Equal(updatedEtag, response.Headers.ETag);
                    Assert.Equal(_fileMediaType, response.Content.Headers.ContentType);
                    updatedEtag = response.Headers.ETag;
                }

                // Update file with forth edit based on original etag (conflicting)
                TestTracer.Trace("==== Update file with forth edit based on original etag (conflicting)");
                using (HttpRequestMessage update4 = new HttpRequestMessage())
                {
                    update4.Method     = HttpMethod.Put;
                    update4.RequestUri = new Uri(fileAddress);
                    update4.Headers.IfMatch.Add(originalEtag);
                    update4.Content = CreateUploadContent(_fileContent4);

                    response = await HttpSendAsync(update4);
                    await VerifyDeploymentAsync(deploymentFileAddress, HttpStatusCode.OK, _fileContent3);

                    Assert.Equal(HttpStatusCode.Conflict, response.StatusCode);
                    Assert.Equal(_conflictMediaType, response.Content.Headers.ContentType);
                    Assert.Null(response.Headers.ETag);
                    string content = await response.Content.ReadAsStringAsync();

                    Assert.True(Regex.IsMatch(content, _conflict));
                }

                // Update file with fifth edit based on invalid etag
                TestTracer.Trace("==== Update file with fifth edit based on invalid etag");
                using (HttpRequestMessage update5 = new HttpRequestMessage())
                {
                    update5.Method     = HttpMethod.Put;
                    update5.RequestUri = new Uri(fileAddress);
                    update5.Headers.IfMatch.Add(new EntityTagHeaderValue("\"invalidetag\""));
                    update5.Content = CreateUploadContent(_fileContent1);

                    response = await HttpSendAsync(update5);
                    await VerifyDeploymentAsync(deploymentFileAddress, HttpStatusCode.OK, _fileContent3);

                    Assert.Equal(HttpStatusCode.PreconditionFailed, response.StatusCode);
                    Assert.Equal(updatedEtag, response.Headers.ETag);
                }

                // Check that update with wildcard etag succeeds
                TestTracer.Trace("==== Check that update with wildcard etag succeeds");
                using (HttpRequestMessage update6 = new HttpRequestMessage())
                {
                    update6.Method     = HttpMethod.Put;
                    update6.RequestUri = new Uri(fileAddress);
                    update6.Headers.IfMatch.Add(EntityTagHeaderValue.Any);
                    update6.Content = CreateUploadContent(_fileContent1);

                    response = await HttpSendAsync(update6);
                    await VerifyDeploymentAsync(deploymentFileAddress, HttpStatusCode.OK, _fileContent1);

                    Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
                    Assert.NotNull(response.Headers.ETag);
                    Assert.NotEqual(originalEtag, response.Headers.ETag);
                    updatedEtag = response.Headers.ETag;
                }

                TestTracer.Trace("==== Check that concurrent updates work");
                List <Task <HttpResponseMessage> > concurrentUpdates = new List <Task <HttpResponseMessage> >();
                for (int cnt = 0; cnt < 16; cnt++)
                {
                    HttpRequestMessage concurrentRequest = new HttpRequestMessage()
                    {
                        Method     = HttpMethod.Put,
                        RequestUri = new Uri(fileAddress + "?nodeploy"),
                        Content    = CreateUploadContent(_fileContent2)
                    };

                    concurrentRequest.Headers.IfMatch.Add(EntityTagHeaderValue.Any);
                    concurrentUpdates.Add(HttpSendAsync(concurrentRequest));
                }
                await Task.WhenAll(concurrentUpdates);

                IEnumerable <HttpResponseMessage> concurrentResponses = concurrentUpdates.Select(update => update.Result);
                foreach (HttpResponseMessage concurrentResponse in concurrentResponses)
                {
                    // NoContent is the expected success case.
                    // PreConditionFailed can happen due to race condition between LibGit2Sharp cleanup and lock acquisition and release.
                    // In PreConditionFailed case, nothing is written and the repo isn't updated or corrupted.
                    // Conflict can happen due to multiple threads pass LibGit2Sharp cleanup step (one after another) and race to write to the same file.
                    // This is an edge case for a legacy feature
                    Assert.True(
                        concurrentResponse.StatusCode == HttpStatusCode.NoContent ||
                        concurrentResponse.StatusCode == HttpStatusCode.PreconditionFailed ||
                        concurrentResponse.StatusCode == HttpStatusCode.Conflict,
                        $"Status code expected to be either {HttpStatusCode.NoContent}, {HttpStatusCode.PreconditionFailed} or {HttpStatusCode.Conflict} but got {concurrentResponse.StatusCode}");
                }

                TestTracer.Trace("==== Check that 'nodeploy' doesn't deploy and that the old content remains.");
                using (HttpRequestMessage request = new HttpRequestMessage())
                {
                    request.Method     = HttpMethod.Put;
                    request.RequestUri = new Uri(fileAddress + "?nodeploy");
                    request.Headers.IfMatch.Add(EntityTagHeaderValue.Any);
                    request.Content = CreateUploadContent(_fileContent2);

                    response = await HttpSendAsync(request);
                    await VerifyDeploymentAsync(deploymentFileAddress, HttpStatusCode.OK, _fileContent1);

                    Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
                    Assert.NotNull(response.Headers.ETag);
                    Assert.NotEqual(originalEtag, response.Headers.ETag);
                    updatedEtag = response.Headers.ETag;
                }

                TestTracer.Trace("==== Check passing custom commit message.");
                using (HttpRequestMessage request = new HttpRequestMessage())
                {
                    request.Method     = HttpMethod.Put;
                    request.RequestUri = new Uri(fileAddress + "?message=helloworld");
                    request.Headers.IfMatch.Add(EntityTagHeaderValue.Any);
                    request.Content = CreateUploadContent(_fileContent3);

                    response = await HttpSendAsync(request);
                    await VerifyDeploymentAsync(deploymentFileAddress, HttpStatusCode.OK, _fileContent3);

                    Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
                    Assert.NotNull(response.Headers.ETag);
                    Assert.NotEqual(originalEtag, response.Headers.ETag);
                    updatedEtag = response.Headers.ETag;
                }

                TestTracer.Trace("==== Check that custom deployment script works");
                using (HttpRequestMessage update7 = new HttpRequestMessage())
                {
                    // Upload custom deployment scripts
                    TestTracer.Trace("==== Upload custom deployment scripts");
                    updatedEtag = await UploadCustomDeploymentScripts();

                    // Upload content and validate that it gets deployed
                    TestTracer.Trace("==== Upload content and validate that it gets deployed");
                    update7.Method     = HttpMethod.Put;
                    update7.RequestUri = new Uri(fileAddress);
                    update7.Headers.IfMatch.Add(updatedEtag);
                    update7.Content = CreateUploadContent(_fileContent2);

                    response = await HttpSendAsync(update7);
                    await VerifyDeploymentAsync(customDeploymentFileAddress, HttpStatusCode.OK, _fileContent2);

                    Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
                    Assert.NotNull(response.Headers.ETag);
                    Assert.NotEqual(originalEtag, response.Headers.ETag);
                    updatedEtag = response.Headers.ETag;

                    // Remove custom deployment scripts
                    TestTracer.Trace("==== Remove custom deployment scripts");
                    updatedEtag = await RemoveCustomDeploymentScripts();
                }

                // Check that delete with invalid etag fails
                TestTracer.Trace("==== Check that delete with invalid etag fails");
                using (HttpRequestMessage deleteRequest = new HttpRequestMessage())
                {
                    deleteRequest.Method     = HttpMethod.Delete;
                    deleteRequest.RequestUri = new Uri(fileAddress);
                    deleteRequest.Headers.IfMatch.Add(new EntityTagHeaderValue("\"invalidetag\""));

                    response = await HttpSendAsync(deleteRequest);
                    await VerifyDeploymentAsync(deploymentFileAddress, HttpStatusCode.OK, _fileContent2);

                    Assert.Equal(HttpStatusCode.PreconditionFailed, response.StatusCode);
                    Assert.Equal(updatedEtag, response.Headers.ETag);
                }

                // Check that delete with conflict fails
                TestTracer.Trace("==== Check that delete with conflict fails");
                using (HttpRequestMessage deleteRequest = new HttpRequestMessage())
                {
                    deleteRequest.Method     = HttpMethod.Delete;
                    deleteRequest.RequestUri = new Uri(fileAddress);
                    deleteRequest.Headers.IfMatch.Add(originalEtag);

                    response = await HttpSendAsync(deleteRequest);
                    await VerifyDeploymentAsync(deploymentFileAddress, HttpStatusCode.OK, _fileContent2);

                    Assert.Equal(HttpStatusCode.Conflict, response.StatusCode);
                }

                // Check that delete with valid etag succeeds
                TestTracer.Trace("==== Check that delete with valid etag succeeds");
                using (HttpRequestMessage deleteRequest = new HttpRequestMessage())
                {
                    deleteRequest.Method     = HttpMethod.Delete;
                    deleteRequest.RequestUri = new Uri(fileAddress);
                    deleteRequest.Headers.IfMatch.Add(updatedEtag);

                    response = await HttpSendAsync(deleteRequest);
                    await VerifyDeploymentAsync(deploymentFileAddress, HttpStatusCode.NotFound, null);

                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                }

                // Check that 2nd delete attempt fails
                TestTracer.Trace("==== Check that 2nd delete attempt fails");
                using (HttpRequestMessage deleteRequest = new HttpRequestMessage())
                {
                    deleteRequest.Method     = HttpMethod.Delete;
                    deleteRequest.RequestUri = new Uri(fileAddress);
                    deleteRequest.Headers.IfMatch.Add(updatedEtag);

                    response = await HttpSendAsync(deleteRequest);
                    await VerifyDeploymentAsync(deploymentFileAddress, HttpStatusCode.NotFound, null);

                    Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
                }
            }
            else
            {
                // Check that update with correct etag generates 204 Response with new etag
                TestTracer.Trace("==== Check that update with correct etag generates 204 Response with new etag");
                using (HttpRequestMessage updateRequest = new HttpRequestMessage())
                {
                    updateRequest.Method     = HttpMethod.Put;
                    updateRequest.RequestUri = new Uri(fileAddress);
                    updateRequest.Headers.IfMatch.Add(originalEtag);
                    updateRequest.Content = CreateUploadContent(_fileContent1);
                    response = await HttpSendAsync(updateRequest);

                    Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
                    Assert.NotNull(response.Headers.ETag);
                    Assert.NotEqual(originalEtag, response.Headers.ETag);
                    updatedEtag = response.Headers.ETag;
                }

                // Check that 2nd create attempt fails
                TestTracer.Trace("==== Check that 2nd create attempt fails");
                using (HttpRequestMessage updateRequest = new HttpRequestMessage())
                {
                    updateRequest.Method     = HttpMethod.Put;
                    updateRequest.RequestUri = new Uri(fileAddress);
                    updateRequest.Headers.IfMatch.Add(originalEtag);
                    updateRequest.Content = CreateUploadContent(_fileContent2);
                    response = await HttpSendAsync(updateRequest);

                    Assert.Equal(HttpStatusCode.PreconditionFailed, response.StatusCode);
                    Assert.Equal(updatedEtag, response.Headers.ETag);
                }

                // Check that update with invalid etag fails
                TestTracer.Trace("==== Check that update with invalid etag fails");
                using (HttpRequestMessage updateRequest = new HttpRequestMessage())
                {
                    updateRequest.Method     = HttpMethod.Put;
                    updateRequest.RequestUri = new Uri(fileAddress);
                    updateRequest.Headers.IfMatch.Add(new EntityTagHeaderValue("\"invalidetag\""));
                    updateRequest.Content = CreateUploadContent(_fileContent1);
                    response = await HttpSendAsync(updateRequest);

                    Assert.Equal(HttpStatusCode.PreconditionFailed, response.StatusCode);
                    Assert.Equal(updatedEtag, response.Headers.ETag);
                }

                // Check that update with wildcard etag succeeds
                TestTracer.Trace("==== Check that update with wildcard etag succeeds");
                using (HttpRequestMessage updateRequest = new HttpRequestMessage())
                {
                    updateRequest.Method     = HttpMethod.Put;
                    updateRequest.RequestUri = new Uri(fileAddress);
                    updateRequest.Headers.IfMatch.Add(EntityTagHeaderValue.Any);
                    updateRequest.Content = CreateUploadContent(_fileContent1);
                    response = await HttpSendAsync(updateRequest);

                    Assert.Equal(HttpStatusCode.NoContent, response.StatusCode);
                    Assert.NotNull(response.Headers.ETag);
                    Assert.NotEqual(originalEtag, response.Headers.ETag);
                    updatedEtag = response.Headers.ETag;
                }

                // Check that delete with invalid etag fails
                TestTracer.Trace("==== Check that delete with invalid etag fails");
                using (HttpRequestMessage deleteRequest = new HttpRequestMessage())
                {
                    deleteRequest.Method     = HttpMethod.Delete;
                    deleteRequest.RequestUri = new Uri(fileAddress);
                    deleteRequest.Headers.IfMatch.Add(new EntityTagHeaderValue("\"invalidetag\""));
                    response = await HttpSendAsync(deleteRequest);

                    Assert.Equal(HttpStatusCode.PreconditionFailed, response.StatusCode);
                    Assert.Equal(updatedEtag, response.Headers.ETag);
                }

                // Check that delete with valid etag succeeds
                TestTracer.Trace("==== Check that delete with valid etag succeeds");
                using (HttpRequestMessage deleteRequest = new HttpRequestMessage())
                {
                    deleteRequest.Method     = HttpMethod.Delete;
                    deleteRequest.RequestUri = new Uri(fileAddress);
                    deleteRequest.Headers.IfMatch.Add(updatedEtag);
                    response = await HttpSendAsync(deleteRequest);

                    Assert.Equal(HttpStatusCode.OK, response.StatusCode);
                }

                // Check that 2nd delete attempt fails
                TestTracer.Trace("==== Check that 2nd delete attempt fails");
                using (HttpRequestMessage deleteRequest = new HttpRequestMessage())
                {
                    deleteRequest.Method     = HttpMethod.Delete;
                    deleteRequest.RequestUri = new Uri(fileAddress);
                    deleteRequest.Headers.IfMatch.Add(updatedEtag);
                    response = await HttpSendAsync(deleteRequest);

                    Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
                }

                // Check that we can delete an empty directory
                TestTracer.Trace("==== Check that we can delete an empty directory");
                response = await HttpDeleteAsync(dirAddress);

                Assert.Equal(HttpStatusCode.OK, response.StatusCode);
            }
        }
Пример #18
0
 internal virtual ETag GetETag(EntityTagHeaderValue etagHeaderValue)
 {
     return(Request.GetETag(etagHeaderValue));
 }
Пример #19
0
 /// <summary>
 /// Gets the EntityTagHeaderValue ETag>.
 /// </summary>
 /// <remarks>This function uses types that are AspNet-specific.</remarks>
 public ETag GetETag <TEntity>(EntityTagHeaderValue etagHeaderValue)
 {
     return(this.innerRequest.GetETag <TEntity>(etagHeaderValue));
 }
Пример #20
0
        private static void RunQueries()
        {
            HttpClient          client = new HttpClient();
            HttpRequestMessage  request;
            HttpResponseMessage response;

            // Retrieving an entity for the first time. Observe that the returned payload contains the annotation
            // @odata.etag indicating the ETag associated with that customer.
            Console.WriteLine("Retrieving a single customer at {0}/odata/Customers(1)", serverUrl);
            Console.WriteLine();
            request  = new HttpRequestMessage(HttpMethod.Get, serverUrl + "/odata/Customers(1)");
            response = client.SendAsync(request).Result;
            response.EnsureSuccessStatusCode();
            dynamic customer = JObject.Parse(response.Content.ReadAsStringAsync().Result);

            Console.WriteLine(customer);
            Console.WriteLine();
            Console.WriteLine("-----------------------------------------------------");
            string etag = customer["@odata.etag"];

            // Retrieving the same customer as in the previous request but only if the ETag doesn't match the one
            // specified in the If-None-Match header. We are sending the ETag value that we obtained from the previous
            // request, so we expect to see a 304 (Not Modified) response.
            Console.WriteLine("Retrieving the customer at {0}/odata/Customers(1) when the Etag value sent matches");
            request = new HttpRequestMessage(HttpMethod.Get, serverUrl + "/odata/Customers(1)");
            request.Headers.IfNoneMatch.Add(EntityTagHeaderValue.Parse(etag));
            response = client.SendAsync(request).Result;
            Console.WriteLine("The response status code is: {0}", response.StatusCode);
            Console.WriteLine();
            Console.WriteLine("-----------------------------------------------------");

            // Retrieving the same customer as in the previous request but only if the ETag doesn't match the one
            // specified in the If-None-Match header. We are sending a different ETag value, so we expect to see a 200
            // (OK) response.
            Console.WriteLine("Retrieving the customer at {0}/odata/Customers(1) when the Etag value sent matches");
            request = new HttpRequestMessage(HttpMethod.Get, serverUrl + "/odata/Customers(1)");
            request.Headers.IfNoneMatch.Add(EntityTagHeaderValue.Parse("W/\"MQ==\""));
            response = client.SendAsync(request).Result;
            Console.WriteLine("The response status code is {0}", response.StatusCode);
            Console.WriteLine(JObject.Parse(response.Content.ReadAsStringAsync().Result));
            Console.WriteLine();
            Console.WriteLine("-----------------------------------------------------");

            // Removing the annotations from the customer object as they are not required on the following requests and
            // changing the age value.
            customer.Age = 99;
            customer.Remove("@odata.etag");
            customer.Remove("@odata.context");

            // Trying to update the customer using a different ETag value than the ETag on the previous request. The
            // server will return a 412 (Precondition Failed) response.
            request = new HttpRequestMessage(HttpMethod.Put, serverUrl + "/odata/Customers(1)");
            // Setting up a different ETag value.
            request.Headers.IfMatch.Add(EntityTagHeaderValue.Parse("W/\"MQ==\""));
            request.Content = new ObjectContent <JObject>(customer, new JsonMediaTypeFormatter());
            Console.WriteLine("Trying to update the Customer using a different ETag value on the If-Match header and failing");
            response = client.SendAsync(request).Result;
            Console.WriteLine("The response status code is {0}", response.StatusCode);
            Console.WriteLine();
            Console.WriteLine("-----------------------------------------------------");

            // Trying to update the customer using the ETag value retrieved from the first request. The server will
            // process the request and return a 200 (OK) response.
            request = new HttpRequestMessage(HttpMethod.Put, serverUrl + "/odata/Customers(1)");
            request.Headers.IfMatch.Add(EntityTagHeaderValue.Parse(etag));
            request.Content = new ObjectContent <JObject>(customer, new JsonMediaTypeFormatter());
            Console.WriteLine("Trying to update a Customer using the same ETag value on the If-Match header and succeeding");
            Console.WriteLine();
            response = client.SendAsync(request).Result;
            Console.Write(JObject.Parse(response.Content.ReadAsStringAsync().Result));
            Console.WriteLine();
            Console.WriteLine("-----------------------------------------------------");

            // Trying to update the customer using the If-Match header and sending an entity that doesn't exist on the
            // database. The behavior in this case is "strict update", meaning that the server shouldn't try to insert
            // the entity instead, so the answer we receive is 404 (Not Found).
            request = new HttpRequestMessage(HttpMethod.Put, serverUrl + "/odata/Customers(30)");
            request.Headers.IfMatch.Add(EntityTagHeaderValue.Parse("W/\"MQ==\""));
            Customer newCustomer = new Customer
            {
                Id      = 30,
                Name    = "New customer",
                Age     = 30,
                Version = 0
            };

            request.Content = new ObjectContent <Customer>(newCustomer, new JsonMediaTypeFormatter());
            Console.WriteLine("Trying to update a non existing customer with the If-Match header present");
            Console.WriteLine();
            response = client.SendAsync(request).Result;
            Console.WriteLine("The response status code is {0}", response.StatusCode);
            Console.WriteLine();
            Console.WriteLine("-----------------------------------------------------");

            // Trying the same request but without the If-Match header. The behavior in this case is "update or insert",
            // meaning that the server should try to insert the entity if it doesn't exist, so the answer we receive is
            // 201 (Created).
            request         = new HttpRequestMessage(HttpMethod.Put, serverUrl + "/odata/Customers(30)");
            request.Content = new ObjectContent <Customer>(newCustomer, new JsonMediaTypeFormatter());
            Console.WriteLine("Trying to update a non existing customer without the If-Match header");
            Console.WriteLine();
            response = client.SendAsync(request).Result;
            Console.WriteLine("The response status code is {0}", response.StatusCode);
            Console.WriteLine(JObject.Parse(response.Content.ReadAsStringAsync().Result));
            Console.WriteLine();
            Console.WriteLine("-----------------------------------------------------");
        }
Пример #21
0
 public NotModifiedResponse(EntityTagHeaderValue etag)
     : base(HttpStatusCode.NotModified)
 {
     this.Headers.ETag = etag;
 }
		public RangeConditionHeaderValue (EntityTagHeaderValue entityTag)
		{
			EntityTag = entityTag;
		}
Пример #23
0
 private static bool EtagEquals(HttpRequestMessage request, EntityTagHeaderValue currentEtag)
 {
     return(request.Headers.IfNoneMatch != null &&
            request.Headers.IfNoneMatch.Any(etag => currentEtag.Equals(etag)));
 }