src/packages/EmbedIO/HttpRequestExtensions.cs
/// <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>
Checks whether a Range206 Partial ContentSee RFC7233
Checks whether a Range206 Partial ContentSee RFC7233
public static bool IsRangeRequest(this IHttpRequest @this, long contentLength, string entityTag, DateTime lastModifiedUtc, out long start, out long upperBound)
        {
            start = 0;
            upperBound = contentLength - 1;
            if (@this.HttpVerb != HttpVerb.Get)
                return false;
            var rangeHeader = @this.Headers.Get(HttpHeaderNames.Range);
            if (rangeHeader == null)
                return false;
            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;
            }
            if (!RangeHeaderValue.TryParse(rangeHeader, out var range))
                return false;
            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;
        }
public static bool IsRangeRequest ( this IHttpRequest @this , long contentLength , string entityTag , DateTime lastModifiedUtc , out long start , out long upperBound ) { start = 0 ; upperBound = contentLength - 1 ; if ( @this . HttpVerb != HttpVerb . Get ) return false ; var rangeHeader = @this . Headers . Get ( HttpHeaderNames . Range ) ; if ( rangeHeader == null ) return false ; 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 ; } if ( ! RangeHeaderValue . TryParse ( rangeHeader , out var range ) ) return false ; 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 ; }
Checks whether a Range206 Partial ContentSee RFC7233
Checks whether a Range206 Partial ContentSee RFC7233
// RFC7233, Section 3.1: // "A server MUST ignore a Range header field received with a request method other than GET." // No Range header, no partial content. // 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." // Ignore the Range request header if it cannot be parsed successfully. // EmbedIO does not support multipart/byteranges responses (yet), // thus ignore range requests that specify one range.
This method returns  if the following conditions are satisfied:>the request's HTTP method is GET>a Range>either no If-Range, or a UTC date and time
equal to ;>the Range>the specified range is entirely contained in the range from 0 to  - 1.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  - 1, this method does not return;
it throws a  instead.If any of the other conditions are not satisfied, this method returns .
This method returns if the following conditions are satisfied : > the request ' s HTTP method is GET > a Range > either no If - Range or a UTC date and time equal to ; > the Range > the specified range is entirely contained in the range from 0 to - 1 . 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 - 1 this method does not return ; it throws a instead . If any of the other conditions are not satisfied this method returns .
IHttpRequest
this
contentLength
long
The total length, in bytes, of the response entity, i.e.
what would be sent in a 200 OK
The total length in bytes of the response entity i . e . what would be sent in a 200 OK
entityTag
string
An entity tag representing the response entity. This value is checked against
the If-Range
An entity tag representing the response entity . This value is checked against the If - Range
lastModifiedUtc
DateTime
The date and time value, in Coordinated Universal Time,
expressing the last modification time of the resource entity. This value is checked against
the If-Range
The date and time value in Coordinated Universal Time expressing the last modification time of the resource entity . This value is checked against the If - Range
long
out
this
The  on which this method is called.
The on which this method is called .
start
When this method returns , the start of the requested byte range.
This parameter is passed uninitialized.
When this method returns the start of the requested byte range . This parameter is passed uninitialized .
upperBound
When this method returns , the upper bound of the requested byte range.
This parameter is passed uninitialized.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 bytes=0-99
When this method returns the upper bound of the requested byte range . This parameter is passed uninitialized . 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 bytes = 0 - 99
remarks
According to RFC7233, Section 3.1200 OKmultipart/byterangesTo make clients aware that range requests are accepted for a resource, every 200 OK304 Not ModifiedAccept-Rangesbytes
According to RFC7233 Section 3 . 1200 OKmultipart / byterangesTo make clients aware that range requests are accepted for a resource every 200 OK304 Not ModifiedAccept - Rangesbytes