protected virtual Task WriteFileAsync( ActionContext context, FileStreamResult result, RangeItemHeaderValue?range, long rangeLength) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (result == null) { throw new ArgumentNullException(nameof(result)); } if (range != null && rangeLength == 0) { return(Task.CompletedTask); } if (range != null) { Logger.WritingRangeToBody(); } return(WriteFileAsync(context.HttpContext, result.FileStream, range, rangeLength)); }
internal static Task WriteFileAsyncInternal( HttpContext httpContext, IFileInfo fileInfo, RangeItemHeaderValue?range, long rangeLength, ILogger logger) { if (range != null && rangeLength == 0) { return(Task.CompletedTask); } var response = httpContext.Response; if (range != null) { logger.WritingRangeToBody(); } if (range != null) { return(response.SendFileAsync(fileInfo, offset: range.From ?? 0L, count: rangeLength)); } return(response.SendFileAsync(fileInfo, offset: 0, count: null)); }
public override bool Equals([NotNullWhen(true)] object? obj) { RangeItemHeaderValue? other = obj as RangeItemHeaderValue; if (other == null) { return false; } return ((_from == other._from) && (_to == other._to)); }
public override bool Equals(object?obj) { RangeItemHeaderValue?other = obj as RangeItemHeaderValue; if (other == null) { return(false); } return((_from == other._from) && (_to == other._to)); }
// Returns the length of a range list. E.g. "1-2, 3-4, 5-6" adds 3 ranges to 'rangeCollection'. Note that empty // list segments are allowed, e.g. ",1-2, , 3-4,,". internal static int GetRangeItemListLength( StringSegment input, int startIndex, ICollection <RangeItemHeaderValue> rangeCollection) { Contract.Requires(startIndex >= 0); Contract.Ensures((Contract.Result <int>() == 0) || (rangeCollection.Count > 0), "If we can parse the string, then we expect to have at least one range item."); if ((StringSegment.IsNullOrEmpty(input)) || (startIndex >= input.Length)) { return(0); } // Empty segments are allowed, so skip all delimiter-only segments (e.g. ", ,"). var separatorFound = false; var current = HeaderUtilities.GetNextNonEmptyOrWhitespaceIndex(input, startIndex, true, out separatorFound); // It's OK if we didn't find leading separator characters. Ignore 'separatorFound'. if (current == input.Length) { return(0); } RangeItemHeaderValue?range = null; while (true) { var rangeLength = GetRangeItemLength(input, current, out range); if (rangeLength == 0) { return(0); } rangeCollection !.Add(range !); current = current + rangeLength; current = HeaderUtilities.GetNextNonEmptyOrWhitespaceIndex(input, current, true, out separatorFound); // If the string is not consumed, we must have a delimiter, otherwise the string is not a valid // range list. if ((current < input.Length) && !separatorFound) { return(0); } if (current == input.Length) { return(current - startIndex); } } }
internal static Task WriteFileAsyncInternal( HttpContext httpContext, PhysicalFileResult result, RangeItemHeaderValue?range, long rangeLength, ILogger logger) { if (httpContext == null) { throw new ArgumentNullException(nameof(httpContext)); } if (result == null) { throw new ArgumentNullException(nameof(result)); } if (range != null && rangeLength == 0) { return(Task.CompletedTask); } var response = httpContext.Response; if (!Path.IsPathRooted(result.FileName)) { throw new NotSupportedException(Resources.FormatFileResult_PathNotRooted(result.FileName)); } if (range != null) { Log.WritingRangeToBody(logger); } if (range != null) { return(response.SendFileAsync(result.FileName, offset: range.From ?? 0L, count: rangeLength)); } return(response.SendFileAsync(result.FileName, offset: 0, count: null)); }
protected static async Task WriteFileAsync(HttpContext context, Stream fileStream, RangeItemHeaderValue?range, long rangeLength) { await WriteFileAsyncInternal(context, fileStream, range, rangeLength); }
protected override Task ExecuteCoreAsync(HttpContext httpContext, RangeItemHeaderValue?range, long rangeLength) { return(_streamWriterCallback(httpContext.Response.Body)); }
/// <inheritdoc/> protected virtual Task WriteFileAsync(ActionContext context, PhysicalFileResult result, RangeItemHeaderValue?range, long rangeLength) { return(WriteFileAsyncInternal(context.HttpContext, result, range, rangeLength, Logger)); }
/// <inheritdoc /> protected override Task WriteFileAsync(ActionContext context, PhysicalFileResult result, RangeItemHeaderValue?range, long rangeLength) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (result == null) { throw new ArgumentNullException(nameof(result)); } if (range != null && rangeLength == 0) { return(Task.CompletedTask); } // It's a bit of wasted IO to perform this check again, but non-symlinks shouldn't use this code if (!IsSymLink(result.FileName)) { return(base.WriteFileAsync(context, result, range, rangeLength)); } var response = context.HttpContext.Response; if (range != null) { return(SendFileAsync( result.FileName, response, offset: range.From ?? 0L, count: rangeLength)); } return(SendFileAsync( result.FileName, response, offset: 0, count: null)); }
/// <summary> /// Write the contents of the fileStream to the response body. /// </summary> /// <param name="context">The <see cref="HttpContext"/>.</param> /// <param name="fileStream">The fileStream to write.</param> /// <param name="range">The <see cref="RangeItemHeaderValue"/>.</param> /// <param name="rangeLength">The range length.</param> /// <returns>The async task.</returns> protected static async Task WriteFileAsync(HttpContext context, Stream fileStream, RangeItemHeaderValue?range, long rangeLength) { await FileResultHelper.WriteFileAsync(context, fileStream, range, rangeLength); }
protected override Task ExecuteCoreAsync(HttpContext context, RangeItemHeaderValue?range, long rangeLength) { return(FileResultHelper.WriteFileAsync(context, FileStream, range, rangeLength)); }
internal static int GetRangeItemLength(string?input, int startIndex, out RangeItemHeaderValue?parsedValue) { Debug.Assert(startIndex >= 0); // This parser parses number ranges: e.g. '1-2', '1-', '-2'. parsedValue = null; if (string.IsNullOrEmpty(input) || (startIndex >= input.Length)) { return(0); } // Caller must remove leading whitespace. If not, we'll return 0. int current = startIndex; // Try parse the first value of a value pair. int fromStartIndex = current; int fromLength = HttpRuleParser.GetNumberLength(input, current, false); if (fromLength > HttpRuleParser.MaxInt64Digits) { return(0); } current = current + fromLength; current = current + HttpRuleParser.GetWhitespaceLength(input, current); // After the first value, the '-' character must follow. if ((current == input.Length) || (input[current] != '-')) { // We need a '-' character otherwise this can't be a valid range. return(0); } current++; // skip the '-' character current = current + HttpRuleParser.GetWhitespaceLength(input, current); int toStartIndex = current; int toLength = 0; // If we didn't reach the end of the string, try parse the second value of the range. if (current < input.Length) { toLength = HttpRuleParser.GetNumberLength(input, current, false); if (toLength > HttpRuleParser.MaxInt64Digits) { return(0); } current = current + toLength; current = current + HttpRuleParser.GetWhitespaceLength(input, current); } if ((fromLength == 0) && (toLength == 0)) { return(0); // At least one value must be provided in order to be a valid range. } // Try convert first value to int64 long from = 0; if ((fromLength > 0) && !HeaderUtilities.TryParseInt64(input, fromStartIndex, fromLength, out from)) { return(0); } // Try convert second value to int64 long to = 0; if ((toLength > 0) && !HeaderUtilities.TryParseInt64(input, toStartIndex, toLength, out to)) { return(0); } // 'from' must not be greater than 'to' if ((fromLength > 0) && (toLength > 0) && (from > to)) { return(0); } parsedValue = new RangeItemHeaderValue((fromLength == 0 ? (long?)null : (long?)from), (toLength == 0 ? (long?)null : (long?)to)); return(current - startIndex); }
internal static async Task WriteFileAsync(HttpContext context, Stream fileStream, RangeItemHeaderValue?range, long rangeLength) { const int BufferSize = 64 * 1024; var outputStream = context.Response.Body; using (fileStream) { try { if (range == null) { await StreamCopyOperation.CopyToAsync(fileStream, outputStream, count : null, bufferSize : 64 * 1024, cancel : context.RequestAborted); } else { fileStream.Seek(range.From !.Value, SeekOrigin.Begin); await StreamCopyOperation.CopyToAsync(fileStream, outputStream, rangeLength, BufferSize, context.RequestAborted); } } catch (OperationCanceledException) { // Don't throw this exception, it's most likely caused by the client disconnecting. // However, if it was cancelled for any other reason we need to prevent empty responses. context.Abort(); } } }
internal static async Task WriteFileAsync(HttpContext context, ReadOnlyMemory <byte> buffer, RangeItemHeaderValue?range, long rangeLength) { var outputStream = context.Response.Body; try { if (range is null) { await outputStream.WriteAsync(buffer, context.RequestAborted); } else { var from = 0; var length = 0; checked { // Overflow should throw from = (int)range.From !.Value; length = (int)rangeLength; } await outputStream.WriteAsync(buffer.Slice(from, length), context.RequestAborted); } } catch (OperationCanceledException) { // Don't throw this exception, it's most likely caused by the client disconnecting. // However, if it was cancelled for any other reason we need to prevent empty responses. context.Abort(); } }
/// <inheritdoc/> protected virtual Task WriteFileAsync(ActionContext context, VirtualFileResult result, IFileInfo fileInfo, RangeItemHeaderValue?range, long rangeLength) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (result == null) { throw new ArgumentNullException(nameof(result)); } return(WriteFileAsyncInternal(context.HttpContext, fileInfo, range, rangeLength, Logger)); }
protected abstract Task ExecuteCoreAsync(HttpContext httpContext, RangeItemHeaderValue?range, long rangeLength);
/// <inheritdoc/> protected virtual Task WriteFileAsync(ActionContext context, VirtualFileResult result, IFileInfo fileInfo, RangeItemHeaderValue?range, long rangeLength) { if (context == null) { throw new ArgumentNullException(nameof(context)); } if (result == null) { throw new ArgumentNullException(nameof(result)); } if (range != null && rangeLength == 0) { return(Task.CompletedTask); } var response = context.HttpContext.Response; if (range != null) { Logger.WritingRangeToBody(); } if (range != null) { return(response.SendFileAsync(fileInfo, offset: range.From ?? 0L, count: rangeLength)); } return(response.SendFileAsync(fileInfo, offset: 0, count: null)); }