@@ -99,7 +99,7 @@ function _raw_http_request(
9999 catch err
100100 _is_first_byte_timeout (err) || rethrow (err)
101101 attempt < attempts || error (" timed out waiting for first response byte ($(attempts) attempts)" )
102- @warn " raw probe got no first byte; re-dialing — known Windows IOCP wake strand (Reseau#107)" attempt port
102+ @warn " raw probe got no first byte; re-dialing after known Windows IOCP wake strand (Reseau#107)" attempt port
103103 finally
104104 NC. close (sock)
105105 end
@@ -108,15 +108,28 @@ function _raw_http_request(
108108 end
109109end
110110
111- function _raw_http_request_until_close (port:: Integer , request:: AbstractString ; timeout_s:: Float64 = 3.0 ):: Tuple{String, Bool}
112- return _run_with_timeout (; timeout_s = timeout_s + 4.0 , label = " raw http request until close (port $(port) )" ) do
113- sock = ND. connect (" tcp" , " 127.0.0.1:$(Int (port)) " )
114- try
115- write (sock, Vector {UInt8} (codeunits (String (request))))
116- return _read_until_close (sock; timeout_s)
117- finally
118- NC. close (sock)
111+ function _raw_http_request_until_close (
112+ port:: Integer ,
113+ request:: AbstractString ;
114+ timeout_s:: Float64 = 3.0 ,
115+ wait_for_first_byte:: Bool = true ,
116+ attempts:: Int = Sys. iswindows () ? 3 : 1 ,
117+ ):: Tuple{String, Bool}
118+ return _run_with_timeout (; timeout_s = (timeout_s + 4.0 ) * attempts, label = " raw http request until close (port $(port) )" ) do
119+ for attempt in 1 : attempts
120+ sock = ND. connect (" tcp" , " 127.0.0.1:$(Int (port)) " )
121+ try
122+ write (sock, Vector {UInt8} (codeunits (String (request))))
123+ return _read_until_close (sock; timeout_s, wait_for_first_byte)
124+ catch err
125+ _is_first_byte_timeout (err) || rethrow (err)
126+ attempt < attempts || error (" timed out waiting for first response byte before close ($(attempts) attempts)" )
127+ @warn " raw probe got no first byte before close; re-dialing after known Windows IOCP wake strand (Reseau#107)" attempt port
128+ finally
129+ NC. close (sock)
130+ end
119131 end
132+ error (" unreachable: raw probe retry loop exited" )
120133 end
121134end
122135
@@ -199,23 +212,34 @@ function _read_until_quiet(
199212 end
200213end
201214
202- function _read_until_close (conn:: NC.Conn ; timeout_s:: Float64 = 1.0 ):: Tuple{String, Bool}
215+ function _read_until_close (conn:: NC.Conn ; timeout_s:: Float64 = 1.0 , wait_for_first_byte :: Bool = false ):: Tuple{String, Bool}
203216 buf = Vector {UInt8} (undef, 1024 )
204217 out = UInt8[]
205218 deadline_ns = Int64 (time_ns ()) + round (Int64, timeout_s * 1.0e9 )
219+ saw_bytes = false
206220 while true
207221 remaining_ns = deadline_ns - Int64 (time_ns ())
208- remaining_ns <= 0 && return String (out), false
222+ if remaining_ns <= 0
223+ wait_for_first_byte && ! saw_bytes && throw (_FirstByteTimeout ())
224+ return String (out), false
225+ end
209226 NC. set_read_deadline! (conn, Int64 (time_ns ()) + remaining_ns)
210227 try
211228 chunk = readavailable (conn)
212229 n = length (chunk)
213- n == 0 && return String (out), true
230+ if n == 0
231+ wait_for_first_byte && ! saw_bytes && throw (_FirstByteTimeout ())
232+ return String (out), true
233+ end
214234 n > length (buf) && resize! (buf, n)
215235 copyto! (buf, 1 , chunk, 1 , n)
216236 append! (out, @view (buf[1 : n]))
237+ saw_bytes = true
217238 catch err
218- err isa IOP. DeadlineExceededError && return String (out), false
239+ if err isa IOP. DeadlineExceededError
240+ wait_for_first_byte && ! saw_bytes && throw (_FirstByteTimeout ())
241+ return String (out), false
242+ end
219243 (err isa EOFError || HT. _is_peer_close_error (err:: Exception )) && return String (out), true
220244 rethrow (err)
221245 end
@@ -1037,7 +1061,8 @@ end
10371061 sock = ND. connect (" tcp" , " 127.0.0.1:$(HT. port (server)) " )
10381062 try
10391063 write (sock, Vector {UInt8} (codeunits (" GET /one HTTP/1.1\r\n Host: $(address) \r\n\r\n " )))
1040- first = _read_until_quiet (sock; timeout_s = 2.0 , quiet_timeout_s = 0.1 )
1064+ first_timeout_s = Sys. iswindows () ? 5.0 : 2.0
1065+ first = _read_until_quiet (sock; timeout_s = first_timeout_s, quiet_timeout_s = 0.1 , wait_for_first_byte = true )
10411066 @test occursin (" HTTP/1.1 200 OK" , first)
10421067 sleep (1.0 )
10431068 closed_after_idle = false
0 commit comments