private void CheckValidTryParse(string input, ContentRangeHeaderValue expectedResult)
        {
            ContentRangeHeaderValue result = null;

            Assert.True(ContentRangeHeaderValue.TryParse(input, out result));
            Assert.Equal(expectedResult, result);
        }
        private void CheckInvalidTryParse(string input)
        {
            ContentRangeHeaderValue result = null;

            Assert.False(ContentRangeHeaderValue.TryParse(input, out result));
            Assert.Null(result);
        }
Example #3
0
    public void TryParse_SetOfValidValueStrings_ParsedCorrectly()
    {
        CheckValidTryParse(" bytes 1-2/3 ", new ContentRangeHeaderValue(1, 2, 3));
        CheckValidTryParse("bytes  *  /  3", new ContentRangeHeaderValue(3));

        CheckValidTryParse(" custom 1234567890123456789-1234567890123456799/*",
                           new ContentRangeHeaderValue(1234567890123456789, 1234567890123456799)
        {
            Unit = "custom"
        });

        CheckValidTryParse(" custom * / 123 ",
                           new ContentRangeHeaderValue(123)
        {
            Unit = "custom"
        });

        // Note that we don't have a public constructor for value 'bytes */*' since the RFC doesn't mention a
        // scenario for it. However, if a server returns this value, we're flexible and accept it.
        Assert.True(ContentRangeHeaderValue.TryParse("bytes */*", out var result));
        Assert.Equal("bytes", result.Unit);
        Assert.Null(result.From);
        Assert.Null(result.To);
        Assert.Null(result.Length);
        Assert.False(result.HasRange, "HasRange");
        Assert.False(result.HasLength, "HasLength");
    }
        public void TryParse_Invalid()
        {
            ContentRangeHeaderValue res;

            Assert.IsFalse(ContentRangeHeaderValue.TryParse("", out res), "#1");
            Assert.IsNull(res, "#2");
        }
        public void TryParse()
        {
            ContentRangeHeaderValue res;

            Assert.IsTrue(ContentRangeHeaderValue.TryParse("b 1-10/*", out res), "#1");
            Assert.AreEqual(1, res.From, "#2");
            Assert.AreEqual(10, res.To, "#3");
        }
Example #6
0
 public void TryParse_SetOfInvalidValueStrings_ReturnsFalse(string?input)
 {
     Assert.False(ContentRangeHeaderValue.TryParse(input, out var result));
     Assert.Null(result);
 }
Example #7
0
        private ParserState ProcessRequest(HttpRequestMessageBuilder request, ParserState currentState, string content)
        {
            switch (currentState)
            {
            case ParserState.RequestLine:
                // From RFC2616: "In the interest of robustness, servers SHOULD ignore any empty line(s) received where a Request-Line is expected."
                if (content.Length == 0)
                {
                    return(currentState);
                }

                var requestLine = content.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

                // Verbs are case-sensitive
                switch (requestLine.Length > 0 ? requestLine[0] : null)
                {
                case "OPTIONS":
                    request.Method = HttpMethod.Options;
                    break;

                case "GET":
                    request.Method = HttpMethod.Get;
                    break;

                case "HEAD":
                    request.Method = HttpMethod.Head;
                    break;

                case "POST":
                    request.Method = HttpMethod.Post;
                    break;

                case "PUT":
                    request.Method = HttpMethod.Put;
                    break;

                case "DELETE":
                    request.Method = HttpMethod.Delete;
                    break;

                case "TRACE":
                    request.Method = HttpMethod.Trace;
                    break;

                default: break;
                }

                request.RequestUri = ResolveTargetUri(requestLine.Length > 1 ? requestLine[1] : "/");

                var     protocolVersion = Regex.Match(requestLine.Length > 2 ? requestLine[2] : null, "HTTP/(?<version>.*)").Groups["version"].Value;
                Version version;
                if (Version.TryParse(protocolVersion, out version))
                {
                    request.Version = version;
                }

                return(ParserState.RequestHeaders);

            case ParserState.RequestHeaders:
                // empty line signals end of request header
                if (content.Length > CrLf.Length)
                {
                    // Header names are case-insensitive
                    var header      = content.Split(new[] { ':' }, 2, StringSplitOptions.RemoveEmptyEntries);
                    var headerName  = header.Length > 0 ? header[0].Trim() : null;
                    var headerValue = header.Length > 1 ? header[1].Trim() : null;
                    if (headerName != null && headerValue != null)
                    {
                        switch (headerName.ToUpperInvariant())
                        {
                        case "RANGE":
                            // fixes issue in HttpClient for WP where a Range header with no upper range
                            // results in an InvalidOperationException - "Nullable object must have a value"
                            if (headerValue.EndsWith("-"))
                            {
                                headerValue += long.MaxValue.ToString();
                            }

                            request.Headers.Add(headerName, headerValue);
                            break;

                        case "REFERER":
                            headerValue = ResolveTargetUri(headerValue).AbsoluteUri;
                            request.Headers.Add(headerName, headerValue);
                            break;

                        case "HOST":
                            break;

                        case "CONNECTION":
                            break;

                        case "ALLOW":
                        case "CONTENT-ENCODING":
                        case "CONTENT-LANGUAGE":
                            request.ContentHeaders[headerName] = headerValue;
                            break;

                        case "CONTENT-DISPOSITION":
                            ContentDispositionHeaderValue contentDisposition;
                            if (ContentDispositionHeaderValue.TryParse(headerValue, out contentDisposition))
                            {
                                request.ContentHeaders[headerName] = contentDisposition;
                            }

                            break;

                        case "CONTENT-LENGTH":
                            long contentLength;
                            if (long.TryParse(headerValue, out contentLength))
                            {
                                request.ContentHeaders[headerName] = contentLength;
                            }

                            break;

                        case "CONTENT-LOCATION":
                            var contentLocation = ResolveTargetUri(headerValue).AbsoluteUri;
                            request.ContentHeaders[headerName] = contentLocation;
                            break;

                        case "CONTENT-MD5":
                            // currently not supported
                            break;

                        case "CONTENT-RANGE":
                            ContentRangeHeaderValue contentRange;
                            if (ContentRangeHeaderValue.TryParse(headerValue, out contentRange))
                            {
                                request.ContentHeaders[headerName] = contentRange;
                            }

                            break;

                        case "CONTENT-TYPE":
                            MediaTypeHeaderValue contentType;
                            if (MediaTypeHeaderValue.TryParse(headerValue, out contentType))
                            {
                                request.ContentHeaders[headerName] = contentType;
                            }

                            break;

                        case "CONTENT-EXPIRES":
                        case "CONTENT-LASTMODIFIED":
                            DateTimeOffset expires;
                            if (DateTimeOffset.TryParse(headerValue, out expires))
                            {
                                request.ContentHeaders[headerName] = expires;
                            }

                            break;

                        case "USER-AGENT":
                            request.Headers.TryAddWithoutValidation("User-Agent", headerValue.Replace(")", "; WAT)"));
                            break;

                        case "COOKIE":
                            // filter out cookies for other domains
                            var filteredCookies = this.cookieManager.FilterCookiesForCurrentRequest(request.RequestUri, headerValue);
                            if (!string.IsNullOrWhiteSpace(filteredCookies))
                            {
                                request.Headers.Add(headerName, filteredCookies);
                            }

                            break;

                        default:
                            request.Headers.Add(headerName, headerValue);
                            break;
                        }
                    }
                }
                else
                {
                    currentState = ParserState.RequestBody;
                }

                break;

            case ParserState.RequestBody:
                request.Content = new StringContent(content);
                currentState    = ParserState.Complete;
                break;
            }

            return(currentState);
        }
Example #8
0
 protected static void SetHeaders(List <KeyValuePair <string, string> > headers, HttpResponseMessage message)
 {
     foreach (KeyValuePair <string, string> keyValuePair in headers)
     {
         string key  = keyValuePair.Key;
         string str1 = keyValuePair.Value;
         try
         {
             if (key == "Allow")
             {
                 foreach (string str2 in ExtendedHttpClientHandler.SplitOnCommaAndOrder(str1))
                 {
                     message.Content.Headers.Allow.Add(str2);
                 }
             }
             else if (key == "Content-Disposition")
             {
                 ContentDispositionHeaderValue parsedValue;
                 if (ContentDispositionHeaderValue.TryParse(str1, out parsedValue))
                 {
                     message.Content.Headers.ContentDisposition = parsedValue;
                 }
             }
             else if (key == "Content-Encoding")
             {
                 foreach (string str2 in ExtendedHttpClientHandler.SplitOnCommaAndOrder(str1))
                 {
                     message.Content.Headers.ContentEncoding.Add(str2);
                 }
             }
             else if (key == "Content-Language")
             {
                 foreach (string str2 in ExtendedHttpClientHandler.SplitOnCommaAndOrder(str1))
                 {
                     message.Content.Headers.ContentLanguage.Add(str2);
                 }
             }
             else if (key == "Content-Length")
             {
                 long result;
                 if (long.TryParse(str1, out result))
                 {
                     message.Content.Headers.ContentLength = new long?(result);
                 }
             }
             else if (key == "Content-Location")
             {
                 try
                 {
                     message.Content.Headers.ContentLocation = new Uri(str1);
                 }
                 catch
                 {
                 }
             }
             else if (!(key == "Content-MD5"))
             {
                 if (key == "Content-Range")
                 {
                     ContentRangeHeaderValue parsedValue;
                     if (ContentRangeHeaderValue.TryParse(str1, out parsedValue))
                     {
                         message.Content.Headers.ContentRange = parsedValue;
                     }
                 }
                 else if (key == "Content-Type")
                 {
                     MediaTypeHeaderValue parsedValue;
                     if (MediaTypeHeaderValue.TryParse(str1, out parsedValue))
                     {
                         message.Content.Headers.ContentType = parsedValue;
                     }
                 }
                 else if (key == "Expires")
                 {
                     double result;
                     if (double.TryParse(str1, out result))
                     {
                         message.Content.Headers.Expires = new DateTimeOffset?(DateTimeOffset.Now.AddSeconds(result));
                     }
                 }
                 else if (key == "LastModified")
                 {
                     DateTimeOffset result;
                     if (DateTimeOffset.TryParse(str1, out result))
                     {
                         message.Content.Headers.LastModified = new DateTimeOffset?(result);
                     }
                 }
                 else
                 {
                     message.Headers.Add(key, str1);
                 }
             }
         }
         catch (Exception ex)
         {
             throw new Exception(string.Format("{0} : {1} {2} Exception: {3}", (object)key, (object)str1, (object)Environment.NewLine, (object)ex.Message));
         }
     }
 }
        public async Task <MultipartPartStream> NextPart(CancellationToken?cancellationToken = null)
        {
            if (this.noMoreParts)
            {
                return(null);
            }

            if (this.baseStream == null)
            {
                this.baseStream = new BufferedStream(await this.response.Content.ReadAsStreamAsync(), 16384);
            }

            if (MultipartBoundary == null)
            {
                switch (this.response.StatusCode)
                {
                case System.Net.HttpStatusCode.OK:
                {
                    this.noMoreParts = true;
                    var stream = new MultipartPartStream(this.response.Content.Headers.ContentLength.Value, 0, this.response.Content.Headers.ContentLength.Value);
                    stream.AppendBaseStream(new ReadLengthLimitingStream(this.baseStream, this.response.Content.Headers.ContentLength.Value));
                    return(stream);
                }

                case System.Net.HttpStatusCode.PartialContent:
                    if (this.response.Content.Headers.ContentType.MediaType.ToLowerInvariant() != "multipart/byteranges")
                    {
                        this.noMoreParts = true;
                        var rangeHeader = this.response.Content.Headers.ContentRange;
                        var rangeLength = rangeHeader.To.Value + 1 - rangeHeader.From.Value;
                        var stream      = new MultipartPartStream(rangeHeader.Length.Value, rangeHeader.From.Value, rangeLength);
                        stream.AppendBaseStream(new ReadLengthLimitingStream(this.baseStream, rangeLength));
                        return(stream);
                    }
                    else
                    {
                        MultipartBoundary          = "--" + this.response.Content.Headers.ContentType.Parameters.Where(p => p.Name.ToLowerInvariant() == "boundary").First().Value;
                        this.multipartEndBoundary  = MultipartBoundary + "--";
                        this.multipartBufferStream = new();
                        this.multipartHeaderLines  = new();
                    }
                    break;

                default:
                    this.response.EnsureSuccessStatusCode();
                    throw new EndOfStreamException($"Unhandled success status code {this.response.StatusCode}");
                }
            }

            while (true)
            {
                if (cancellationToken.HasValue)
                {
                    cancellationToken.Value.ThrowIfCancellationRequested();
                }

                var eof = false;
                using (var buffer = ReusableByteBufferManager.GetBuffer())
                {
                    int readSize;
                    if (cancellationToken == null)
                    {
                        readSize = await this.baseStream.ReadAsync(buffer.Buffer, 0, buffer.Buffer.Length);
                    }
                    else
                    {
                        readSize = await this.baseStream.ReadAsync(buffer.Buffer, 0, buffer.Buffer.Length, (CancellationToken)cancellationToken);
                    }

                    if (readSize == 0)
                    {
                        eof = true;
                    }
                    else
                    {
                        this.multipartBufferStream.Feed(buffer.Buffer, 0, readSize);
                    }
                }

                for (int i = 0; i < this.multipartBufferStream.Length - 1; ++i)
                {
                    if (this.multipartBufferStream[i + 0] != '\r' || this.multipartBufferStream[i + 1] != '\n')
                    {
                        continue;
                    }

                    var isEmptyLine = i == 0;

                    if (isEmptyLine)
                    {
                        this.multipartBufferStream.Consume(null, 0, 2);
                    }
                    else
                    {
                        using var buffer = ReusableByteBufferManager.GetBuffer();
                        if (i > buffer.Buffer.Length)
                        {
                            throw new IOException($"Multipart header line is too long ({i} bytes)");
                        }

                        this.multipartBufferStream.Consume(buffer.Buffer, 0, i + 2);
                        this.multipartHeaderLines.Add(Encoding.UTF8.GetString(buffer.Buffer, 0, i));
                    }
                    i = -1;

                    if (this.multipartHeaderLines.Count == 0)
                    {
                        continue;
                    }
                    if (this.multipartHeaderLines.Last() == this.multipartEndBoundary)
                    {
                        this.noMoreParts = true;
                        return(null);
                    }
                    if (!isEmptyLine)
                    {
                        continue;
                    }

                    ContentRangeHeaderValue rangeHeader = null;
                    foreach (var headerLine in this.multipartHeaderLines)
                    {
                        var kvs = headerLine.Split(new char[] { ':' }, 2);
                        if (kvs.Length != 2)
                        {
                            continue;
                        }
                        if (kvs[0].ToLowerInvariant() != "content-range")
                        {
                            continue;
                        }
                        if (ContentRangeHeaderValue.TryParse(kvs[1], out rangeHeader))
                        {
                            break;
                        }
                    }
                    if (rangeHeader == null)
                    {
                        throw new IOException("Content-Range not found in multipart part");
                    }

                    this.multipartHeaderLines.Clear();
                    var rangeFrom   = rangeHeader.From.Value;
                    var rangeLength = rangeHeader.To.Value - rangeFrom + 1;
                    var stream      = new MultipartPartStream(rangeHeader.Length.Value, rangeFrom, rangeLength);
                    stream.AppendBaseStream(new ConsumeLengthLimitingStream(this.multipartBufferStream, Math.Min(rangeLength, this.multipartBufferStream.Length)));
                    stream.AppendBaseStream(new ReadLengthLimitingStream(this.baseStream, stream.UnfulfilledBaseStreamLength));
                    return(stream);
                }

                if (eof && !this.noMoreParts)
                {
                    throw new EndOfStreamException("Reached premature EOF");
                }
            }
        }