3131using System . Globalization ;
3232using System . IO ;
3333using System . Text ;
34- using System . Threading . Tasks ;
3534
3635namespace System . Net
3736{
3837 public sealed partial class HttpListenerResponse : IDisposable
3938 {
4039 private long _contentLength ;
41- private bool _clSet ;
4240 private Version _version = HttpVersion . Version11 ;
4341 private int _statusCode = 200 ;
44- private bool _chunked ;
45- private HttpListenerContext _context ;
4642 internal object _headersLock = new object ( ) ;
4743 private bool _forceCloseChunked ;
4844
4945 internal HttpListenerResponse ( HttpListenerContext context )
5046 {
51- _context = context ;
47+ _httpContext = context ;
5248 }
5349
5450 internal bool ForceCloseChunked => _forceCloseChunked ;
5551
56- public long ContentLength64
57- {
58- get => _contentLength ;
59- set
60- {
61- CheckDisposed ( ) ;
62- CheckSentHeaders ( ) ;
63-
64- if ( value < 0 )
65- throw new ArgumentOutOfRangeException ( nameof ( value ) , SR . net_clsmall ) ;
66-
67- _clSet = true ;
68- _contentLength = value ;
69- }
70- }
71-
7252 private void EnsureResponseStream ( )
7353 {
7454 if ( _responseStream == null )
7555 {
76- _responseStream = _context . Connection . GetResponseStream ( ) ;
56+ _responseStream = _httpContext . Connection . GetResponseStream ( ) ;
7757 }
7858 }
7959
@@ -95,18 +75,6 @@ public Version ProtocolVersion
9575 }
9676 }
9777
98- public bool SendChunked
99- {
100- get => _chunked ;
101- set
102- {
103- CheckDisposed ( ) ;
104- CheckSentHeaders ( ) ;
105-
106- _chunked = value ;
107- }
108- }
109-
11078 public int StatusCode
11179 {
11280 get => _statusCode ;
@@ -142,19 +110,49 @@ public void Abort()
142110 private void Close ( bool force )
143111 {
144112 Disposed = true ;
145- _context . Connection . Close ( force ) ;
113+ _httpContext . Connection . Close ( force ) ;
146114 }
147115
148116 public void Close ( byte [ ] responseEntity , bool willBlock )
149117 {
150118 CheckDisposed ( ) ;
151119
152120 if ( responseEntity == null )
121+ {
153122 throw new ArgumentNullException ( nameof ( responseEntity ) ) ;
123+ }
154124
155- ContentLength64 = responseEntity . Length ;
156- OutputStream . Write ( responseEntity , 0 , ( int ) _contentLength ) ;
157- Close ( false ) ;
125+ if ( _boundaryType != BoundaryType . Chunked )
126+ {
127+ ContentLength64 = responseEntity . Length ;
128+ }
129+
130+ if ( willBlock )
131+ {
132+ try
133+ {
134+ OutputStream . Write ( responseEntity , 0 , responseEntity . Length ) ;
135+ }
136+ finally
137+ {
138+ Close ( false ) ;
139+ }
140+ }
141+ else
142+ {
143+ OutputStream . BeginWrite ( responseEntity , 0 , responseEntity . Length , iar =>
144+ {
145+ var thisRef = ( HttpListenerResponse ) iar . AsyncState ;
146+ try
147+ {
148+ thisRef . OutputStream . EndWrite ( iar ) ;
149+ }
150+ finally
151+ {
152+ thisRef . Close ( false ) ;
153+ }
154+ } , this ) ;
155+ }
158156 }
159157
160158 public void CopyFrom ( HttpListenerResponse templateResponse )
@@ -191,26 +189,49 @@ internal void SendHeaders(bool closing, MemoryStream ms, bool isWebSocketHandsha
191189 if ( ! isWebSocketHandshake )
192190 {
193191 if ( _webHeaders [ HttpKnownHeaderNames . Server ] == null )
192+ {
194193 _webHeaders . Set ( HttpKnownHeaderNames . Server , HttpHeaderStrings . NetCoreServerName ) ;
195- CultureInfo inv = CultureInfo . InvariantCulture ;
194+ }
195+
196196 if ( _webHeaders [ HttpKnownHeaderNames . Date ] == null )
197- _webHeaders . Set ( HttpKnownHeaderNames . Date , DateTime . UtcNow . ToString ( "r" , inv ) ) ;
197+ {
198+ _webHeaders . Set ( HttpKnownHeaderNames . Date , DateTime . UtcNow . ToString ( "r" , CultureInfo . InvariantCulture ) ) ;
199+ }
198200
199- if ( ! _chunked )
201+ if ( _boundaryType == BoundaryType . None )
200202 {
201- if ( ! _clSet && closing )
203+ if ( HttpListenerRequest . ProtocolVersion <= HttpVersion . Version10 )
202204 {
203- _clSet = true ;
204- _contentLength = 0 ;
205+ _keepAlive = false ;
206+ }
207+ else
208+ {
209+ _boundaryType = BoundaryType . Chunked ;
205210 }
206211
207- if ( _clSet )
208- _webHeaders . Set ( HttpKnownHeaderNames . ContentLength , _contentLength . ToString ( inv ) ) ;
212+ if ( CanSendResponseBody ( _httpContext . Response . StatusCode ) )
213+ {
214+ _contentLength = - 1 ;
215+ }
216+ else
217+ {
218+ _boundaryType = BoundaryType . ContentLength ;
219+ _contentLength = 0 ;
220+ }
209221 }
210222
211- Version v = _context . Request . ProtocolVersion ;
212- if ( ! _clSet && ! _chunked && v >= HttpVersion . Version11 )
213- _chunked = true ;
223+ if ( _boundaryType != BoundaryType . Chunked )
224+ {
225+ if ( _boundaryType != BoundaryType . ContentLength && closing )
226+ {
227+ _contentLength = CanSendResponseBody ( _httpContext . Response . StatusCode ) ? - 1 : 0 ;
228+ }
229+
230+ if ( _boundaryType == BoundaryType . ContentLength )
231+ {
232+ _webHeaders . Set ( HttpKnownHeaderNames . ContentLength , _contentLength . ToString ( "D" , CultureInfo . InvariantCulture ) ) ;
233+ }
234+ }
214235
215236 /* Apache forces closing the connection for these status codes:
216237 * HttpStatusCode.BadRequest 400
@@ -226,8 +247,10 @@ internal void SendHeaders(bool closing, MemoryStream ms, bool isWebSocketHandsha
226247 || _statusCode == ( int ) HttpStatusCode . RequestUriTooLong || _statusCode == ( int ) HttpStatusCode . InternalServerError
227248 || _statusCode == ( int ) HttpStatusCode . ServiceUnavailable ) ;
228249
229- if ( conn_close == false )
230- conn_close = ! _context . Request . KeepAlive ;
250+ if ( ! conn_close )
251+ {
252+ conn_close = ! _httpContext . Request . KeepAlive ;
253+ }
231254
232255 // They sent both KeepAlive: true and Connection: close
233256 if ( ! _keepAlive || conn_close )
@@ -236,10 +259,12 @@ internal void SendHeaders(bool closing, MemoryStream ms, bool isWebSocketHandsha
236259 conn_close = true ;
237260 }
238261
239- if ( _chunked )
262+ if ( SendChunked )
263+ {
240264 _webHeaders . Set ( HttpKnownHeaderNames . TransferEncoding , HttpHeaderStrings . Chunked ) ;
265+ }
241266
242- int reuses = _context . Connection . Reuses ;
267+ int reuses = _httpContext . Connection . Reuses ;
243268 if ( reuses >= 100 )
244269 {
245270 _forceCloseChunked = true ;
@@ -250,17 +275,17 @@ internal void SendHeaders(bool closing, MemoryStream ms, bool isWebSocketHandsha
250275 }
251276 }
252277
253- if ( ! conn_close )
278+ if ( ! conn_close && _httpContext . Request . ProtocolVersion <= HttpVersion . Version10 )
254279 {
255- _webHeaders . Set ( HttpKnownHeaderNames . KeepAlive , String . Format ( "timeout=15,max={0}" , 100 - reuses ) ) ;
256- if ( _context . Request . ProtocolVersion <= HttpVersion . Version10 )
257- _webHeaders . Set ( HttpKnownHeaderNames . Connection , HttpHeaderStrings . KeepAlive ) ;
280+ _webHeaders . Set ( HttpKnownHeaderNames . Connection , HttpHeaderStrings . KeepAlive ) ;
258281 }
259282
260283 if ( _cookies != null )
261284 {
262285 foreach ( Cookie cookie in _cookies )
286+ {
263287 _webHeaders . Set ( HttpKnownHeaderNames . SetCookie , CookieToClientString ( cookie ) ) ;
288+ }
264289 }
265290 }
266291
0 commit comments