public FamilyDateTimeClass DecodeDate(HttpDate inDate)
 {
     if (inDate != null)
     {
         FamilyDateTimeClass date = new FamilyDateTimeClass(inDate.gedcom);
     }
     return(null);
 }
示例#2
0
        /// <summary>
        /// Sets the necessary headers to disable caching of a response on the client side.
        /// </summary>
        /// <param name="this">The <see cref="IHttpResponse"/> interface on which this method is called.</param>
        /// <exception cref="NullReferenceException"><paramref name="this"/> is <see langword="null"/>.</exception>
        public static void DisableCaching(this IHttpResponse @this)
        {
            var headers = @this.Headers;

            headers.Set(HttpHeaderNames.Expires, "Sat, 26 Jul 1997 05:00:00 GMT");
            headers.Set(HttpHeaderNames.LastModified, HttpDate.Format(DateTime.UtcNow));
            headers.Set(HttpHeaderNames.CacheControl, "no-store, no-cache, must-revalidate");
            headers.Add(HttpHeaderNames.Pragma, "no-cache");
        }
示例#3
0
 private static bool IsOutDated(string ifRangeHeader, DateTime lastModified)
 {
     try {
         DateTime utcLastModified = lastModified.ToUniversalTime();
         DateTime utc             = HttpDate.UtcParse(ifRangeHeader);
         return(utc < utcLastModified);
     }
     catch {
         return(true);
     }
 }
示例#4
0
        public async Task ListDirectoryAsync(
            MappedResourceInfo info,
            string absolutePath,
            IEnumerable <MappedResourceInfo> entries,
            Stream stream,
            CancellationToken cancellationToken)
        {
            const int MaxEntryLength = 50;
            const int SizeIndent     = -20; // Negative for right alignment

            if (!info.IsDirectory)
            {
                throw SelfCheck.Failure($"{nameof(HtmlDirectoryLister)}.{nameof(ListDirectoryAsync)} invoked with a file, not a directory.");
            }

            var encodedPath = WebUtility.HtmlEncode(absolutePath);

            using var text = new StreamWriter(stream, Encoding.UTF8);
            text.Write("<html><head><title>Index of ");
            text.Write(encodedPath);
            text.Write("</title></head><body><h1>Index of ");
            text.Write(encodedPath);
            text.Write("</h1><hr/><pre>");

            if (encodedPath.Length > 1)
            {
                text.Write("<a href='../'>../</a>\n");
            }

            entries = entries.ToArray();

            foreach (var directory in entries.Where(m => m.IsDirectory).OrderBy(e => e.Name))
            {
                text.Write($"<a href=\"{Uri.EscapeDataString(directory.Name)}{Path.DirectorySeparatorChar}\">{WebUtility.HtmlEncode(directory.Name)}</a>");
                text.Write(new string(' ', Math.Max(1, MaxEntryLength - directory.Name.Length + 1)));
                text.Write(HttpDate.Format(directory.LastModifiedUtc));
                text.Write('\n');
                await Task.Yield();
            }

            foreach (var file in entries.Where(m => m.IsFile).OrderBy(e => e.Name))
            {
                text.Write($"<a href=\"{Uri.EscapeDataString(file.Name)}{Path.DirectorySeparatorChar}\">{WebUtility.HtmlEncode(file.Name)}</a>");
                text.Write(new string(' ', Math.Max(1, MaxEntryLength - file.Name.Length + 1)));
                text.Write(HttpDate.Format(file.LastModifiedUtc));
                text.Write($" {file.Length.ToString("#,###", CultureInfo.InvariantCulture),SizeIndent}\n");
                await Task.Yield();
            }

            text.Write("</pre><hr/></body></html>");
        }
示例#5
0
        // Check whether the If-Modified-Since request header exists
        // and specifies a date and time more recent than or equal to
        // the date and time of last modification of the requested resource.
        // RFC7232, Section 3.3

        /// <summary>
        /// <para>Checks whether an <c>If-Modified-Since</c> header exists in a request
        /// and, if so, whether its value is a date and time more recent or equal to
        /// a given <see cref="DateTime"/>.</para>
        /// <para>See <see href="https://tools.ietf.org/html/rfc7232#section-3.3">RFC7232, Section 3.3</see>
        /// for a normative reference.</para>
        /// </summary>
        /// <param name="this">The <see cref="IHttpRequest"/> on which this method is called.</param>
        /// <param name="lastModifiedUtc">A date and time value, in Coordinated Universal Time,
        /// expressing the last time a resource was modified.</param>
        /// <param name="headerExists">When this method returns, a value that indicates whether an
        /// <c>If-Modified-Since</c> header is present in <paramref name="this"/>, regardless of the method's
        /// return value. This parameter is passed uninitialized.</param>
        /// <returns><see langword="true"/> if an <c>If-Modified-Since</c> header is present in
        /// <paramref name="this"/> and its value is a date and time more recent or equal to <paramref name="lastModifiedUtc"/>;
        /// <see langword="false"/> otherwise.</returns>
        public static bool CheckIfModifiedSince(this IHttpRequest @this, DateTime lastModifiedUtc, out bool headerExists)
        {
            var value = @this.Headers.Get(HttpHeaderNames.IfModifiedSince);

            if (value == null)
            {
                headerExists = false;
                return(false);
            }

            headerExists = true;
            return(HttpDate.TryParse(value, out var dateTime) &&
                   dateTime.UtcDateTime >= lastModifiedUtc);
        }
        public async Task ListDirectoryAsync(
            MappedResourceInfo info,
            string absoluteUrlPath,
            IEnumerable <MappedResourceInfo> entries,
            Stream stream,
            CancellationToken cancellationToken)
        {
            if (info?.IsDirectory != true)
            {
                throw new ArgumentException("HtmlDirectoryLister.ListDirectoryAsync invoked with a file, not a directory.");
            }
            string str = WebUtility.HtmlEncode(absoluteUrlPath);

            await using StreamWriter text = new StreamWriter(stream, Encoding.UTF8);
            text.Write("<html><head><title>Index of ");
            text.Write(str);
            text.Write("</title></head><body><h1>Index of ");
            text.Write(str);
            text.Write("</h1><hr/><pre>");
            if (str?.Length > 1)
            {
                text.Write("<a href='../'>../</a>\n");
            }
            entries = entries.ToArray();
            foreach (MappedResourceInfo mappedResourceInfo in entries.Where(m => m.IsDirectory).OrderBy(e => e.Name))
            {
                text.Write(
                    $"<a href=\"{(!string.IsNullOrEmpty(str)? str + (str.EndsWith(Path.DirectorySeparatorChar) ? "" : Path.DirectorySeparatorChar.ToString(CultureInfo.InvariantCulture)) : "")}{Uri.EscapeDataString(mappedResourceInfo.Name)}{Path.DirectorySeparatorChar}\">{WebUtility.HtmlEncode(mappedResourceInfo.Name)}</a>");
                text.Write(new string(' ', Math.Max(1, 50 - mappedResourceInfo.Name.Length + 1)));
                text.Write(HttpDate.Format(mappedResourceInfo.LastModifiedUtc));
                text.Write('\n');
                await Task.Yield();
            }
            foreach (MappedResourceInfo mappedResourceInfo in entries.Where(m => m.IsFile).OrderBy(e => e.Name))
            {
                text.Write(
                    $"<a href=\"{(!string.IsNullOrEmpty(str) ? str + (str.EndsWith(Path.DirectorySeparatorChar) ? "" : Path.DirectorySeparatorChar.ToString(CultureInfo.InvariantCulture)) : "")}{Uri.EscapeDataString(mappedResourceInfo.Name)}\">{WebUtility.HtmlEncode(mappedResourceInfo.Name)}</a>");
                text.Write(new string(' ', Math.Max(1, 50 - mappedResourceInfo.Name.Length + 1)));
                text.Write(HttpDate.Format(mappedResourceInfo.LastModifiedUtc));
                text.Write(" {0,-20}\n", mappedResourceInfo.Length.ToString("#,###", CultureInfo.InvariantCulture));
                await Task.Yield();
            }
            text.Write("</pre><hr/></body></html>");
        }
示例#7
0
        public IHttpAction Handle(Request request)
        {
            if (request.Object.Method == "GET" || request.Object.Method == "HEAD")
            {
                var includeBody = request.Object.Method != "HEAD";

                var httpHeaders = new HttpHeaders();

                var fileSystem = new FileSystem(Path.Combine(DirectoryRoot, "www", request.VirtualHost.Directory, request.Object.Uri.Url), request.VirtualHost.DefaultIndex);

                var fileDescription = fileSystem.GetFile();

                if (fileDescription == null)
                {
                    return(new NotFound(includeBody));
                }

                var dateChange = new HttpDate(fileDescription.GetLastModified());

                httpHeaders.Add("Content-Type", HttpMimeType.GetByExtension(fileDescription.GetExtension()) + "; charset=" + fileDescription.GetEncoding());
                httpHeaders.Add("Last-Modified", dateChange.ToString());

                if (request.Object.HttpRange != null)
                {
                    try
                    {
                        request.Object.HttpRange.Normalize(fileDescription.GetFileSize() - 1);
                        var bytesArray = fileDescription.GetRangeBytes(request.Object.HttpRange);
                        if (bytesArray.Length > 0)
                        {
                            httpHeaders.Add("Content-Range", request.Object.HttpRange.ToString());
                            return(new PartialContent(httpHeaders, bytesArray, includeBody));
                        }
                        else
                        {
                            return(new NotSatisfiable(includeBody));
                        }
                    }
                    catch (Exception)
                    {
                        request.Object.HttpRange = null;
                    }
                }

                if (request.Object["If-Modified-Since"] != null)
                {
                    try
                    {
                        var requestDate = DateTime.Parse(request.Object["If-Modified-Since"].Trim());
                        if (requestDate >= dateChange.DateTime)
                        {
                            return(new NotModified(httpHeaders, includeBody));
                        }
                    }
                    catch
                    {
                        // ignored
                    }
                }

                return(new Ok(httpHeaders, fileDescription.GetAllBytes(), includeBody));
            }
            return(NextHandler != null?NextHandler.Handle(request) : new NotImplemented());
        }
示例#8
0
        /*
         * Try to find this request in the cache. If so, return it. Otherwise,
         * store the cache key for use on Leave.
         */
        /// <include file='doc\OutputCacheModule.uex' path='docs/doc[@for="OutputCacheModule.OnEnter"]/*' />
        /// <devdoc>
        /// <para>Raises the <see langword='Enter'/>
        /// event, which searches the output cache for an item to satisfy the HTTP request. </para>
        /// </devdoc>
        internal /*public*/ void OnEnter(Object source, EventArgs eventArgs)
        {
            HttpApplication         app;
            HttpContext             context;
            string                  key;
            HttpRequest             request;
            HttpResponse            response;
            Object                  item;
            CachedRawResponse       cachedRawResponse;
            HttpCachePolicySettings settings;
            int  i, n;
            bool sendBody;
            HttpValidationStatus   validationStatus, validationStatusFinal;
            ValidationCallbackInfo callbackInfo;
            string   ifModifiedSinceHeader;
            DateTime utcIfModifiedSince;
            string   etag;

            string[] etags;
            int      send304;
            string   cacheControl;

            string[] cacheDirectives = null;
            string   pragma;

            string[]      pragmaDirectives = null;
            string        directive;
            int           maxage;
            int           minfresh;
            int           age;
            int           fresh;
            bool          hasValidationPolicy;
            CachedVary    cachedVary;
            CacheInternal cacheInternal;

            Debug.Trace("OutputCacheModuleEnter", "Beginning OutputCacheModule::Enter");

            app                = (HttpApplication)source;
            context            = app.Context;
            request            = context.Request;
            response           = context.Response;
            _key               = null;
            _recordedCacheMiss = false;
            _method            = CacheRequestMethod.Invalid;

            /*
             * Check if the request can be resolved for this method.
             */
            switch (request.HttpMethod)
            {
            case "HEAD":
                _method = CacheRequestMethod.Head;
                break;

            case "GET":
                _method = CacheRequestMethod.Get;
                break;

            case "POST":
                _method = CacheRequestMethod.Post;
                break;

            default:
                Debug.Trace("OutputCacheModuleEnter", "Output cache miss, Http method not GET, POST, or HEAD" +
                            "\nReturning from OutputCacheModule::Enter");

                return;
            }

            /*
             * Create a lookup key. Remember the key for use inside Leave()
             */
            _key = key = CreateOutputCachedItemKey(context, null);
            Debug.Assert(_key != null, "_key != null");

            /*
             *  Lookup the cached item.
             */
            cacheInternal = HttpRuntime.CacheInternal;
            item          = cacheInternal.Get(key);
            if (item == null)
            {
                Debug.Trace("OutputCacheModuleEnter", "Output cache miss, item not found.\n\tkey=" + key +
                            "\nReturning from OutputCacheModule::Enter");

                return;
            }

            cachedVary = item as CachedVary;
            if (cachedVary != null)
            {
                /*
                 * This cached output has a Vary policy. Create a new key based
                 * on the vary headers in cachedRawResponse and try again.
                 */
                Debug.Trace("OutputCacheModuleEnter", "Output cache found CachedVary, \n\tkey=" + key);
                key = CreateOutputCachedItemKey(context, cachedVary);
                if (key == null)
                {
                    Debug.Trace("OutputCacheModuleEnter", "Output cache miss, key could not be created for vary-by item." +
                                "\nReturning from OutputCacheModule::Enter");

                    return;
                }

                item = cacheInternal.Get(key);
                if (item == null)
                {
                    Debug.Trace("OutputCacheModuleEnter", "Output cache miss, item not found.\n\tkey=" + key +
                                "\nReturning from OutputCacheModule::Enter");

                    return;
                }
            }

            Debug.Assert(item.GetType() == typeof(CachedRawResponse), "item.GetType() == typeof(CachedRawResponse)");
            cachedRawResponse = (CachedRawResponse)item;
            settings          = cachedRawResponse._settings;
            if (cachedVary == null && !settings.IgnoreParams)
            {
                /*
                 * This cached output has no vary policy, so make sure it doesn't have a query string or form post.
                 */
                if (_method == CacheRequestMethod.Post)
                {
                    Debug.Trace("OutputCacheModuleEnter", "Output cache item found but method is POST and no VaryByParam specified." +
                                "\n\tkey=" + key +
                                "\nReturning from OutputCacheModule::Enter");
                    RecordCacheMiss();
                    return;
                }

                string queryStringText = request.QueryStringText;
                if (queryStringText != null && queryStringText.Length > 0)
                {
                    Debug.Trace("OutputCacheModuleEnter", "Output cache item found but contains a querystring and no VaryByParam specified." +
                                "\n\tkey=" + key +
                                "\nReturning from OutputCacheModule::Enter");
                    RecordCacheMiss();
                    return;
                }
            }

            hasValidationPolicy = settings.HasValidationPolicy();

            /*
             * Determine whether the client can accept a cached copy, and
             * get values of other cache control directives.
             *
             * We do this after lookup so we don't have to crack the headers
             * if the item is not found. Cracking the headers is expensive.
             */
            if (!hasValidationPolicy)
            {
                cacheControl = request.Headers["Cache-Control"];
                if (cacheControl != null)
                {
                    cacheDirectives = cacheControl.Split(s_fieldSeparators);
                    for (i = 0; i < cacheDirectives.Length; i++)
                    {
                        directive = cacheDirectives[i];
                        if (directive == "no-cache")
                        {
                            Debug.Trace("OutputCacheModuleEnter",
                                        "Skipping lookup because of Cache-Control: no-cache directive." +
                                        "\nReturning from OutputCacheModule::Enter");

                            RecordCacheMiss();
                            return;
                        }

                        if (directive.StartsWith("max-age="))
                        {
                            try {
                                maxage = Convert.ToInt32(directive.Substring(8));
                            }
                            catch {
                                maxage = -1;
                            }

                            if (maxage >= 0)
                            {
                                age = (int)((context.UtcTimestamp.Ticks - settings.UtcTimestampCreated.Ticks) / TimeSpan.TicksPerSecond);
                                if (age >= maxage)
                                {
                                    Debug.Trace("OutputCacheModuleEnter",
                                                "Not returning found item due to Cache-Control: max-age directive." +
                                                "\nReturning from OutputCacheModule::Enter");

                                    RecordCacheMiss();
                                    return;
                                }
                            }
                        }
                        else if (directive.StartsWith("min-fresh="))
                        {
                            try {
                                minfresh = Convert.ToInt32(directive.Substring(10));
                            }
                            catch {
                                minfresh = -1;
                            }

                            if (minfresh >= 0 && settings.IsExpiresSet && !settings.SlidingExpiration)
                            {
                                fresh = (int)((settings.UtcExpires.Ticks - context.UtcTimestamp.Ticks) / TimeSpan.TicksPerSecond);
                                if (fresh < minfresh)
                                {
                                    Debug.Trace("OutputCacheModuleEnter",
                                                "Not returning found item due to Cache-Control: min-fresh directive." +
                                                "\nReturning from OutputCacheModule::Enter");

                                    RecordCacheMiss();
                                    return;
                                }
                            }
                        }
                    }
                }

                pragma = request.Headers["Pragma"];
                if (pragma != null)
                {
                    pragmaDirectives = pragma.Split(s_fieldSeparators);
                    for (i = 0; i < pragmaDirectives.Length; i++)
                    {
                        if (pragmaDirectives[i] == "no-cache")
                        {
                            Debug.Trace("OutputCacheModuleEnter",
                                        "Skipping lookup because of Pragma: no-cache directive." +
                                        "\nReturning from OutputCacheModule::Enter");

                            RecordCacheMiss();
                            return;
                        }
                    }
                }
            }
            else if (settings.ValidationCallbackInfo != null)
            {
                /*
                 * Check if the item is still valid.
                 */
                validationStatus      = HttpValidationStatus.Valid;
                validationStatusFinal = validationStatus;
                for (i = 0, n = settings.ValidationCallbackInfo.Length; i < n; i++)
                {
                    callbackInfo = settings.ValidationCallbackInfo[i];
                    try {
                        callbackInfo.handler(context, callbackInfo.data, ref validationStatus);
                    }
                    catch (Exception e) {
                        validationStatus = HttpValidationStatus.Invalid;
                        HttpApplicationFactory.RaiseError(e);
                    }

                    switch (validationStatus)
                    {
                    case HttpValidationStatus.Invalid:
                        Debug.Trace("OutputCacheModuleEnter", "Output cache item found but callback invalidated it." +
                                    "\n\tkey=" + key +
                                    "\nReturning from OutputCacheModule::Enter");

                        cacheInternal.Remove(key);
                        RecordCacheMiss();
                        return;

                    case HttpValidationStatus.IgnoreThisRequest:
                        validationStatusFinal = HttpValidationStatus.IgnoreThisRequest;
                        break;

                    case HttpValidationStatus.Valid:
                        break;

                    default:
                        Debug.Trace("OutputCacheModuleEnter", "Invalid validation status, ignoring it, status=" + validationStatus +
                                    "\n\tkey=" + key);

                        validationStatus = validationStatusFinal;
                        break;
                    }
                }

                if (validationStatusFinal == HttpValidationStatus.IgnoreThisRequest)
                {
                    Debug.Trace("OutputCacheModuleEnter", "Output cache item found but callback status is IgnoreThisRequest." +
                                "\n\tkey=" + key +
                                "\nReturning from OutputCacheModule::Enter");


                    RecordCacheMiss();
                    return;
                }

                Debug.Assert(validationStatusFinal == HttpValidationStatus.Valid,
                             "validationStatusFinal == HttpValidationStatus.Valid");
            }

            /*
             * Try to satisfy a conditional request. The cached response
             * must satisfy all conditions that are present.
             *
             * We can only satisfy a conditional request if the response
             * is buffered and has no substitution blocks.
             *
             * N.B. RFC 2616 says conditional requests only occur
             * with the GET method, but we try to satisfy other
             * verbs (HEAD, POST) as well.
             */
            send304 = -1;

            if (response.IsBuffered() && !cachedRawResponse._rawResponse.HasSubstBlocks)
            {
                /* Check "If-Modified-Since" header */
                ifModifiedSinceHeader = request.IfModifiedSince;
                if (ifModifiedSinceHeader != null)
                {
                    send304 = 0;
                    try {
                        utcIfModifiedSince = HttpDate.UtcParse(ifModifiedSinceHeader);
                        if (settings.IsLastModifiedSet &&
                            settings.UtcLastModified <= utcIfModifiedSince &&
                            utcIfModifiedSince <= context.UtcTimestamp)
                        {
                            send304 = 1;
                        }
                    }
                    catch {
                        Debug.Trace("OutputCacheModuleEnter", "Ignore If-Modified-Since header, invalid format: " + ifModifiedSinceHeader);
                    }
                }

                /* Check "If-None-Match" header */
                if (send304 != 0)
                {
                    etag = request.IfNoneMatch;
                    if (etag != null)
                    {
                        send304 = 0;
                        etags   = etag.Split(s_fieldSeparators);
                        for (i = 0, n = etags.Length; i < n; i++)
                        {
                            if (i == 0 && etags[i].Equals("*"))
                            {
                                send304 = 1;
                                break;
                            }

                            if (etags[i].Equals(settings.ETag))
                            {
                                send304 = 1;
                                break;
                            }
                        }
                    }
                }
            }

            if (send304 == 1)
            {
                /*
                 * Send 304 Not Modified
                 */
                Debug.Trace("OutputCacheModuleEnter", "Output cache hit & conditional request satisfied, status=304." +
                            "\n\tkey=" + key +
                            "\nReturning from OutputCacheModule::Enter");

                response.ClearAll();
                response.StatusCode = 304;
            }
            else
            {
                /*
                 * Send the full response.
                 */
#if DBG
                if (send304 == -1)
                {
                    Debug.Trace("OutputCacheModuleEnter", "Output cache hit.\n\tkey=" + key +
                                "\nReturning from OutputCacheModule::Enter");
                }
                else
                {
                    Debug.Trace("OutputCacheModuleEnter", "Output cache hit but conditional request not satisfied.\n\tkey=" + key +
                                "\nReturning from OutputCacheModule::Enter");
                }
#endif

                sendBody = (_method != CacheRequestMethod.Head);

                // UseSnapshot calls ClearAll
                response.UseSnapshot(cachedRawResponse._rawResponse, sendBody);
            }

            response.Cache.ResetFromHttpCachePolicySettings(settings, context.UtcTimestamp);

            PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_RATIO_BASE);
            PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_HITS);

            _key = null;
            _recordedCacheMiss = false;
            _method            = CacheRequestMethod.Invalid;

            app.CompleteRequest();
        }
示例#9
0
        /// <summary>Creates a <see cref="CookieList"/> by parsing
        /// the value of one or more <c>Cookie</c> or <c>Set-Cookie</c> headers.</summary>
        /// <param name="headerValue">The value, or comma-separated list of values,
        /// of the header or headers.</param>
        /// <returns>A newly-created instance of <see cref="CookieList"/>.</returns>
        public static CookieList Parse(string headerValue)
        {
            var cookies = new CookieList();

            Cookie cookie = null;
            var    pairs  = SplitCookieHeaderValue(headerValue);

            for (var i = 0; i < pairs.Length; i++)
            {
                var pair = pairs[i].Trim();
                if (pair.Length == 0)
                {
                    continue;
                }

                if (pair.StartsWith("version", StringComparison.OrdinalIgnoreCase) && cookie != null)
                {
                    cookie.Version = int.Parse(GetValue(pair, true), CultureInfo.InvariantCulture);
                }
                else if (pair.StartsWith("expires", StringComparison.OrdinalIgnoreCase) && cookie != null)
                {
                    var buff = new StringBuilder(GetValue(pair), 32);
                    if (i < pairs.Length - 1)
                    {
                        buff.AppendFormat(CultureInfo.InvariantCulture, ", {0}", pairs[++i].Trim());
                    }

                    if (!HttpDate.TryParse(buff.ToString(), out var expires))
                    {
                        expires = DateTimeOffset.Now;
                    }

                    if (cookie.Expires == DateTime.MinValue)
                    {
                        cookie.Expires = expires.LocalDateTime;
                    }
                }
                else if (pair.StartsWith("max-age", StringComparison.OrdinalIgnoreCase) && cookie != null)
                {
                    var max = int.Parse(GetValue(pair, true), CultureInfo.InvariantCulture);

                    cookie.Expires = DateTime.Now.AddSeconds(max);
                }
                else if (pair.StartsWith("path", StringComparison.OrdinalIgnoreCase) && cookie != null)
                {
                    cookie.Path = GetValue(pair);
                }
                else if (pair.StartsWith("domain", StringComparison.OrdinalIgnoreCase) && cookie != null)
                {
                    cookie.Domain = GetValue(pair);
                }
                else if (pair.StartsWith("port", StringComparison.OrdinalIgnoreCase) && cookie != null)
                {
                    cookie.Port = pair.Equals("port", StringComparison.OrdinalIgnoreCase)
                        ? "\"\""
                        : GetValue(pair);
                }
                else if (pair.StartsWith("comment", StringComparison.OrdinalIgnoreCase) && cookie != null)
                {
                    cookie.Comment = WebUtility.UrlDecode(GetValue(pair));
                }
                else if (pair.StartsWith("commenturl", StringComparison.OrdinalIgnoreCase) && cookie != null)
                {
                    cookie.CommentUri = UriUtility.StringToUri(GetValue(pair, true));
                }
                else if (pair.StartsWith("discard", StringComparison.OrdinalIgnoreCase) && cookie != null)
                {
                    cookie.Discard = true;
                }
                else if (pair.StartsWith("secure", StringComparison.OrdinalIgnoreCase) && cookie != null)
                {
                    cookie.Secure = true;
                }
                else if (pair.StartsWith("httponly", StringComparison.OrdinalIgnoreCase) && cookie != null)
                {
                    cookie.HttpOnly = true;
                }
                else
                {
                    if (cookie != null)
                    {
                        cookies.Add(cookie);
                    }

                    cookie = ParseCookie(pair);
                }
            }

            if (cookie != null)
            {
                cookies.Add(cookie);
            }

            return(cookies);
        }
示例#10
0
        // Checks the Range request header to tell whether to send
        // a "206 Partial Content" response.

        /// <summary>
        /// <para>Checks whether a <c>Range</c> header exists in a request
        /// and, if so, determines whether it is possible to send a <c>206 Partial Content</c> response.</para>
        /// <para>See <see href="https://tools.ietf.org/html/rfc7233">RFC7233</see>
        /// for a normative reference; however, see the Remarks section for more information
        /// about the RFC compliance of this method.</para>
        /// </summary>
        /// <param name="this">The <see cref="IHttpRequest"/> on which this method is called.</param>
        /// <param name="contentLength">The total length, in bytes, of the response entity, i.e.
        /// what would be sent in a <c>200 OK</c> response.</param>
        /// <param name="entityTag">An entity tag representing the response entity. This value is checked against
        /// the <c>If-Range</c> header, if it is present.</param>
        /// <param name="lastModifiedUtc">The date and time value, in Coordinated Universal Time,
        /// expressing the last modification time of the resource entity. This value is checked against
        /// the <c>If-Range</c> header, if it is present.</param>
        /// <param name="start">When this method returns <see langword="true"/>, the start of the requested byte range.
        /// This parameter is passed uninitialized.</param>
        /// <param name="upperBound">
        /// <para>When this method returns <see langword="true"/>, the upper bound of the requested byte range.
        /// This parameter is passed uninitialized.</para>
        /// <para>Note that the upper bound of a range is NOT the sum of the range's start and length;
        /// for example, a range expressed as <c>bytes=0-99</c> has a start of 0, an upper bound of 99,
        /// and a length of 100 bytes.</para>
        /// </param>
        /// <returns>
        /// <para>This method returns <see langword="true"/> if the following conditions are satisfied:</para>
        /// <list type="bullet">
        /// <item><description>>the request's HTTP method is <c>GET</c>;</description></item>
        /// <item><description>>a <c>Range</c> header is present in the request;</description></item>
        /// <item><description>>either no <c>If-Range</c> header is present in the request, or it
        /// specifies an entity tag equal to <paramref name="entityTag"/>, or a UTC date and time
        /// equal to <paramref name="lastModifiedUtc"/>;</description></item>
        /// <item><description>>the <c>Range</c> header specifies exactly one range;</description></item>
        /// <item><description>>the specified range is entirely contained in the range from 0 to <paramref name="contentLength"/> - 1.</description></item>
        /// </list>
        /// <para>If the last condition is not satisfied, i.e. the specified range start and/or upper bound
        /// are out of the range from 0 to <paramref name="contentLength"/> - 1, this method does not return;
        /// it throws a <see cref="HttpRangeNotSatisfiableException"/> instead.</para>
        /// <para>If any of the other conditions are not satisfied, this method returns <see langword="false"/>.</para>
        /// </returns>
        /// <remarks>
        /// <para>According to <see href="https://tools.ietf.org/html/rfc7233#section-3.1">RFC7233, Section 3.1</see>,
        /// there are several conditions under which a server may ignore or reject a range request; therefore,
        /// clients are (or should be) prepared to receive a <c>200 OK</c> response with the whole response
        /// entity instead of the requested range(s). For this reason, until the generation of
        /// <c>multipart/byteranges</c> responses is implemented in EmbedIO, this method will ignore
        /// range requests specifying more than one range, even if this behavior is not, strictly speaking,
        /// RFC7233-compliant.</para>
        /// <para>To make clients aware that range requests are accepted for a resource, every <c>200 OK</c>
        /// (or <c>304 Not Modified</c>) response for the same resource should include an <c>Accept-Ranges</c>
        /// header with the string <c>bytes</c> as value.</para>
        /// </remarks>
        public static bool IsRangeRequest(this IHttpRequest @this, long contentLength, string entityTag, DateTime lastModifiedUtc, out long start, out long upperBound)
        {
            start      = 0;
            upperBound = contentLength - 1;

            // RFC7233, Section 3.1:
            // "A server MUST ignore a Range header field received with a request method other than GET."
            if (@this.HttpVerb != HttpVerbs.Get)
            {
                return(false);
            }

            // No Range header, no partial content.
            var rangeHeader = @this.Headers.Get(HttpHeaderNames.Range);

            if (rangeHeader == null)
            {
                return(false);
            }

            // Ignore the Range header if there is no If-Range header
            // or if the If-Range header specifies a non-matching validator.
            // RFC7233, Section 3.2: "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.Note that this comparison by exact match,
            //                       including when the validator is an HTTP-date, differs from the
            //                       "earlier than or equal to" comparison used when evaluating an
            //                       If-Unmodified-Since conditional."
            var ifRange = @this.Headers.Get(HttpHeaderNames.IfRange)?.Trim();

            if (ifRange != null && ifRange != entityTag)
            {
                if (!HttpDate.TryParse(ifRange, out var rangeDate))
                {
                    return(false);
                }

                if (rangeDate.UtcDateTime != lastModifiedUtc)
                {
                    return(false);
                }
            }

            // Ignore the Range request header if it cannot be parsed successfully.
            if (!RangeHeaderValue.TryParse(rangeHeader, out var range))
            {
                return(false);
            }

            // EmbedIO does not support multipart/byteranges responses (yet),
            // thus ignore range requests that specify one range.
            if (range.Ranges.Count != 1)
            {
                return(false);
            }

            var firstRange = range.Ranges.First();

            start      = firstRange.From ?? 0L;
            upperBound = firstRange.To ?? contentLength - 1;
            if (start >= contentLength || upperBound < start || upperBound >= contentLength)
            {
                throw HttpException.RangeNotSatisfiable(contentLength);
            }

            return(true);
        }
        internal void OnEnter(object source, EventArgs eventArgs)
        {
            this._key = null;
            this._recordedCacheMiss = false;
            if (OutputCache.InUse)
            {
                string[]        strArray2   = null;
                string[]        strArray3   = null;
                HttpApplication application = (HttpApplication)source;
                HttpContext     context     = application.Context;
                context.GetFilePathData();
                HttpRequest  request  = context.Request;
                HttpResponse response = context.Response;
                switch (request.HttpVerb)
                {
                case HttpVerb.GET:
                case HttpVerb.HEAD:
                case HttpVerb.POST:
                {
                    string str;
                    this._key = str = this.CreateOutputCachedItemKey(context, null);
                    object obj2 = OutputCache.Get(str);
                    if (obj2 != null)
                    {
                        int        num;
                        int        length;
                        CachedVary cachedVary = obj2 as CachedVary;
                        if (cachedVary != null)
                        {
                            str = this.CreateOutputCachedItemKey(context, cachedVary);
                            if (str == null)
                            {
                                return;
                            }
                            if (cachedVary._contentEncodings == null)
                            {
                                obj2 = OutputCache.Get(str);
                            }
                            else
                            {
                                obj2 = null;
                                bool   flag3 = true;
                                string knownRequestHeader = context.WorkerRequest.GetKnownRequestHeader(0x16);
                                if (knownRequestHeader != null)
                                {
                                    string[] contentEncodings = cachedVary._contentEncodings;
                                    int      startIndex       = 0;
                                    bool     flag4            = false;
                                    while (!flag4)
                                    {
                                        flag4 = true;
                                        int index = GetAcceptableEncoding(contentEncodings, startIndex, knownRequestHeader);
                                        if (index > -1)
                                        {
                                            flag3 = false;
                                            obj2  = OutputCache.Get(str + contentEncodings[index]);
                                            if (obj2 == null)
                                            {
                                                startIndex = index + 1;
                                                if (startIndex < contentEncodings.Length)
                                                {
                                                    flag4 = false;
                                                }
                                            }
                                        }
                                        else if (index == -2)
                                        {
                                            flag3 = false;
                                        }
                                    }
                                }
                                if ((obj2 == null) && flag3)
                                {
                                    obj2 = OutputCache.Get(str);
                                }
                            }
                            if ((obj2 == null) || (((CachedRawResponse)obj2)._cachedVaryId != cachedVary.CachedVaryId))
                            {
                                if (obj2 != null)
                                {
                                    OutputCache.Remove(str, context);
                                }
                                return;
                            }
                        }
                        CachedRawResponse       response2 = (CachedRawResponse)obj2;
                        HttpCachePolicySettings settings  = response2._settings;
                        if ((cachedVary == null) && !settings.IgnoreParams)
                        {
                            if (request.HttpVerb == HttpVerb.POST)
                            {
                                this.RecordCacheMiss();
                                return;
                            }
                            if (request.HasQueryString)
                            {
                                this.RecordCacheMiss();
                                return;
                            }
                        }
                        if (settings.IgnoreRangeRequests)
                        {
                            string str8 = request.Headers["Range"];
                            if (StringUtil.StringStartsWithIgnoreCase(str8, "bytes"))
                            {
                                return;
                            }
                        }
                        if (!settings.HasValidationPolicy())
                        {
                            string str4 = request.Headers["Cache-Control"];
                            if (str4 != null)
                            {
                                strArray2 = str4.Split(s_fieldSeparators);
                                for (num = 0; num < strArray2.Length; num++)
                                {
                                    string str6 = strArray2[num];
                                    switch (str6)
                                    {
                                    case "no-cache":
                                    case "no-store":
                                        this.RecordCacheMiss();
                                        return;
                                    }
                                    if (StringUtil.StringStartsWith(str6, "max-age="))
                                    {
                                        int num4;
                                        try
                                        {
                                            num4 = Convert.ToInt32(str6.Substring(8), CultureInfo.InvariantCulture);
                                        }
                                        catch
                                        {
                                            num4 = -1;
                                        }
                                        if (num4 >= 0)
                                        {
                                            int num6 = (int)((context.UtcTimestamp.Ticks - settings.UtcTimestampCreated.Ticks) / 0x989680L);
                                            if (num6 >= num4)
                                            {
                                                this.RecordCacheMiss();
                                                return;
                                            }
                                        }
                                    }
                                    else if (StringUtil.StringStartsWith(str6, "min-fresh="))
                                    {
                                        int num5;
                                        try
                                        {
                                            num5 = Convert.ToInt32(str6.Substring(10), CultureInfo.InvariantCulture);
                                        }
                                        catch
                                        {
                                            num5 = -1;
                                        }
                                        if (((num5 >= 0) && settings.IsExpiresSet) && !settings.SlidingExpiration)
                                        {
                                            int num7 = (int)((settings.UtcExpires.Ticks - context.UtcTimestamp.Ticks) / 0x989680L);
                                            if (num7 < num5)
                                            {
                                                this.RecordCacheMiss();
                                                return;
                                            }
                                        }
                                    }
                                }
                            }
                            string str5 = request.Headers["Pragma"];
                            if (str5 != null)
                            {
                                strArray3 = str5.Split(s_fieldSeparators);
                                for (num = 0; num < strArray3.Length; num++)
                                {
                                    if (strArray3[num] == "no-cache")
                                    {
                                        this.RecordCacheMiss();
                                        return;
                                    }
                                }
                            }
                        }
                        else if (settings.ValidationCallbackInfo != null)
                        {
                            HttpValidationStatus valid             = HttpValidationStatus.Valid;
                            HttpValidationStatus ignoreThisRequest = valid;
                            num    = 0;
                            length = settings.ValidationCallbackInfo.Length;
                            while (num < length)
                            {
                                ValidationCallbackInfo info = settings.ValidationCallbackInfo[num];
                                try
                                {
                                    info.handler(context, info.data, ref valid);
                                }
                                catch (Exception exception)
                                {
                                    valid = HttpValidationStatus.Invalid;
                                    HttpApplicationFactory.RaiseError(exception);
                                }
                                switch (valid)
                                {
                                case HttpValidationStatus.Invalid:
                                    OutputCache.Remove(str, context);
                                    this.RecordCacheMiss();
                                    return;

                                case HttpValidationStatus.IgnoreThisRequest:
                                    ignoreThisRequest = HttpValidationStatus.IgnoreThisRequest;
                                    break;

                                case HttpValidationStatus.Valid:
                                    break;

                                default:
                                    valid = ignoreThisRequest;
                                    break;
                                }
                                num++;
                            }
                            if (ignoreThisRequest == HttpValidationStatus.IgnoreThisRequest)
                            {
                                this.RecordCacheMiss();
                                return;
                            }
                        }
                        HttpRawResponse rawResponse = response2._rawResponse;
                        if ((cachedVary == null) || (cachedVary._contentEncodings == null))
                        {
                            string    acceptEncoding  = request.Headers["Accept-Encoding"];
                            string    contentEncoding = null;
                            ArrayList headers         = rawResponse.Headers;
                            if (headers != null)
                            {
                                foreach (HttpResponseHeader header in headers)
                                {
                                    if (header.Name == "Content-Encoding")
                                    {
                                        contentEncoding = header.Value;
                                        break;
                                    }
                                }
                            }
                            if (!IsAcceptableEncoding(contentEncoding, acceptEncoding))
                            {
                                this.RecordCacheMiss();
                                return;
                            }
                        }
                        int num3 = -1;
                        if (!rawResponse.HasSubstBlocks)
                        {
                            string ifModifiedSince = request.IfModifiedSince;
                            if (ifModifiedSince != null)
                            {
                                num3 = 0;
                                try
                                {
                                    DateTime time = HttpDate.UtcParse(ifModifiedSince);
                                    if ((settings.IsLastModifiedSet && (settings.UtcLastModified <= time)) && (time <= context.UtcTimestamp))
                                    {
                                        num3 = 1;
                                    }
                                }
                                catch
                                {
                                }
                            }
                            if (num3 != 0)
                            {
                                string ifNoneMatch = request.IfNoneMatch;
                                if (ifNoneMatch != null)
                                {
                                    num3 = 0;
                                    string[] strArray = ifNoneMatch.Split(s_fieldSeparators);
                                    num    = 0;
                                    length = strArray.Length;
                                    while (num < length)
                                    {
                                        if ((num == 0) && strArray[num].Equals("*"))
                                        {
                                            num3 = 1;
                                            break;
                                        }
                                        if (strArray[num].Equals(settings.ETag))
                                        {
                                            num3 = 1;
                                            break;
                                        }
                                        num++;
                                    }
                                }
                            }
                        }
                        if (num3 == 1)
                        {
                            response.ClearAll();
                            response.StatusCode = 0x130;
                        }
                        else
                        {
                            bool sendBody = request.HttpVerb != HttpVerb.HEAD;
                            response.UseSnapshot(rawResponse, sendBody);
                        }
                        response.Cache.ResetFromHttpCachePolicySettings(settings, context.UtcTimestamp);
                        string originalCacheUrl = response2._kernelCacheUrl;
                        if (originalCacheUrl != null)
                        {
                            response.SetupKernelCaching(originalCacheUrl);
                        }
                        PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_RATIO_BASE);
                        PerfCounters.IncrementCounter(AppPerfCounter.OUTPUT_CACHE_HITS);
                        this._key = null;
                        this._recordedCacheMiss = false;
                        application.CompleteRequest();
                        return;
                    }
                    return;
                }
                }
            }
        }