public override async Task ExecuteResultAsync(IWebDavResponse response, CancellationToken ct) { await base.ExecuteResultAsync(response, ct).ConfigureAwait(false); response.Headers["Accept-Ranges"] = new[] { "bytes" }; var properties = await _document.GetProperties(response.Dispatcher).ToList(ct).ConfigureAwait(false); var etagProperty = properties.OfType <GetETagProperty>().FirstOrDefault(); if (etagProperty != null) { var propValue = await etagProperty.GetValueAsync(ct).ConfigureAwait(false); response.Headers["ETag"] = new[] { propValue.ToString() }; } if (!_returnFile) { var lastModifiedProp = properties.OfType <LastModifiedProperty>().FirstOrDefault(); if (lastModifiedProp != null) { var propValue = await lastModifiedProp.GetValueAsync(ct).ConfigureAwait(false); response.Headers["Last-Modified"] = new[] { propValue.ToString("R") }; } return; } var views = new List <StreamView>(); try { foreach (var rangeItem in _rangeItems) { var baseStream = await _document.OpenReadAsync(ct).ConfigureAwait(false); var streamView = await StreamView .CreateAsync(baseStream, rangeItem.From, rangeItem.Length, ct) .ConfigureAwait(false); views.Add(streamView); } string contentType; var contentTypeProp = properties.OfType <GetContentTypeProperty>().FirstOrDefault(); if (contentTypeProp != null) { contentType = await contentTypeProp.GetValueAsync(ct).ConfigureAwait(false); } else { contentType = MimeTypesMap.DefaultMimeType; } HttpContent content; if (_rangeItems.Count == 1) { // No multipart content var rangeItem = _rangeItems.Single(); var streamView = views.Single(); content = new StreamContent(streamView); try { content.Headers.ContentRange = new ContentRangeHeaderValue(rangeItem.From, rangeItem.To, _document.Length); content.Headers.ContentLength = rangeItem.Length; } catch { content.Dispose(); throw; } content.Headers.ContentType = MediaTypeHeaderValue.Parse(contentType); } else { // Multipart content var multipart = new MultipartContent("byteranges"); try { var index = 0; foreach (var rangeItem in _rangeItems) { var streamView = views[index++]; var partContent = new StreamContent(streamView); partContent.Headers.ContentRange = new ContentRangeHeaderValue(rangeItem.From, rangeItem.To, _document.Length); partContent.Headers.ContentType = MediaTypeHeaderValue.Parse(contentType); partContent.Headers.ContentLength = rangeItem.Length; multipart.Add(partContent); } } catch { multipart.Dispose(); throw; } content = multipart; } using (content) { await SetPropertiesToContentHeaderAsync(content, properties, ct) .ConfigureAwait(false); foreach (var header in content.Headers) { response.Headers.Add(header.Key, header.Value.ToArray()); } await content.CopyToAsync(response.Body).ConfigureAwait(false); } } finally { foreach (var streamView in views) { streamView.Dispose(); } } }
public override async Task ExecuteResultAsync(IWebDavResponse response, CancellationToken ct) { await base.ExecuteResultAsync(response, ct); response.Headers["Accept-Ranges"] = new[] { "bytes" }; var properties = await _document.GetProperties(response.Dispatcher).ToList(ct); var etagProperty = properties.OfType <GetETagProperty>().FirstOrDefault(); if (etagProperty != null) { var propValue = await etagProperty.GetValueAsync(ct); response.Headers["ETag"] = new[] { propValue.ToString() }; } if (!_returnFile) { var lastModifiedProp = properties.OfType <LastModifiedProperty>().FirstOrDefault(); if (lastModifiedProp != null) { var propValue = await lastModifiedProp.GetValueAsync(ct); response.Headers["Last-Modified"] = new[] { propValue.ToString("R") }; } return; } var views = new List <StreamView>(); try { foreach (var rangeItem in _rangeItems) { var baseStream = await _document.OpenReadAsync(ct); var streamView = await StreamView .CreateAsync(baseStream, rangeItem.From, rangeItem.Length, ct) ; views.Add(streamView); } string contentType; var contentTypeProp = properties.OfType <GetContentTypeProperty>().FirstOrDefault(); if (contentTypeProp != null) { contentType = await contentTypeProp.GetValueAsync(ct); } else { contentType = MimeTypesMap.DefaultMimeType; } if (_rangeItems.Count == 1) { // No multipart content var rangeItem = _rangeItems.Single(); var streamView = views.Single(); using (var streamContent = new StreamContent(streamView)) { streamContent.Headers.ContentRange = new ContentRangeHeaderValue( rangeItem.From, rangeItem.To, _document.Length); streamContent.Headers.ContentLength = rangeItem.Length; streamContent.Headers.ContentType = MediaTypeHeaderValue.Parse(contentType); await SetPropertiesToContentHeaderAsync(streamContent, properties, ct) ; foreach (var header in streamContent.Headers) { response.Headers.Add(header.Key, header.Value.ToArray()); } // Use the CopyToAsync function of the stream itself, because // we're able to pass the cancellation token. This is a workaround // for issue dotnet/corefx#9071 and fixes FubarDevelopment/WebDavServer#47. await streamView.CopyToAsync(response.Body, 81920, ct) ; } } else { // Multipart content using (var multipart = new MultipartContent("byteranges")) { var index = 0; foreach (var rangeItem in _rangeItems) { var streamView = views[index++]; var partContent = new StreamContent(streamView); partContent.Headers.ContentRange = new ContentRangeHeaderValue( rangeItem.From, rangeItem.To, _document.Length); partContent.Headers.ContentType = MediaTypeHeaderValue.Parse(contentType); partContent.Headers.ContentLength = rangeItem.Length; multipart.Add(partContent); } await SetPropertiesToContentHeaderAsync(multipart, properties, ct) ; foreach (var header in multipart.Headers) { response.Headers.Add(header.Key, header.Value.ToArray()); } // TODO: Workaround for issue dotnet/corefx#9071 await multipart.CopyToAsync(response.Body); } } } finally { foreach (var streamView in views) { streamView.Dispose(); } } }