3
3
4
4
using System ;
5
5
using System . Collections . Generic ;
6
+ using System . Diagnostics ;
6
7
using System . IO ;
7
8
using System . Linq ;
8
9
using System . Net ;
@@ -172,7 +173,7 @@ public int StatusCode
172
173
{
173
174
if ( HasResponseStarted )
174
175
{
175
- BadHttpResponse . ThrowException ( ResponseRejectionReasons . ValueCannotBeSetResponseStarted , ResponseRejectionParameter . StatusCode ) ;
176
+ ThrowResponseAlreadyStartedException ( nameof ( StatusCode ) ) ;
176
177
}
177
178
178
179
_statusCode = value ;
@@ -190,7 +191,7 @@ public string ReasonPhrase
190
191
{
191
192
if ( HasResponseStarted )
192
193
{
193
- BadHttpResponse . ThrowException ( ResponseRejectionReasons . ValueCannotBeSetResponseStarted , ResponseRejectionParameter . ReasonPhrase ) ;
194
+ ThrowResponseAlreadyStartedException ( nameof ( ReasonPhrase ) ) ;
194
195
}
195
196
196
197
_reasonPhrase = value ;
@@ -426,7 +427,7 @@ public void OnStarting(Func<object, Task> callback, object state)
426
427
{
427
428
if ( HasResponseStarted )
428
429
{
429
- BadHttpResponse . ThrowException ( ResponseRejectionReasons . OnStartingCannotBeSetResponseStarted , ResponseRejectionParameter . OnStarting ) ;
430
+ ThrowResponseAlreadyStartedException ( nameof ( OnStarting ) ) ;
430
431
}
431
432
432
433
if ( _onStarting == null )
@@ -513,7 +514,7 @@ public void Write(ArraySegment<byte> data)
513
514
{
514
515
ProduceStartAndFireOnStarting ( ) . GetAwaiter ( ) . GetResult ( ) ;
515
516
516
- if ( _canHaveBody )
517
+ if ( _canHaveBody || StatusCode == 101 )
517
518
{
518
519
if ( _autoChunk )
519
520
{
@@ -541,7 +542,7 @@ public Task WriteAsync(ArraySegment<byte> data, CancellationToken cancellationTo
541
542
return WriteAsyncAwaited ( data , cancellationToken ) ;
542
543
}
543
544
544
- if ( _canHaveBody )
545
+ if ( _canHaveBody || StatusCode == 101 )
545
546
{
546
547
if ( _autoChunk )
547
548
{
@@ -567,7 +568,7 @@ public async Task WriteAsyncAwaited(ArraySegment<byte> data, CancellationToken c
567
568
{
568
569
await ProduceStartAndFireOnStarting ( ) ;
569
570
570
- if ( _canHaveBody )
571
+ if ( _canHaveBody || StatusCode == 101 )
571
572
{
572
573
if ( _autoChunk )
573
574
{
@@ -587,7 +588,6 @@ public async Task WriteAsyncAwaited(ArraySegment<byte> data, CancellationToken c
587
588
HandleNonBodyResponseWrite ( data . Count ) ;
588
589
return ;
589
590
}
590
-
591
591
}
592
592
593
593
private void WriteChunked ( ArraySegment < byte > data )
@@ -700,11 +700,11 @@ protected Task ProduceEnd()
700
700
return TaskCache . CompletedTask ;
701
701
}
702
702
703
- // If the request was rejected, StatusCode has already been set by SetBadRequestState
703
+ // If the request was rejected, the error state has already been set by SetBadRequestState
704
704
if ( ! _requestRejected )
705
705
{
706
706
// 500 Internal Server Error
707
- ErrorResetHeadersToDefaults ( statusCode : 500 ) ;
707
+ SetErrorResponseHeaders ( statusCode : 500 ) ;
708
708
}
709
709
}
710
710
@@ -758,19 +758,19 @@ private void CreateResponseHeader(
758
758
bool appCompleted )
759
759
{
760
760
var responseHeaders = FrameResponseHeaders ;
761
-
762
761
var hasConnection = responseHeaders . HasConnection ;
763
762
764
- // Set whether response can have body
765
- _canHaveBody = StatusCanHaveBody ( StatusCode ) && Method != "HEAD" ;
766
-
767
763
var end = SocketOutput . ProducingStart ( ) ;
764
+
768
765
if ( _keepAlive && hasConnection )
769
766
{
770
767
var connectionValue = responseHeaders . HeaderConnection . ToString ( ) ;
771
768
_keepAlive = connectionValue . Equals ( "keep-alive" , StringComparison . OrdinalIgnoreCase ) ;
772
769
}
773
-
770
+
771
+ // Set whether response can have body
772
+ _canHaveBody = StatusCanHaveBody ( StatusCode ) && Method != "HEAD" ;
773
+
774
774
if ( _canHaveBody )
775
775
{
776
776
if ( ! responseHeaders . HasTransferEncoding && ! responseHeaders . HasContentLength )
@@ -781,7 +781,7 @@ private void CreateResponseHeader(
781
781
// the headers we can safely set the Content-Length to 0.
782
782
responseHeaders . SetRawContentLength ( "0" , _bytesContentLengthZero ) ;
783
783
}
784
- else
784
+ else if ( _keepAlive )
785
785
{
786
786
// Note for future reference: never change this to set _autoChunk to true on HTTP/1.0
787
787
// connections, even if we were to infer the client supports it because an HTTP/1.0 request
@@ -805,7 +805,7 @@ private void CreateResponseHeader(
805
805
else
806
806
{
807
807
// Don't set the Content-Length or Transfer-Encoding headers
808
- // automatically for HEAD requests or 101, 204, 205, 304 responses.
808
+ // automatically for HEAD requests or 204, 205, 304 responses.
809
809
if ( responseHeaders . HasTransferEncoding )
810
810
{
811
811
RejectNonBodyTransferEncodingResponse ( appCompleted ) ;
@@ -1277,9 +1277,14 @@ public bool StatusCanHaveBody(int statusCode)
1277
1277
statusCode != 304 ;
1278
1278
}
1279
1279
1280
+ private void ThrowResponseAlreadyStartedException ( string value )
1281
+ {
1282
+ throw new InvalidOperationException ( $ "{ value } cannot be set, response has already started.") ;
1283
+ }
1284
+
1280
1285
private void RejectNonBodyTransferEncodingResponse ( bool appCompleted )
1281
1286
{
1282
- var ex = BadHttpResponse . GetException ( ResponseRejectionReasons . TransferEncodingSetOnNonBodyResponse , StatusCode ) ;
1287
+ var ex = new InvalidOperationException ( $ "Transfer-Encoding set on a { StatusCode } non-body request." ) ;
1283
1288
if ( ! appCompleted )
1284
1289
{
1285
1290
// Back out of header creation surface exeception in user code
@@ -1289,18 +1294,22 @@ private void RejectNonBodyTransferEncodingResponse(bool appCompleted)
1289
1294
else
1290
1295
{
1291
1296
ReportApplicationError ( ex ) ;
1297
+
1292
1298
// 500 Internal Server Error
1293
- ErrorResetHeadersToDefaults ( statusCode : 500 ) ;
1299
+ SetErrorResponseHeaders ( statusCode : 500 ) ;
1294
1300
}
1295
1301
}
1296
1302
1297
- private void ErrorResetHeadersToDefaults ( int statusCode )
1303
+ private void SetErrorResponseHeaders ( int statusCode )
1298
1304
{
1299
- // Setting status code will throw if response has already started
1300
- if ( ! HasResponseStarted )
1305
+ Debug . Assert ( ! HasResponseStarted , $ "{ nameof ( SetErrorResponseHeaders ) } called after response had already started.") ;
1306
+
1307
+ StatusCode = statusCode ;
1308
+ ReasonPhrase = null ;
1309
+
1310
+ if ( FrameResponseHeaders == null )
1301
1311
{
1302
- StatusCode = statusCode ;
1303
- ReasonPhrase = null ;
1312
+ InitializeHeaders ( ) ;
1304
1313
}
1305
1314
1306
1315
var responseHeaders = FrameResponseHeaders ;
@@ -1325,8 +1334,8 @@ public void HandleNonBodyResponseWrite(int count)
1325
1334
}
1326
1335
else
1327
1336
{
1328
- // Throw Exception for 101, 204, 205, 304 responses.
1329
- BadHttpResponse . ThrowException ( ResponseRejectionReasons . WriteToNonBodyResponse , StatusCode ) ;
1337
+ // Throw Exception for 204, 205, 304 responses.
1338
+ throw new InvalidOperationException ( $ "Write to non-body { StatusCode } response." ) ;
1330
1339
}
1331
1340
}
1332
1341
@@ -1365,7 +1374,11 @@ public void SetBadRequestState(RequestRejectionReason reason)
1365
1374
1366
1375
public void SetBadRequestState ( BadHttpRequestException ex )
1367
1376
{
1368
- ErrorResetHeadersToDefaults ( statusCode : ex . StatusCode ) ;
1377
+ // Setting status code will throw if response has already started
1378
+ if ( ! HasResponseStarted )
1379
+ {
1380
+ SetErrorResponseHeaders ( statusCode : ex . StatusCode ) ;
1381
+ }
1369
1382
1370
1383
_keepAlive = false ;
1371
1384
_requestProcessingStopping = true ;
0 commit comments