Reorder SendFileAsync to match Write/FlushAsync
This commit is contained in:
parent
c2a1b8d17f
commit
c2f52db3a5
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
|
@ -81,6 +82,17 @@ namespace Microsoft.Net.Http.Server
|
|||
return tcs.Task;
|
||||
}
|
||||
|
||||
internal static ArraySegment<byte> GetChunkHeader(long size)
|
||||
{
|
||||
if (size < int.MaxValue)
|
||||
{
|
||||
return GetChunkHeader((int)size);
|
||||
}
|
||||
|
||||
// Greater than 2gb, perf is no longer our concern
|
||||
return new ArraySegment<byte>(Encoding.ASCII.GetBytes(size.ToString("X") + "\r\n"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A private utility routine to convert an integer to a chunk header,
|
||||
/// which is an ASCII hex number followed by a CRLF.The header is returned
|
||||
|
|
|
|||
|
|
@ -308,12 +308,13 @@ namespace Microsoft.Net.Http.Server
|
|||
// TODO: Verbose log
|
||||
try
|
||||
{
|
||||
if (_requestAbortSource != null)
|
||||
{
|
||||
_requestAbortSource.Dispose();
|
||||
}
|
||||
_requestAbortSource?.Dispose();
|
||||
Response.Dispose();
|
||||
}
|
||||
catch
|
||||
{
|
||||
Abort();
|
||||
}
|
||||
finally
|
||||
{
|
||||
Request.Dispose();
|
||||
|
|
@ -334,14 +335,19 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
_requestAbortSource.Cancel();
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogHelper.LogException(Logger, "Abort", ex);
|
||||
LogHelper.LogDebug(Logger, "Abort", ex);
|
||||
}
|
||||
_requestAbortSource.Dispose();
|
||||
}
|
||||
ForceCancelRequest();
|
||||
Request.Dispose();
|
||||
// Only Abort, Response.Dispose() tries a graceful flush
|
||||
Response.Abort();
|
||||
}
|
||||
|
||||
private static void Abort(object state)
|
||||
|
|
|
|||
|
|
@ -109,7 +109,6 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
get
|
||||
{
|
||||
CheckDisposed();
|
||||
EnsureResponseStream();
|
||||
return _nativeStream;
|
||||
}
|
||||
|
|
@ -245,6 +244,12 @@ namespace Microsoft.Net.Http.Server
|
|||
}
|
||||
}
|
||||
|
||||
internal void Abort()
|
||||
{
|
||||
// Update state for HasStarted. Do not attempt a graceful Dispose.
|
||||
_responseState = ResponseState.Closed;
|
||||
}
|
||||
|
||||
// should only be called from RequestContext
|
||||
internal void Dispose()
|
||||
{
|
||||
|
|
@ -685,14 +690,6 @@ namespace Microsoft.Net.Http.Server
|
|||
}
|
||||
}
|
||||
|
||||
private void CheckDisposed()
|
||||
{
|
||||
if (_responseState >= ResponseState.Closed)
|
||||
{
|
||||
throw new ObjectDisposedException(GetType().FullName);
|
||||
}
|
||||
}
|
||||
|
||||
internal void CancelLastWrite()
|
||||
{
|
||||
_nativeStream?.CancelLastWrite();
|
||||
|
|
|
|||
|
|
@ -132,12 +132,13 @@ namespace Microsoft.Net.Http.Server
|
|||
var started = _requestContext.Response.HasStarted;
|
||||
if (data.Count == 0 && started && !endOfRequest)
|
||||
{
|
||||
// Empty flush
|
||||
// No data to send and we've already sent the headers
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure all validation is performed before this computes the headers
|
||||
var flags = ComputeLeftToWrite(endOfRequest);
|
||||
if (!_inOpaqueMode && endOfRequest && _leftToWrite > data.Count)
|
||||
if (!_inOpaqueMode && endOfRequest && _leftToWrite > 0)
|
||||
{
|
||||
_requestContext.Abort();
|
||||
// This is logged rather than thrown because it is too late for an exception to be visible in user code.
|
||||
|
|
@ -303,7 +304,7 @@ namespace Microsoft.Net.Http.Server
|
|||
var started = _requestContext.Response.HasStarted;
|
||||
if (data.Count == 0 && started)
|
||||
{
|
||||
// Empty flush
|
||||
// No data to send and we've already sent the headers
|
||||
return Helpers.CompletedTask();
|
||||
}
|
||||
|
||||
|
|
@ -313,6 +314,7 @@ namespace Microsoft.Net.Http.Server
|
|||
return Helpers.CanceledTask<int>();
|
||||
}
|
||||
|
||||
// Make sure all validation is performed before this computes the headers
|
||||
var flags = ComputeLeftToWrite();
|
||||
if (_leftToWrite != data.Count)
|
||||
{
|
||||
|
|
@ -464,30 +466,31 @@ namespace Microsoft.Net.Http.Server
|
|||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
// Validates for null and bounds. Allows count == 0.
|
||||
// TODO: Verbose log parameters
|
||||
var data = new ArraySegment<byte>(buffer, offset, count);
|
||||
CheckDisposed();
|
||||
// TODO: Verbose log parameters
|
||||
|
||||
var contentLength = _requestContext.Response.ContentLength;
|
||||
if (contentLength.HasValue && !_requestContext.Response.HasComputedHeaders && contentLength.Value <= data.Count)
|
||||
{
|
||||
if (contentLength.Value < data.Count)
|
||||
{
|
||||
throw new InvalidOperationException("More bytes written than specified in the Content-Length header.");
|
||||
}
|
||||
}
|
||||
// The last write in a response that has already started, flush immediately
|
||||
else if (_requestContext.Response.HasComputedHeaders && _leftToWrite >= 0 && _leftToWrite <= data.Count)
|
||||
{
|
||||
if (_leftToWrite < data.Count)
|
||||
{
|
||||
throw new InvalidOperationException("More bytes written than specified in the Content-Length header.");
|
||||
}
|
||||
}
|
||||
CheckWriteCount(count);
|
||||
|
||||
FlushInternal(endOfRequest: false, data: data);
|
||||
}
|
||||
|
||||
private void CheckWriteCount(long? count)
|
||||
{
|
||||
var contentLength = _requestContext.Response.ContentLength;
|
||||
// First write with more bytes written than the entire content-length
|
||||
if (!_requestContext.Response.HasComputedHeaders && contentLength < count)
|
||||
{
|
||||
throw new InvalidOperationException("More bytes written than specified in the Content-Length header.");
|
||||
}
|
||||
// A write in a response that has already started where the count exceeds the remainder of the content-length
|
||||
else if (_requestContext.Response.HasComputedHeaders && _requestContext.Response.BoundaryType == BoundaryType.ContentLength
|
||||
&& _leftToWrite < count)
|
||||
{
|
||||
throw new InvalidOperationException("More bytes written than specified in the Content-Length header.");
|
||||
}
|
||||
}
|
||||
|
||||
#if NETSTANDARD1_3
|
||||
public IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback callback, object state)
|
||||
#else
|
||||
|
|
@ -512,26 +515,11 @@ namespace Microsoft.Net.Http.Server
|
|||
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
|
||||
{
|
||||
// Validates for null and bounds. Allows count == 0.
|
||||
// TODO: Verbose log parameters
|
||||
var data = new ArraySegment<byte>(buffer, offset, count);
|
||||
CheckDisposed();
|
||||
// TODO: Verbose log parameters
|
||||
|
||||
var contentLength = _requestContext.Response.ContentLength;
|
||||
if (contentLength.HasValue && !_requestContext.Response.HasComputedHeaders && contentLength.Value <= data.Count)
|
||||
{
|
||||
if (contentLength.Value < data.Count)
|
||||
{
|
||||
throw new InvalidOperationException("More bytes written than specified in the Content-Length header.");
|
||||
}
|
||||
}
|
||||
// The last write in a response that has already started, flush immediately
|
||||
else if (_requestContext.Response.HasComputedHeaders && _leftToWrite > 0 && _leftToWrite <= data.Count)
|
||||
{
|
||||
if (_leftToWrite < data.Count)
|
||||
{
|
||||
throw new InvalidOperationException("More bytes written than specified in the Content-Length header.");
|
||||
}
|
||||
}
|
||||
CheckWriteCount(count);
|
||||
|
||||
return FlushInternalAsync(data, cancellationToken);
|
||||
}
|
||||
|
|
@ -540,12 +528,15 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
// It's too expensive to validate the file attributes before opening the file. Open the file and then check the lengths.
|
||||
// This all happens inside of ResponseStreamAsyncResult.
|
||||
// TODO: Verbose log parameters
|
||||
if (string.IsNullOrWhiteSpace(fileName))
|
||||
{
|
||||
throw new ArgumentNullException("fileName");
|
||||
}
|
||||
CheckDisposed();
|
||||
|
||||
CheckWriteCount(count);
|
||||
|
||||
// We can't mix await and unsafe so separate the unsafe code into another method.
|
||||
await SendFileAsyncCore(fileName, offset, count, cancellationToken);
|
||||
}
|
||||
|
|
@ -557,43 +548,65 @@ namespace Microsoft.Net.Http.Server
|
|||
return Helpers.CompletedTask();
|
||||
}
|
||||
|
||||
var flags = ComputeLeftToWrite();
|
||||
if (count == 0 && _leftToWrite != 0)
|
||||
var started = _requestContext.Response.HasStarted;
|
||||
if (count == 0 && started)
|
||||
{
|
||||
// No data to send and we've already sent the headers
|
||||
return Helpers.CompletedTask();
|
||||
}
|
||||
|
||||
if (_leftToWrite >= 0 && count > _leftToWrite)
|
||||
{
|
||||
throw new InvalidOperationException(Resources.Exception_TooMuchWritten);
|
||||
}
|
||||
|
||||
if (cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
Abort(ThrowWriteExceptions);
|
||||
return Helpers.CanceledTask<int>();
|
||||
}
|
||||
// TODO: Verbose log
|
||||
|
||||
// We are setting buffer size to 1 to prevent FileStream from allocating it's internal buffer
|
||||
// It's too expensive to validate anything before opening the file. Open the file and then check the lengths.
|
||||
var fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize: 1,
|
||||
options: FileOptions.Asynchronous | FileOptions.SequentialScan); // Extremely expensive.
|
||||
|
||||
try
|
||||
{
|
||||
var length = fileStream.Length; // Expensive, only do it once
|
||||
if (!count.HasValue)
|
||||
{
|
||||
count = length - offset;
|
||||
}
|
||||
if (offset < 0 || offset > length)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(offset), offset, string.Empty);
|
||||
}
|
||||
if (count < 0 || count > length - offset)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(count), count, string.Empty);
|
||||
}
|
||||
|
||||
CheckWriteCount(count);
|
||||
}
|
||||
catch
|
||||
{
|
||||
fileStream.Dispose();
|
||||
throw;
|
||||
}
|
||||
|
||||
// Make sure all validation is performed before this computes the headers
|
||||
var flags = ComputeLeftToWrite();
|
||||
uint statusCode;
|
||||
uint bytesSent = 0;
|
||||
var started = _requestContext.Response.HasStarted;
|
||||
var chunked = _requestContext.Response.BoundaryType == BoundaryType.Chunked;
|
||||
var asyncResult = new ResponseStreamAsyncResult(this, fileName, offset, count, chunked, cancellationToken);
|
||||
var asyncResult = new ResponseStreamAsyncResult(this, fileStream, offset, count.Value, chunked, cancellationToken);
|
||||
|
||||
long bytesWritten;
|
||||
if (chunked)
|
||||
{
|
||||
bytesWritten = 0;
|
||||
}
|
||||
else if (count.HasValue)
|
||||
else
|
||||
{
|
||||
bytesWritten = count.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
bytesWritten = asyncResult.FileLength - offset;
|
||||
}
|
||||
|
||||
// Update _leftToWrite now so we can queue up additional calls to SendFileAsync.
|
||||
flags |= _leftToWrite == bytesWritten ? HttpApi.HTTP_FLAGS.NONE : HttpApi.HTTP_FLAGS.HTTP_SEND_RESPONSE_FLAG_MORE_DATA;
|
||||
UpdateWritenCount((uint)bytesWritten);
|
||||
|
|
|
|||
|
|
@ -114,33 +114,15 @@ namespace Microsoft.Net.Http.Server
|
|||
}
|
||||
}
|
||||
|
||||
internal ResponseStreamAsyncResult(ResponseStream responseStream, string fileName, long offset,
|
||||
long? count, bool chunked, CancellationToken cancellationToken)
|
||||
internal ResponseStreamAsyncResult(ResponseStream responseStream, FileStream fileStream, long offset,
|
||||
long count, bool chunked, CancellationToken cancellationToken)
|
||||
: this(responseStream, cancellationToken)
|
||||
{
|
||||
var boundHandle = responseStream.RequestContext.Server.RequestQueue.BoundHandle;
|
||||
|
||||
int bufferSize = 1024 * 64; // TODO: Validate buffer size choice.
|
||||
#if NETSTANDARD1_3
|
||||
_fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize /*, useAsync: true*/); // Extremely expensive.
|
||||
#else
|
||||
// It's too expensive to validate anything before opening the file. Open the file and then check the lengths.
|
||||
_fileStream = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, bufferSize,
|
||||
FileOptions.Asynchronous | FileOptions.SequentialScan); // Extremely expensive.
|
||||
#endif
|
||||
long length = _fileStream.Length; // Expensive
|
||||
if (offset < 0 || offset > length)
|
||||
{
|
||||
_fileStream.Dispose();
|
||||
throw new ArgumentOutOfRangeException("offset", offset, string.Empty);
|
||||
}
|
||||
if (count.HasValue && (count < 0 || count > length - offset))
|
||||
{
|
||||
_fileStream.Dispose();
|
||||
throw new ArgumentOutOfRangeException("count", count, string.Empty);
|
||||
}
|
||||
_fileStream = fileStream;
|
||||
|
||||
if (count == 0 || (!count.HasValue && _fileStream.Length == 0))
|
||||
if (count == 0)
|
||||
{
|
||||
_dataChunks = null;
|
||||
_overlapped = new SafeNativeOverlapped(boundHandle,
|
||||
|
|
@ -156,14 +138,14 @@ namespace Microsoft.Net.Http.Server
|
|||
var chunkHeaderBuffer = new ArraySegment<byte>();
|
||||
if (chunked)
|
||||
{
|
||||
chunkHeaderBuffer = Helpers.GetChunkHeader((int)(count ?? _fileStream.Length - offset));
|
||||
chunkHeaderBuffer = Helpers.GetChunkHeader(count);
|
||||
_dataChunks[0].DataChunkType = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromMemory;
|
||||
_dataChunks[0].fromMemory.BufferLength = (uint)chunkHeaderBuffer.Count;
|
||||
objectsToPin[0] = chunkHeaderBuffer.Array;
|
||||
|
||||
_dataChunks[1].DataChunkType = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromFileHandle;
|
||||
_dataChunks[1].fromFile.offset = (ulong)offset;
|
||||
_dataChunks[1].fromFile.count = (ulong)(count ?? -1);
|
||||
_dataChunks[1].fromFile.count = (ulong)count;
|
||||
_dataChunks[1].fromFile.fileHandle = _fileStream.SafeFileHandle.DangerousGetHandle();
|
||||
// Nothing to pin for the file handle.
|
||||
|
||||
|
|
@ -175,7 +157,7 @@ namespace Microsoft.Net.Http.Server
|
|||
{
|
||||
_dataChunks[0].DataChunkType = HttpApi.HTTP_DATA_CHUNK_TYPE.HttpDataChunkFromFileHandle;
|
||||
_dataChunks[0].fromFile.offset = (ulong)offset;
|
||||
_dataChunks[0].fromFile.count = (ulong)(count ?? -1);
|
||||
_dataChunks[0].fromFile.count = (ulong)count;
|
||||
_dataChunks[0].fromFile.fileHandle = _fileStream.SafeFileHandle.DangerousGetHandle();
|
||||
}
|
||||
|
||||
|
|
@ -248,11 +230,6 @@ namespace Microsoft.Net.Http.Server
|
|||
}
|
||||
}
|
||||
|
||||
internal long FileLength
|
||||
{
|
||||
get { return _fileStream == null ? 0 : _fileStream.Length; }
|
||||
}
|
||||
|
||||
internal bool EndCalled { get; set; }
|
||||
|
||||
internal void IOCompleted(uint errorCode)
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ namespace Microsoft.Net.Http.Server
|
|||
// returned from HttpReceiveClientCertificate when using the
|
||||
// FileCompletionNotificationModes.SkipCompletionPortOnSuccess flag.
|
||||
// This bug was only hit when the buffer passed into HttpReceiveClientCertificate
|
||||
// (1500 bytes initially) is tool small for the certificate.
|
||||
// (1500 bytes initially) is too small for the certificate.
|
||||
// Due to this bug in downlevel operating systems the FileCompletionNotificationModes.SkipCompletionPortOnSuccess
|
||||
// flag is only used on Win8 and later.
|
||||
internal static readonly bool SkipIOCPCallbackOnSuccess = ComNetOS.IsWin8orLater;
|
||||
|
|
|
|||
|
|
@ -221,12 +221,14 @@ namespace Microsoft.AspNetCore.Server.WebListener
|
|||
using (Utilities.CreateHttpServer(out address, async httpContext =>
|
||||
{
|
||||
var sendFile = httpContext.Features.Get<IHttpSendFileFeature>();
|
||||
await sendFile.SendFileAsync(AbsoluteFilePath, 1234567, null, CancellationToken.None);
|
||||
await Assert.ThrowsAsync<ArgumentOutOfRangeException>(() =>
|
||||
sendFile.SendFileAsync(AbsoluteFilePath, 1234567, null, CancellationToken.None));
|
||||
completed = true;
|
||||
}))
|
||||
{
|
||||
await Assert.ThrowsAsync<HttpRequestException>(() => SendRequestAsync(address));
|
||||
Assert.False(completed);
|
||||
var response = await SendRequestAsync(address);
|
||||
response.EnsureSuccessStatusCode();
|
||||
Assert.True(completed);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -238,12 +240,14 @@ namespace Microsoft.AspNetCore.Server.WebListener
|
|||
using (Utilities.CreateHttpServer(out address, async httpContext =>
|
||||
{
|
||||
var sendFile = httpContext.Features.Get<IHttpSendFileFeature>();
|
||||
await sendFile.SendFileAsync(AbsoluteFilePath, 0, 1234567, CancellationToken.None);
|
||||
await Assert.ThrowsAsync<ArgumentOutOfRangeException>(() =>
|
||||
sendFile.SendFileAsync(AbsoluteFilePath, 0, 1234567, CancellationToken.None));
|
||||
completed = true;
|
||||
}))
|
||||
{
|
||||
await Assert.ThrowsAsync<HttpRequestException>(() => SendRequestAsync(address));
|
||||
Assert.False(completed);
|
||||
var response = await SendRequestAsync(address);
|
||||
response.EnsureSuccessStatusCode();
|
||||
Assert.True(completed);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -30,14 +30,15 @@ namespace Microsoft.Net.Http.Server
|
|||
string address;
|
||||
using (var server = Utilities.CreateHttpServer(out address))
|
||||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.AcceptAsync();
|
||||
await Assert.ThrowsAsync<FileNotFoundException>(() =>
|
||||
context.Response.SendFileAsync("Missing.txt", 0, null, CancellationToken.None));
|
||||
context.Dispose();
|
||||
|
||||
HttpResponseMessage response = await responseTask;
|
||||
var response = await responseTask;
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -47,13 +48,13 @@ namespace Microsoft.Net.Http.Server
|
|||
string address;
|
||||
using (var server = Utilities.CreateHttpServer(out address))
|
||||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.AcceptAsync();
|
||||
await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None);
|
||||
context.Dispose();
|
||||
|
||||
HttpResponseMessage response = await responseTask;
|
||||
var response = await responseTask;
|
||||
Assert.Equal(200, (int)response.StatusCode);
|
||||
IEnumerable<string> ignored;
|
||||
Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length");
|
||||
|
|
@ -68,13 +69,13 @@ namespace Microsoft.Net.Http.Server
|
|||
string address;
|
||||
using (var server = Utilities.CreateHttpServer(out address))
|
||||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.AcceptAsync();
|
||||
await context.Response.SendFileAsync(RelativeFilePath, 0, null, CancellationToken.None);
|
||||
context.Dispose();
|
||||
|
||||
HttpResponseMessage response = await responseTask;
|
||||
var response = await responseTask;
|
||||
Assert.Equal(200, (int)response.StatusCode);
|
||||
IEnumerable<string> ignored;
|
||||
Assert.False(response.Content.Headers.TryGetValues("content-length", out ignored), "Content-Length");
|
||||
|
|
@ -89,13 +90,13 @@ namespace Microsoft.Net.Http.Server
|
|||
string address;
|
||||
using (var server = Utilities.CreateHttpServer(out address))
|
||||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.AcceptAsync();
|
||||
await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None);
|
||||
context.Dispose();
|
||||
|
||||
HttpResponseMessage response = await responseTask;
|
||||
var response = await responseTask;
|
||||
Assert.Equal(200, (int)response.StatusCode);
|
||||
IEnumerable<string> contentLength;
|
||||
Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length");
|
||||
|
|
@ -110,14 +111,14 @@ namespace Microsoft.Net.Http.Server
|
|||
string address;
|
||||
using (var server = Utilities.CreateHttpServer(out address))
|
||||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.AcceptAsync();
|
||||
await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None);
|
||||
await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None);
|
||||
context.Dispose();
|
||||
|
||||
HttpResponseMessage response = await responseTask;
|
||||
var response = await responseTask;
|
||||
Assert.Equal(200, (int)response.StatusCode);
|
||||
IEnumerable<string> contentLength;
|
||||
Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length");
|
||||
|
|
@ -132,13 +133,13 @@ namespace Microsoft.Net.Http.Server
|
|||
string address;
|
||||
using (var server = Utilities.CreateHttpServer(out address))
|
||||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.AcceptAsync();
|
||||
await context.Response.SendFileAsync(AbsoluteFilePath, 0, FileLength / 2, CancellationToken.None);
|
||||
context.Dispose();
|
||||
|
||||
HttpResponseMessage response = await responseTask;
|
||||
var response = await responseTask;
|
||||
Assert.Equal(200, (int)response.StatusCode);
|
||||
IEnumerable<string> contentLength;
|
||||
Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length");
|
||||
|
|
@ -153,14 +154,15 @@ namespace Microsoft.Net.Http.Server
|
|||
string address;
|
||||
using (var server = Utilities.CreateHttpServer(out address))
|
||||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.AcceptAsync();
|
||||
await Assert.ThrowsAsync<ArgumentOutOfRangeException>(
|
||||
() => context.Response.SendFileAsync(AbsoluteFilePath, 1234567, null, CancellationToken.None));
|
||||
context.Dispose();
|
||||
|
||||
HttpResponseMessage response = await responseTask;
|
||||
var response = await responseTask;
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -170,14 +172,15 @@ namespace Microsoft.Net.Http.Server
|
|||
string address;
|
||||
using (var server = Utilities.CreateHttpServer(out address))
|
||||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.AcceptAsync();
|
||||
await Assert.ThrowsAsync<ArgumentOutOfRangeException>(
|
||||
() => context.Response.SendFileAsync(AbsoluteFilePath, 0, 1234567, CancellationToken.None));
|
||||
context.Dispose();
|
||||
|
||||
HttpResponseMessage response = await responseTask;
|
||||
var response = await responseTask;
|
||||
response.EnsureSuccessStatusCode();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -187,13 +190,13 @@ namespace Microsoft.Net.Http.Server
|
|||
string address;
|
||||
using (var server = Utilities.CreateHttpServer(out address))
|
||||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.AcceptAsync();
|
||||
await context.Response.SendFileAsync(AbsoluteFilePath, 0, 0, CancellationToken.None);
|
||||
context.Dispose();
|
||||
|
||||
HttpResponseMessage response = await responseTask;
|
||||
var response = await responseTask;
|
||||
Assert.Equal(200, (int)response.StatusCode);
|
||||
IEnumerable<string> contentLength;
|
||||
Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length");
|
||||
|
|
@ -212,7 +215,7 @@ namespace Microsoft.Net.Http.Server
|
|||
string address;
|
||||
using (var server = Utilities.CreateHttpServer(out address))
|
||||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.AcceptAsync();
|
||||
await context.Response.SendFileAsync(emptyFilePath, 0, null, CancellationToken.None);
|
||||
|
|
@ -221,7 +224,7 @@ namespace Microsoft.Net.Http.Server
|
|||
context.Dispose();
|
||||
File.Delete(emptyFilePath);
|
||||
|
||||
HttpResponseMessage response = await responseTask;
|
||||
var response = await responseTask;
|
||||
Assert.Equal(200, (int)response.StatusCode);
|
||||
IEnumerable<string> contentLength;
|
||||
Assert.False(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length");
|
||||
|
|
@ -236,13 +239,13 @@ namespace Microsoft.Net.Http.Server
|
|||
string address;
|
||||
using (var server = Utilities.CreateHttpServer(out address))
|
||||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["Content-lenGth"] = FileLength.ToString();
|
||||
await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, CancellationToken.None);
|
||||
|
||||
HttpResponseMessage response = await responseTask;
|
||||
var response = await responseTask;
|
||||
Assert.Equal(200, (int)response.StatusCode);
|
||||
IEnumerable<string> contentLength;
|
||||
Assert.True(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length");
|
||||
|
|
@ -258,14 +261,14 @@ namespace Microsoft.Net.Http.Server
|
|||
string address;
|
||||
using (var server = Utilities.CreateHttpServer(out address))
|
||||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["Content-lenGth"] = "10";
|
||||
await context.Response.SendFileAsync(AbsoluteFilePath, 0, 10, CancellationToken.None);
|
||||
context.Dispose();
|
||||
|
||||
HttpResponseMessage response = await responseTask;
|
||||
var response = await responseTask;
|
||||
Assert.Equal(200, (int)response.StatusCode);
|
||||
IEnumerable<string> contentLength;
|
||||
Assert.True(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length");
|
||||
|
|
@ -281,14 +284,14 @@ namespace Microsoft.Net.Http.Server
|
|||
string address;
|
||||
using (var server = Utilities.CreateHttpServer(out address))
|
||||
{
|
||||
Task<HttpResponseMessage> responseTask = SendRequestAsync(address);
|
||||
var responseTask = SendRequestAsync(address);
|
||||
|
||||
var context = await server.AcceptAsync();
|
||||
context.Response.Headers["Content-lenGth"] = "0";
|
||||
await context.Response.SendFileAsync(AbsoluteFilePath, 0, 0, CancellationToken.None);
|
||||
context.Dispose();
|
||||
|
||||
HttpResponseMessage response = await responseTask;
|
||||
var response = await responseTask;
|
||||
Assert.Equal(200, (int)response.StatusCode);
|
||||
IEnumerable<string> contentLength;
|
||||
Assert.True(response.Content.Headers.TryGetValues("content-length", out contentLength), "Content-Length");
|
||||
|
|
@ -313,7 +316,7 @@ namespace Microsoft.Net.Http.Server
|
|||
await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token);
|
||||
context.Dispose();
|
||||
|
||||
HttpResponseMessage response = await responseTask;
|
||||
var response = await responseTask;
|
||||
Assert.Equal(200, (int)response.StatusCode);
|
||||
Assert.Equal(FileLength * 2, (await response.Content.ReadAsByteArrayAsync()).Length);
|
||||
}
|
||||
|
|
@ -335,7 +338,7 @@ namespace Microsoft.Net.Http.Server
|
|||
await context.Response.SendFileAsync(AbsoluteFilePath, 0, null, cts.Token);
|
||||
context.Dispose();
|
||||
|
||||
HttpResponseMessage response = await responseTask;
|
||||
var response = await responseTask;
|
||||
Assert.Equal(200, (int)response.StatusCode);
|
||||
Assert.Equal(FileLength * 2, (await response.Content.ReadAsByteArrayAsync()).Length);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue