@@ -22,6 +22,7 @@ import org.http4s.Response
2222import org .http4s .curl .internal .Utils
2323import org .http4s .curl .internal ._
2424import org .http4s .curl .unsafe .CurlExecutorScheduler
25+ import org .http4s .curl .unsafe .CurlMultiSocket
2526
2627private [curl] object CurlRequest {
2728 private def setup (
@@ -78,6 +79,57 @@ private[curl] object CurlRequest {
7879 )
7980 )
8081
82+ private def setup (
83+ handle : CurlEasy ,
84+ send : RequestSend ,
85+ recv : RequestRecv ,
86+ req : Request [IO ],
87+ ): Resource [IO , Unit ] =
88+ Utils .newZone.flatMap(implicit zone =>
89+ CurlSList ().evalMap(headers =>
90+ IO {
91+ // TODO add in options
92+ // handle.setVerbose(true)
93+
94+ import org .http4s .curl .unsafe .libcurl_const
95+ import scala .scalanative .unsafe ._
96+ import org .http4s .Header
97+ import org .http4s .HttpVersion
98+ import org .typelevel .ci ._
99+
100+ handle.setCustomRequest(toCString(req.method.renderString))
101+
102+ handle.setUpload(true )
103+
104+ handle.setUrl(toCString(req.uri.renderString))
105+
106+ val httpVersion = req.httpVersion match {
107+ case HttpVersion .`HTTP/1.0` => libcurl_const.CURL_HTTP_VERSION_1_0
108+ case HttpVersion .`HTTP/1.1` => libcurl_const.CURL_HTTP_VERSION_1_1
109+ case HttpVersion .`HTTP/2` => libcurl_const.CURL_HTTP_VERSION_2
110+ case HttpVersion .`HTTP/3` => libcurl_const.CURL_HTTP_VERSION_3
111+ case _ => libcurl_const.CURL_HTTP_VERSION_NONE
112+ }
113+ handle.setHttpVersion(httpVersion)
114+
115+ req.headers // curl adds these headers automatically, so we explicitly disable them
116+ .transform(Header .Raw (ci " Expect " , " " ) :: Header .Raw (ci " Transfer-Encoding " , " " ) :: _)
117+ .foreach(header => headers.append(header.toString))
118+
119+ handle.setHttpHeader(headers.toPtr)
120+
121+ handle.setReadData(Utils .toPtr(send))
122+ handle.setReadFunction(RequestSend .readCallback(_, _, _, _))
123+
124+ handle.setHeaderData(Utils .toPtr(recv))
125+ handle.setHeaderFunction(RequestRecv .headerCallback(_, _, _, _))
126+
127+ handle.setWriteData(Utils .toPtr(recv))
128+ handle.setWriteFunction(RequestRecv .writeCallback(_, _, _, _))
129+ }
130+ )
131+ )
132+
81133 def apply (ec : CurlExecutorScheduler , req : Request [IO ]): Resource [IO , Response [IO ]] = for {
82134 gc <- GCRoot ()
83135 handle <- CurlEasy ()
@@ -89,4 +141,17 @@ private[curl] object CurlRequest {
89141 _ <- req.body.through(send.pipe).compile.drain.background
90142 resp <- recv.response()
91143 } yield resp
144+
145+ def applyMultiSocket (ms : CurlMultiSocket , req : Request [IO ]): Resource [IO , Response [IO ]] = for {
146+ gc <- GCRoot ()
147+ handle <- CurlEasy ()
148+ flow <- FlowControl (handle)
149+ send <- RequestSend (flow)
150+ recv <- RequestRecv (flow)
151+ _ <- gc.add(send, recv)
152+ _ <- setup(handle, send, recv, req)
153+ _ <- ms.addHandlerTerminating(handle, recv.onTerminated).toResource
154+ _ <- req.body.through(send.pipe).compile.drain.background
155+ resp <- recv.response()
156+ } yield resp
92157}
0 commit comments