public ByteRangeStream(Stream innerStream, RangeItemHeaderValue range) : base(innerStream) { if (range == null) { throw new ArgumentNullException("range"); } if (!innerStream.CanSeek) { throw new ArgumentException("innerStream"); } if (innerStream.Length < 1) { throw new ArgumentOutOfRangeException("innerStream"); } if (range.From.HasValue && range.From.Value > innerStream.Length) { throw new ArgumentOutOfRangeException("range"); } // Ranges are inclusive so 0-9 means the first 10 bytes long maxLength = innerStream.Length - 1; long upperbounds; if (range.To.HasValue) { if (range.From.HasValue) { // e.g bytes=0-499 (the first 500 bytes offsets 0-499) upperbounds = Math.Min(innerStream.Position + range.To.Value, maxLength); _lowerbounds = innerStream.Position + range.From.Value; } else { // e.g bytes=-500 (the final 500 bytes) upperbounds = Math.Min(innerStream.Position + range.To.Value, maxLength); _lowerbounds = innerStream.Position; } } else { if (range.From.HasValue) { // e.g bytes=500- (from byte offset 500 and up) upperbounds = maxLength; _lowerbounds = innerStream.Position + range.From.Value; } else { // e.g. bytes=- (invalid so will never get here) upperbounds = maxLength; _lowerbounds = innerStream.Position; } } _totalCount = upperbounds - _lowerbounds + 1; ContentRange = new RangeItemHeaderValue( range.From ?? 0, range.To ?? innerStream.Length - innerStream.Position); }
protected virtual 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); } var response = context.HttpContext.Response; if (!Path.IsPathRooted(result.FileName)) { throw new NotSupportedException(Resources.FormatFileResult_PathNotRooted(result.FileName)); } var sendFile = response.HttpContext.Features.Get <IHttpSendFileFeature>(); if (sendFile != null) { if (range != null) { return(sendFile.SendFileAsync( result.FileName, offset: range.From ?? 0L, count: rangeLength, cancellation: default(CancellationToken))); } return(sendFile.SendFileAsync( result.FileName, offset: 0, count: null, cancellation: default(CancellationToken))); } return(WriteFileAsync(context.HttpContext, GetFileStream(result.FileName), range, rangeLength)); }
protected static async Task WriteFileAsync(HttpContext context, Stream fileStream, RangeItemHeaderValue range, long rangeLength) { var outputStream = context.Response.Body; using (fileStream) { try { if (range == null) { await StreamCopyOperation.CopyToAsync(fileStream, outputStream, count : null, bufferSize : BufferSize, 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(); } } }
public IHttpActionResult Get([FromUri] string filename) { string path = HttpContext.Current.Server.MapPath("~/" + filename); if (!File.Exists(path)) { return(NotFound()); } try { MemoryStream responseStream = new MemoryStream(); Stream fileStream = File.Open(path, FileMode.Open); bool fullContent = true; if (this.Request.Headers.Range != null) { fullContent = false; // Currently we only support a single range. RangeItemHeaderValue range = this.Request.Headers.Range.Ranges.First(); // From specified, so seek to the requested position. if (range.From != null) { fileStream.Seek(range.From.Value, SeekOrigin.Begin); // In this case, actually the complete file will be returned. if (range.From == 0 && (range.To == null || range.To >= fileStream.Length)) { fileStream.CopyTo(responseStream); fullContent = true; } } if (range.To != null) { // 10-20, return the range. if (range.From != null) { long? rangeLength = range.To - range.From; int length = (int)Math.Min(rangeLength.Value, fileStream.Length - range.From.Value); byte[] buffer = new byte[length]; fileStream.Read(buffer, 0, length); responseStream.Write(buffer, 0, length); } // -20, return the bytes from beginning to the specified value. else { int length = (int)Math.Min(range.To.Value, fileStream.Length); byte[] buffer = new byte[length]; fileStream.Read(buffer, 0, length); responseStream.Write(buffer, 0, length); } } // No Range.To else { // 10-, return from the specified value to the end of file. if (range.From != null) { if (range.From < fileStream.Length) { int length = (int)(fileStream.Length - range.From.Value); byte[] buffer = new byte[length]; fileStream.Read(buffer, 0, length); responseStream.Write(buffer, 0, length); } } } } // No Range header. Return the complete file. else { fileStream.CopyTo(responseStream); } fileStream.Close(); responseStream.Position = 0; HttpResponseMessage response = new HttpResponseMessage(); response.StatusCode = fullContent ? HttpStatusCode.OK : HttpStatusCode.PartialContent; response.Content = new StreamContent(responseStream); return(Ok(response)); } catch (IOException) { return(InternalServerError()); } catch (Exception) { return(InternalServerError()); } }
private static void CheckInvalidGetRangeItemListLength(string input, int startIndex) { List <RangeItemHeaderValue> ranges = new List <RangeItemHeaderValue>(); Assert.Equal(0, RangeItemHeaderValue.GetRangeItemListLength(input, startIndex, ranges)); }
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); } return(WriteFileAsync(context.HttpContext, result.FileStream, range, rangeLength)); }
public HttpResponseMessage getCustomDict() { HttpResponseMessage response = new HttpResponseMessage(); string filepath = AppDomain.CurrentDomain.BaseDirectory; string filename = filepath + "\\Dicts\\updict.dic"; FileInfo fileinfo = new FileInfo(filename); if (fileinfo == null) { throw new HttpResponseException(HttpStatusCode.NotFound); } string etag = string.Format("\"{0}\"", GetMD5.GetMD5HashFromFile(filename)); var tag = Request.Headers.IfNoneMatch.FirstOrDefault(); if (Request.Headers.IfModifiedSince.HasValue && tag != null && tag.Tag == etag) { response.StatusCode = HttpStatusCode.NotModified; } else { FileStream fs = fileinfo.OpenRead(); MemoryStream responseStream = new MemoryStream(); bool fullContent = true; if (this.Request.Headers.Range != null) { fullContent = false; RangeItemHeaderValue range = this.Request.Headers.Range.Ranges.First(); if (range.From != null) { fs.Seek(range.From.Value, SeekOrigin.Begin); if (range.From == 0 && (range.To == null || range.To >= fs.Length)) { fs.CopyTo(responseStream); fullContent = true; } } if (range.To != null) { if (range.From != null) { long? rangeLength = range.To - range.From; int length = (int)Math.Min(rangeLength.Value, fs.Length - range.From.Value); byte[] buffer = new byte[length]; fs.Read(buffer, 0, length); responseStream.Write(buffer, 0, length); } else { int length = (int)Math.Min(range.To.Value, fs.Length); byte[] buffer = new byte[length]; fs.Read(buffer, 0, length); responseStream.Write(buffer, 0, length); } } else { if (range.From != null) { if (range.From < fs.Length) { int length = (int)(fs.Length - range.From.Value); byte[] buffer = new byte[length]; fs.Read(buffer, 0, length); responseStream.Write(buffer, 0, length); } } } } else { fs.CopyTo(responseStream); } fs.Close(); responseStream.Position = 0; response.StatusCode = fullContent ? HttpStatusCode.OK : HttpStatusCode.PartialContent; response.Content = new StreamContent(responseStream); response.Headers.ETag = new EntityTagHeaderValue(etag); response.Headers.CacheControl = new CacheControlHeaderValue(); response.Headers.CacheControl.Public = true; response.Headers.CacheControl.MaxAge = TimeSpan.FromHours(24); response.Content.Headers.Expires = DateTimeOffset.Now.AddDays(1); response.Content.Headers.LastModified = fileinfo.LastWriteTime; } return(response); }
private async Task SendResponseAsync(PreconditionState state, HttpContext context, EntityTagHeaderValue etag, DateTimeOffset lastModified, string contentType, IFileInfo fileInfo) { switch (state) { //304 Not Modified case PreconditionState.NotModified: { context.SetResponseHeaders(304, etag, lastModified, contentType, fileInfo.Length); break; } //416 Precondition Failded case PreconditionState.PreconditionFailed: { context.SetResponseHeaders(412, etag, lastModified, contentType, fileInfo.Length); break; } case PreconditionState.Unspecified: case PreconditionState.ShouldProcess: { //200 OK if (context.UseMethods("HEAD")) { context.SetResponseHeaders(200, etag, lastModified, contentType, fileInfo.Length); return; } IEnumerable <RangeItemHeaderValue> ranges; if (context.IsRangeRequest() && this.TryGetRanges(context, lastModified, etag, fileInfo.Length, out ranges)) { RangeItemHeaderValue range = ranges.FirstOrDefault(); //416 if (null == range) { context.SetResponseHeaders(416, etag, lastModified, contentType, fileInfo.Length); return; } else { //206 Partial Content context.SetResponseHeaders(206, etag, lastModified, contentType, fileInfo.Length, range); context.Response.GetTypedHeaders().ContentRange = new ContentRangeHeaderValue(range.From.Value, range.To.Value, fileInfo.Length); using (var stream = fileInfo.CreateReadStream()) { stream.Seek(range.From.Value, SeekOrigin.Begin); await StreamCopyOperation.CopyToAsync(stream, context.Response.Body, range.To - range.From + 1, context.RequestAborted); } return; } } //200 OK context.SetResponseHeaders(200, etag, lastModified, contentType, fileInfo.Length); using (Stream stream = fileInfo.CreateReadStream()) { await StreamCopyOperation.CopyToAsync(stream, context.Response.Body, fileInfo.Length, context.RequestAborted); } break; } } }
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; var physicalPath = fileInfo.PhysicalPath; if (range != null) { Logger.WritingRangeToBody(); } var sendFile = response.HttpContext.Features.Get <IHttpSendFileFeature>(); if (sendFile != null && !string.IsNullOrEmpty(physicalPath)) { if (range != null) { return(sendFile.SendFileAsync( physicalPath, offset: range.From ?? 0L, count: rangeLength, cancellation: default(CancellationToken))); } return(sendFile.SendFileAsync( physicalPath, offset: 0, count: null, cancellation: default(CancellationToken))); } return(WriteFileAsync(context.HttpContext, GetFileStream(fileInfo), range, rangeLength)); }
public HttpResponseMessage Download(string fileName) { var fileuploadPath = @"D:\TestZip"; string path = Path.Combine(fileuploadPath, fileName); if (!File.Exists(path)) { throw new HttpResponseException(HttpStatusCode.NotFound); } //try //{ bool fullContent = true; MemoryStream responseStream = new MemoryStream(); Stream fileStream = File.Open(path, FileMode.Open); if (this.Request.Headers.Range != null) { fullContent = false; // Currently we only support a single range. RangeItemHeaderValue range = this.Request.Headers.Range.Ranges.First(); // From specified, so seek to the requested position. if (range.From != null) { fileStream.Seek(range.From.Value, SeekOrigin.Begin); // In this case, actually the complete file will be returned. if (range.From == 0 && (range.To == null || range.To >= fileStream.Length)) { fileStream.CopyTo(responseStream); fullContent = true; } } if (range.To != null) { // 10-20, return the range. if (range.From != null) { long? rangeLength = range.To - range.From; int length = (int)Math.Min(rangeLength.Value, fileStream.Length - range.From.Value); byte[] buffer = new byte[length]; fileStream.Read(buffer, 0, length); responseStream.Write(buffer, 0, length); } // -20, return the bytes from beginning to the specified value. else { int length = (int)Math.Min(range.To.Value, fileStream.Length); byte[] buffer = new byte[length]; fileStream.Read(buffer, 0, length); responseStream.Write(buffer, 0, length); } } // No Range.To else { // 10-, return from the specified value to the end of file. if (range.From != null) { if (range.From < fileStream.Length) { int length = (int)(fileStream.Length - range.From.Value); byte[] buffer = new byte[length]; fileStream.Read(buffer, 0, length); responseStream.Write(buffer, 0, length); } } } } // No Range header. Return the complete file. else { fileStream.CopyTo(responseStream); } fileStream.Close(); responseStream.Position = 0; HttpResponseMessage response = new HttpResponseMessage(); response.StatusCode = fullContent ? HttpStatusCode.OK : HttpStatusCode.PartialContent; response.Content = new StreamContent(responseStream); return(response); //} //catch (IOException) //{ // throw new HttpResponseException(HttpStatusCode.InternalServerError); //} }
public void Ctor_ThrowsOnNullInnerStream() { var range = new RangeItemHeaderValue(0, 10); Assert.ThrowsArgumentNull(() => new ByteRangeStream(innerStream: null, range: range), "innerStream"); }
public async Task <HttpResponseMessage> StreamingResource([FromUri] string id) { using (var db = new OnlineMusicEntities()) { var resource = (from r in db.Resources where r.Id == id select r).FirstOrDefault(); if (resource == null) { return(Request.CreateErrorResponse(HttpStatusCode.NotFound, "Không tìm thấy resource")); } stream = await services.Stream(id); var mediaType = "image/jpg"; if (resource.Type == (int)ResourceTypeManager.Audio) { mediaType = "audio/mpeg"; } else if (resource.Type == (int)ResourceTypeManager.Video) { mediaType = "video/mp4"; } RangeHeaderValue range = Request.Headers.Range; if (range != null) { try { // Convert percent to bytes if (range.Unit == "percent" && range.Ranges.Count > 0) { Request.Headers.Range.Unit = "bytes"; var value = range.Ranges.First(); long?from = value.From != null ? stream.Length * value.From / 100 : null; long?to = value.To != null ? stream.Length * value.To / 100 : null; RangeItemHeaderValue newValue = new RangeItemHeaderValue(from, to); Request.Headers.Range.Ranges.Remove(value); Request.Headers.Range.Ranges.Add(newValue); } HttpResponseMessage partialResponse = Request.CreateResponse(HttpStatusCode.PartialContent); partialResponse.Content = new ByteRangeStreamContent(stream, Request.Headers.Range, mediaType); return(partialResponse); } catch (Exception ex) { return(Request.CreateErrorResponse(HttpStatusCode.InternalServerError, ex.Message)); } } else { HttpContent content; if (resource.Type == (int)ResourceTypeManager.Video) { content = new PushStreamContent((Func <Stream, HttpContent, TransportContext, Task>)WriteToStream, new MediaTypeHeaderValue(mediaType)); } else { content = new StreamContent(stream); } var response = Request.CreateResponse(HttpStatusCode.OK); response.Content = content; response.Content.Headers.ContentLength = stream.Length; response.Content.Headers.ContentType = new MediaTypeHeaderValue(mediaType); return(response); } } }
internal static int GetRangeItemLength(StringSegment input, int startIndex, out RangeItemHeaderValue?parsedValue) { Contract.Requires(startIndex >= 0); // This parser parses number ranges: e.g. '1-2', '1-', '-2'. parsedValue = null; if (StringSegment.IsNullOrEmpty(input) || (startIndex >= input.Length)) { return(0); } // Caller must remove leading whitespaces. If not, we'll return 0. var current = startIndex; // Try parse the first value of a value pair. var fromStartIndex = current; var 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); var toStartIndex = current; var 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.TryParseNonNegativeInt64(input.Subsegment(fromStartIndex, fromLength), out from)) { return(0); } // Try convert second value to int64 long to = 0; if ((toLength > 0) && !HeaderUtilities.TryParseNonNegativeInt64(input.Subsegment(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); }
/// <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)); }