@@ -281,6 +281,110 @@ func TestDoHTTPRequestBodyReaderServerError(t *testing.T) {
281281 assert .Contains (t , err .Error (), "500" )
282282}
283283
284+ func TestDoHTTPRequestBodyReaderNoTimeoutOnSlowStream (t * testing.T ) {
285+ // This test verifies that DoHTTPRequestBodyReader successfully completes
286+ // for quick responses, proving the streaming timeout is long enough
287+ responseData := []byte ("streaming response data" )
288+ server := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
289+ w .Header ().Set ("Content-Type" , "application/octet-stream" )
290+ w .WriteHeader (http .StatusOK )
291+ _ , err := w .Write (responseData )
292+ require .NoError (t , err )
293+ }))
294+ defer server .Close ()
295+
296+ // Context without timeout - function should apply streaming timeout (5 min default)
297+ ctx := context .Background ()
298+ reader , err := DoHTTPRequestBodyReader (ctx , server .URL )
299+ require .NoError (t , err )
300+ require .NotNil (t , reader )
301+ defer func (reader io.ReadCloser ) {
302+ _ = reader .Close ()
303+ }(reader )
304+
305+ body , err := io .ReadAll (reader )
306+ require .NoError (t , err )
307+ assert .Equal (t , responseData , body )
308+ }
309+
310+ func TestDoHTTPRequestBodyReaderWithShortTimeout (t * testing.T ) {
311+ // This test uses a custom short streaming timeout to actually verify timeout behavior
312+ // Save and restore the original timeout
313+ originalTimeout := httpStreamingTimeout
314+ httpStreamingTimeout = 500 // 500ms for testing - enough for connection but not for slow read
315+ defer func () {
316+ httpStreamingTimeout = originalTimeout
317+ }()
318+
319+ server := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
320+ w .Header ().Set ("Content-Type" , "application/octet-stream" )
321+ w .WriteHeader (http .StatusOK )
322+ // Write some data immediately
323+ flusher , ok := w .(http.Flusher )
324+ require .True (t , ok , "Expected http.ResponseWriter to be an http.Flusher" )
325+ _ , _ = w .Write ([]byte ("starting..." ))
326+ flusher .Flush ()
327+
328+ // Sleep longer than timeout - this should cause the read to fail
329+ time .Sleep (1 * time .Second )
330+ _ , _ = w .Write ([]byte ("this should not be received" ))
331+ }))
332+ defer server .Close ()
333+
334+ ctx := context .Background ()
335+ reader , err := DoHTTPRequestBodyReader (ctx , server .URL )
336+ require .NoError (t , err )
337+ require .NotNil (t , reader )
338+ defer func (reader io.ReadCloser ) {
339+ _ = reader .Close ()
340+ }(reader )
341+
342+ // Reading should fail due to timeout while reading the body
343+ _ , err = io .ReadAll (reader )
344+ // Should get an error because the server is too slow
345+ require .Error (t , err , "Should get timeout error on slow stream" )
346+ }
347+
348+ func TestDoHTTPRequestBodyReaderRespectsExistingDeadline (t * testing.T ) {
349+ // This test verifies that DoHTTPRequestBodyReader respects an existing context deadline
350+ // We do this by setting a very short deadline and ensuring it times out quickly
351+ // (rather than waiting for the 5-minute streaming timeout)
352+ server := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
353+ w .Header ().Set ("Content-Type" , "application/octet-stream" )
354+ w .WriteHeader (http .StatusOK )
355+ // Write initial data
356+ _ , _ = w .Write ([]byte ("start" ))
357+ if flusher , ok := w .(http.Flusher ); ok {
358+ flusher .Flush ()
359+ }
360+ // Sleep for 2 seconds - longer than our 100ms deadline
361+ time .Sleep (2 * time .Second )
362+ _ , _ = w .Write ([]byte ("should timeout before this" ))
363+ }))
364+ defer server .Close ()
365+
366+ // Context with very short 100ms timeout (much shorter than 5-minute streaming default)
367+ ctx , cancel := context .WithTimeout (context .Background (), 100 * time .Millisecond )
368+ defer cancel ()
369+
370+ start := time .Now ()
371+ reader , err := DoHTTPRequestBodyReader (ctx , server .URL )
372+ require .NoError (t , err )
373+ require .NotNil (t , reader )
374+ defer func (reader io.ReadCloser ) {
375+ _ = reader .Close ()
376+ }(reader )
377+
378+ // This should timeout due to our 100ms deadline, not the 5-minute streaming timeout
379+ _ , err = io .ReadAll (reader )
380+ elapsed := time .Since (start )
381+
382+ // Should fail with timeout
383+ require .Error (t , err , "Should timeout with custom deadline" )
384+ // Should have timed out quickly (within 1 second), not after 5 minutes
385+ assert .Less (t , elapsed , 2 * time .Second , "Should respect short custom deadline, not wait for streaming timeout" )
386+ }
387+
284388func TestDoHTTPRequestEmptyRequestBody (t * testing.T ) {
285389 server := httptest .NewServer (http .HandlerFunc (func (w http.ResponseWriter , r * http.Request ) {
286390 // Empty slice still triggers POST because len(requestBody) > 0
0 commit comments