@@ -35,6 +35,7 @@ internal partial class CurlHandler : HttpMessageHandler
35
35
private readonly static string [ ] AuthenticationSchemes = { "Negotiate" , "Digest" , "Basic" } ; // the order in which libcurl goes over authentication schemes
36
36
private static readonly string [ ] s_headerDelimiters = new string [ ] { "\r \n " } ;
37
37
private const int s_requestBufferSize = 16384 ; // Default used by libcurl
38
+ private const string NoTransferEncoding = HttpKnownHeaderNames . TransferEncoding + ":" ;
38
39
39
40
#endregion
40
41
@@ -202,10 +203,17 @@ protected internal override Task<HttpResponseMessage> SendAsync(
202
203
{
203
204
throw new ArgumentNullException ( "request" , SR . net_http_handler_norequest ) ;
204
205
}
205
- else if ( ( request . RequestUri . Scheme != UriSchemeHttp ) && ( request . RequestUri . Scheme != UriSchemeHttps ) )
206
+
207
+ if ( ( request . RequestUri . Scheme != UriSchemeHttp ) && ( request . RequestUri . Scheme != UriSchemeHttps ) )
206
208
{
207
209
throw NotImplemented . ByDesignWithMessage ( SR . net_http_client_http_baseaddress_required ) ;
208
210
}
211
+
212
+ if ( request . Headers . TransferEncodingChunked . GetValueOrDefault ( ) && ( request . Content == null ) )
213
+ {
214
+ throw new InvalidOperationException ( SR . net_http_chunked_not_allowed_with_empty_content ) ;
215
+ }
216
+
209
217
// TODO: Check that SendAsync is not being called again for same request object.
210
218
// Probably fix is needed in WinHttpHandler as well
211
219
@@ -612,6 +620,8 @@ private SafeCurlSlistHandle SetRequestHeaders(SafeCurlHandle handle, HttpRequest
612
620
HttpHeaders contentHeaders = null ;
613
621
if ( request . Content != null )
614
622
{
623
+ SetChunkedModeForSend ( request ) ;
624
+
615
625
// TODO: Content-Length header isn't getting correctly placed using ToString()
616
626
// This is a bug in HttpContentHeaders that needs to be fixed.
617
627
if ( request . Content . Headers . ContentLength . HasValue )
@@ -632,14 +642,23 @@ private SafeCurlSlistHandle SetRequestHeaders(SafeCurlHandle handle, HttpRequest
632
642
IntPtr rawHandle = IntPtr . Zero ;
633
643
for ( int i = 0 ; i < allHeaders . Length ; i ++ )
634
644
{
635
- string header = allHeaders [ i ] ;
645
+ string header = allHeaders [ i ] . Trim ( ) ;
636
646
if ( header . Equals ( "{" ) || header . Equals ( "}" ) )
637
647
{
638
648
continue ;
639
649
}
640
650
rawHandle = Interop . libcurl . curl_slist_append ( rawHandle , header ) ;
641
651
retVal . SetHandle ( rawHandle ) ;
642
652
}
653
+
654
+ // Since libcurl always adds a Transfer-Encoding header, we need to explicitly block
655
+ // it if caller specifically does not want to set the header
656
+ if ( request . Headers . TransferEncodingChunked . HasValue && ! request . Headers . TransferEncodingChunked . Value )
657
+ {
658
+ rawHandle = Interop . libcurl . curl_slist_append ( rawHandle , NoTransferEncoding ) ;
659
+ retVal . SetHandle ( rawHandle ) ;
660
+ }
661
+
643
662
if ( ! retVal . IsInvalid )
644
663
{
645
664
SetCurlOption ( handle , CURLoption . CURLOPT_HTTPHEADER , rawHandle ) ;
@@ -656,6 +675,29 @@ private SafeCurlSlistHandle SetRequestHeaders(SafeCurlHandle handle, HttpRequest
656
675
return retVal ;
657
676
}
658
677
678
+ private static void SetChunkedModeForSend ( HttpRequestMessage request )
679
+ {
680
+ bool chunkedMode = request . Headers . TransferEncodingChunked . GetValueOrDefault ( ) ;
681
+ HttpContent requestContent = request . Content ;
682
+ Debug . Assert ( requestContent != null ) ;
683
+
684
+ // Deal with conflict between 'Content-Length' vs. 'Transfer-Encoding: chunked' semantics.
685
+ // libcurl adds a Tranfer-Encoding header by default and the request fails if both are set.
686
+ if ( requestContent . Headers . ContentLength . HasValue )
687
+ {
688
+ if ( chunkedMode )
689
+ {
690
+ // Same behaviour as WinHttpHandler
691
+ requestContent . Headers . ContentLength = null ;
692
+ }
693
+ else
694
+ {
695
+ // Prevent libcurl from adding Transfer-Encoding header
696
+ request . Headers . TransferEncodingChunked = false ;
697
+ }
698
+ }
699
+ }
700
+
659
701
private void AddEasyHandle ( RequestCompletionSource state )
660
702
{
661
703
bool gotReference = false ;
0 commit comments