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); }
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"); }
public void TryParse_SetOfInvalidValueStrings_ReturnsFalse(string?input) { Assert.False(ContentRangeHeaderValue.TryParse(input, out var result)); Assert.Null(result); }
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); }
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"); } } }