Skip to content

Commit bdf293d

Browse files
authored
Merge pull request #75 from http4s/jetty-10
Jetty 10 and friends
2 parents a4d40e4 + 3934130 commit bdf293d

File tree

9 files changed

+62
-104
lines changed

9 files changed

+62
-104
lines changed

.github/workflows/ci.yml

+8-60
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,10 @@ jobs:
3030
matrix:
3131
os: [ubuntu-latest]
3232
scala: [2.13.8, 2.12.17, 3.2.0]
33-
java: [temurin@8, temurin@11, temurin@17]
33+
java: [temurin@11, temurin@17]
3434
exclude:
35-
- scala: 2.12.17
36-
java: temurin@11
3735
- scala: 2.12.17
3836
java: temurin@17
39-
- scala: 3.2.0
40-
java: temurin@11
4137
- scala: 3.2.0
4238
java: temurin@17
4339
runs-on: ${{ matrix.os }}
@@ -47,22 +43,6 @@ jobs:
4743
with:
4844
fetch-depth: 0
4945

50-
- name: Download Java (temurin@8)
51-
id: download-java-temurin-8
52-
if: matrix.java == 'temurin@8'
53-
uses: typelevel/download-java@v1
54-
with:
55-
distribution: temurin
56-
java-version: 8
57-
58-
- name: Setup Java (temurin@8)
59-
if: matrix.java == 'temurin@8'
60-
uses: actions/setup-java@v2
61-
with:
62-
distribution: jdkfile
63-
java-version: 8
64-
jdkFile: ${{ steps.download-java-temurin-8.outputs.jdkFile }}
65-
6646
- name: Download Java (temurin@11)
6747
id: download-java-temurin-11
6848
if: matrix.java == 'temurin@11'
@@ -111,26 +91,26 @@ jobs:
11191
run: sbt githubWorkflowCheck
11292

11393
- name: Check headers and formatting
114-
if: matrix.java == 'temurin@8'
94+
if: matrix.java == 'temurin@11'
11595
run: sbt '++${{ matrix.scala }}' headerCheckAll scalafmtCheckAll 'project /' scalafmtSbtCheck
11696

11797
- name: Test
11898
run: sbt '++${{ matrix.scala }}' test
11999

120100
- name: Check binary compatibility
121-
if: matrix.java == 'temurin@8'
101+
if: matrix.java == 'temurin@11'
122102
run: sbt '++${{ matrix.scala }}' mimaReportBinaryIssues
123103

124104
- name: Generate API documentation
125-
if: matrix.java == 'temurin@8'
105+
if: matrix.java == 'temurin@11'
126106
run: sbt '++${{ matrix.scala }}' doc
127107

128108
- name: Check scalafix lints
129-
if: matrix.java == 'temurin@8' && !startsWith(matrix.scala, '3.')
109+
if: matrix.java == 'temurin@11' && !startsWith(matrix.scala, '3.')
130110
run: sbt '++${{ matrix.scala }}' 'scalafixAll --check'
131111

132112
- name: Check unused compile dependencies
133-
if: matrix.java == 'temurin@8'
113+
if: matrix.java == 'temurin@11'
134114
run: sbt '++${{ matrix.scala }}' unusedCompileDependenciesTest
135115

136116
- name: Make target directories
@@ -156,30 +136,14 @@ jobs:
156136
matrix:
157137
os: [ubuntu-latest]
158138
scala: [2.13.8]
159-
java: [temurin@8]
139+
java: [temurin@11]
160140
runs-on: ${{ matrix.os }}
161141
steps:
162142
- name: Checkout current branch (full)
163143
uses: actions/checkout@v2
164144
with:
165145
fetch-depth: 0
166146

167-
- name: Download Java (temurin@8)
168-
id: download-java-temurin-8
169-
if: matrix.java == 'temurin@8'
170-
uses: typelevel/download-java@v1
171-
with:
172-
distribution: temurin
173-
java-version: 8
174-
175-
- name: Setup Java (temurin@8)
176-
if: matrix.java == 'temurin@8'
177-
uses: actions/setup-java@v2
178-
with:
179-
distribution: jdkfile
180-
java-version: 8
181-
jdkFile: ${{ steps.download-java-temurin-8.outputs.jdkFile }}
182-
183147
- name: Download Java (temurin@11)
184148
id: download-java-temurin-11
185149
if: matrix.java == 'temurin@11'
@@ -274,30 +238,14 @@ jobs:
274238
matrix:
275239
os: [ubuntu-latest]
276240
scala: [2.13.8]
277-
java: [temurin@8]
241+
java: [temurin@11]
278242
runs-on: ${{ matrix.os }}
279243
steps:
280244
- name: Checkout current branch (full)
281245
uses: actions/checkout@v2
282246
with:
283247
fetch-depth: 0
284248

285-
- name: Download Java (temurin@8)
286-
id: download-java-temurin-8
287-
if: matrix.java == 'temurin@8'
288-
uses: typelevel/download-java@v1
289-
with:
290-
distribution: temurin
291-
java-version: 8
292-
293-
- name: Setup Java (temurin@8)
294-
if: matrix.java == 'temurin@8'
295-
uses: actions/setup-java@v2
296-
with:
297-
distribution: jdkfile
298-
java-version: 8
299-
jdkFile: ${{ steps.download-java-temurin-8.outputs.jdkFile }}
300-
301249
- name: Download Java (temurin@11)
302250
id: download-java-temurin-11
303251
if: matrix.java == 'temurin@11'

build.sbt

+9-5
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
// https://typelevel.org/sbt-typelevel/faq.html#what-is-a-base-version-anyway
2-
ThisBuild / tlBaseVersion := "0.23" // your current series x.y
3-
ThisBuild / tlMimaPreviousVersions ++= (0 to 11).map(y => s"0.23.$y").toSet
1+
import org.typelevel.sbt.gha
2+
3+
ThisBuild / tlBaseVersion := "0.24" // your current series x.y
44

55
ThisBuild / licenses := Seq(License.Apache2)
66
ThisBuild / developers := List(
@@ -14,6 +14,10 @@ ThisBuild / tlSitePublishBranch := Some("main")
1414
val Scala213 = "2.13.8"
1515
ThisBuild / crossScalaVersions := Seq(Scala213, "2.12.17", "3.2.0")
1616
ThisBuild / scalaVersion := Scala213 // the default Scala
17+
ThisBuild / githubWorkflowJavaVersions ~= {
18+
// Jetty 10 bumps the requirement to Java 11
19+
_.filter { case JavaSpec(_, major) => major.toInt >= 11 }
20+
}
1721

1822
ThisBuild / resolvers +=
1923
"s01 snapshots".at("https://s01.oss.sonatype.org/content/repositories/snapshots/")
@@ -23,9 +27,9 @@ lazy val root = project
2327
.enablePlugins(NoPublishPlugin)
2428
.aggregate(jettyServer, jettyClient)
2529

26-
val jettyVersion = "9.4.50.v20221201"
30+
val jettyVersion = "10.0.13"
2731
val http4sVersion = "0.23.17"
28-
val http4sServletVersion = "0.23.13"
32+
val http4sServletVersion = "0.24.0-M2"
2933
val munitCatsEffectVersion = "1.0.7"
3034
val slf4jVersion = "1.7.25"
3135

flake.nix

+1-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@
1818
imports = [ typelevel-nix.typelevelShell ];
1919
name = "http4s-jetty-shell";
2020
typelevelShell = {
21-
jdk.package = pkgs.jdk8;
22-
nodejs.enable = true;
21+
jdk.package = pkgs.jdk11;
2322
};
2423
};
2524
}

jetty-client/src/main/scala/org/http4s/jetty/client/JettyClient.scala

+11-12
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import fs2._
2525
import org.eclipse.jetty.client.HttpClient
2626
import org.eclipse.jetty.client.api.{Request => JettyRequest}
2727
import org.eclipse.jetty.http.{HttpVersion => JHttpVersion}
28-
import org.eclipse.jetty.util.ssl.SslContextFactory
2928
import org.http4s.client.Client
3029
import org.log4s.Logger
3130
import org.log4s.getLogger
@@ -39,19 +38,19 @@ object JettyClient {
3938

4039
def resource[F[_]](
4140
client: HttpClient = defaultHttpClient()
42-
)(implicit F: Async[F]): Resource[F, Client[F]] = Dispatcher.parallel[F].flatMap { implicit D =>
41+
)(implicit F: Async[F]): Resource[F, Client[F]] = Dispatcher.parallel[F].flatMap { dispatcher =>
4342
val acquire = F
4443
.pure(client)
4544
.flatTap(client => F.delay(client.start()))
4645
.map(client =>
4746
Client[F] { req =>
4847
Resource.suspend(F.async[Resource[F, Response[F]]] { cb =>
49-
F.bracket(StreamRequestContentProvider()) { dcp =>
48+
F.bracket(StreamRequestContent[F](dispatcher)) { dcp =>
5049
(for {
5150
jReq <- F.catchNonFatal(toJettyRequest(client, req, dcp))
52-
rl <- ResponseListener(cb)
51+
rl <- ResponseListener(cb, dispatcher)
5352
_ <- F.delay(jReq.send(rl))
54-
_ <- dcp.write(req)
53+
_ <- dcp.write(req.body)
5554
} yield Option.empty[F[Unit]]).recover { case e =>
5655
cb(Left(e))
5756
Option.empty[F[Unit]]
@@ -75,8 +74,7 @@ object JettyClient {
7574
Stream.resource(resource(client))
7675

7776
def defaultHttpClient(): HttpClient = {
78-
val sslCtxFactory = new SslContextFactory.Client();
79-
val c = new HttpClient(sslCtxFactory)
77+
val c = new HttpClient()
8078
c.setFollowRedirects(false)
8179
c.setDefaultRequestContentType(null)
8280
c
@@ -85,7 +83,7 @@ object JettyClient {
8583
private def toJettyRequest[F[_]](
8684
client: HttpClient,
8785
request: Request[F],
88-
dcp: StreamRequestContentProvider[F],
86+
dcp: StreamRequestContent[F],
8987
): JettyRequest = {
9088
val jReq = client
9189
.newRequest(request.uri.toString)
@@ -98,9 +96,10 @@ object JettyClient {
9896
case _ => JHttpVersion.HTTP_1_1
9997
}
10098
)
101-
102-
for (h <- request.headers.headers if h.isNameValid)
103-
jReq.header(h.name.toString, h.value)
104-
jReq.content(dcp)
99+
jReq.headers { jettyHeaders =>
100+
for (h <- request.headers.headers if h.isNameValid)
101+
jettyHeaders.add(h.name.toString, h.value)
102+
}
103+
jReq.body(dcp)
105104
}
106105
}

jetty-client/src/main/scala/org/http4s/jetty/client/ResponseListener.scala

+11-7
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,8 @@ import java.nio.ByteBuffer
3939
private[jetty] final case class ResponseListener[F[_]](
4040
queue: Queue[F, Option[Item]],
4141
cb: Callback[Resource[F, Response[F]]],
42-
)(implicit F: Async[F], D: Dispatcher[F])
42+
dispatcher: Dispatcher[F],
43+
)(implicit F: Async[F])
4344
extends JettyResponse.Listener.Adapter {
4445
import ResponseListener.logger
4546

@@ -69,7 +70,9 @@ private[jetty] final case class ResponseListener[F[_]](
6970
}
7071
.leftMap { t => abort(t, response); t }
7172

72-
D.unsafeRunAndForget(F.delay(cb(r)).attempt.flatMap(loggingAsyncCallback[F, Unit](logger)))
73+
dispatcher.unsafeRunAndForget(
74+
F.delay(cb(r)).attempt.flatMap(loggingAsyncCallback[F, Unit](logger))
75+
)
7376
}
7477

7578
private def getHttpVersion(version: JHttpVersion): HttpVersion =
@@ -100,7 +103,7 @@ private[jetty] final case class ResponseListener[F[_]](
100103
override def onFailure(response: JettyResponse, failure: Throwable): Unit =
101104
if (responseSent) enqueue(Item.Raise(failure))(_ => F.unit)
102105
else
103-
D.unsafeRunAndForget(
106+
dispatcher.unsafeRunAndForget(
104107
F.delay(cb(Left(failure))).attempt.flatMap(loggingAsyncCallback[F, Unit](logger))
105108
)
106109

@@ -122,7 +125,7 @@ private[jetty] final case class ResponseListener[F[_]](
122125
enqueue(Item.Done)(loggingAsyncCallback[F, Unit](logger))
123126

124127
private def enqueue(item: Item)(cb: Either[Throwable, Unit] => F[Unit]): Unit =
125-
D.unsafeRunAndForget(queue.offer(item.some).attempt.flatMap(cb))
128+
dispatcher.unsafeRunAndForget(queue.offer(item.some).attempt.flatMap(cb))
126129
}
127130

128131
private[jetty] object ResponseListener {
@@ -138,9 +141,10 @@ private[jetty] object ResponseListener {
138141
private val logger = getLogger
139142

140143
def apply[F[_]](
141-
cb: Callback[Resource[F, Response[F]]]
142-
)(implicit F: Async[F], D: Dispatcher[F]): F[ResponseListener[F]] =
144+
cb: Callback[Resource[F, Response[F]]],
145+
dispatcher: Dispatcher[F],
146+
)(implicit F: Async[F]): F[ResponseListener[F]] =
143147
Queue
144148
.synchronous[F, Option[Item]]
145-
.map(q => ResponseListener(q, cb))
149+
.map(q => ResponseListener(q, cb, dispatcher))
146150
}

jetty-client/src/main/scala/org/http4s/jetty/client/StreamRequestContentProvider.scala jetty-client/src/main/scala/org/http4s/jetty/client/StreamRequestContent.scala

+16-12
Original file line numberDiff line numberDiff line change
@@ -22,19 +22,21 @@ import cats.effect._
2222
import cats.effect.std._
2323
import cats.syntax.all._
2424
import fs2._
25-
import org.eclipse.jetty.client.util.DeferredContentProvider
25+
import org.eclipse.jetty.client.util.AsyncRequestContent
2626
import org.eclipse.jetty.util.{Callback => JettyCallback}
2727
import org.http4s.jetty.client.internal.loggingAsyncCallback
2828
import org.log4s.getLogger
2929

30-
private[jetty] final case class StreamRequestContentProvider[F[_]](s: Semaphore[F])(implicit
31-
F: Async[F],
32-
D: Dispatcher[F],
33-
) extends DeferredContentProvider {
34-
import StreamRequestContentProvider.logger
30+
private[jetty] class StreamRequestContent[F[_]] private (
31+
s: Semaphore[F],
32+
dispatcher: Dispatcher[F],
33+
)(implicit
34+
F: Async[F]
35+
) extends AsyncRequestContent {
36+
import StreamRequestContent.logger
3537

36-
def write(req: Request[F]): F[Unit] =
37-
req.body.chunks
38+
def write(body: Stream[F, Byte]): F[Unit] =
39+
body.chunks
3840
.through(pipe)
3941
.compile
4042
.drain
@@ -53,13 +55,15 @@ private[jetty] final case class StreamRequestContentProvider[F[_]](s: Semaphore[
5355

5456
private val callback: JettyCallback = new JettyCallback {
5557
override def succeeded(): Unit =
56-
D.unsafeRunAndForget(s.release.attempt.flatMap(loggingAsyncCallback[F, Unit](logger)))
58+
dispatcher.unsafeRunAndForget(
59+
s.release.attempt.flatMap(loggingAsyncCallback[F, Unit](logger))
60+
)
5761
}
5862
}
5963

60-
private[jetty] object StreamRequestContentProvider {
64+
private[jetty] object StreamRequestContent {
6165
private val logger = getLogger
6266

63-
def apply[F[_]: Async: Dispatcher](): F[StreamRequestContentProvider[F]] =
64-
Semaphore[F](1).map(StreamRequestContentProvider(_))
67+
def apply[F[_]: Async](dispatcher: Dispatcher[F]): F[StreamRequestContent[F]] =
68+
Semaphore[F](1).map(new StreamRequestContent(_, dispatcher))
6569
}

jetty-server/src/main/scala/org/http4s/jetty/server/JettyBuilder.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ import java.util
5252
import javax.net.ssl.SSLContext
5353
import javax.net.ssl.SSLParameters
5454
import javax.servlet.DispatcherType
55-
import javax.servlet.Filter
55+
import javax.servlet.http.HttpFilter
5656
import javax.servlet.http.HttpServlet
5757
import scala.annotation.nowarn
5858
import scala.collection.immutable
@@ -189,7 +189,7 @@ sealed class JettyBuilder[F[_]] private (
189189
})
190190

191191
override def mountFilter(
192-
filter: Filter,
192+
filter: HttpFilter,
193193
urlMapping: String,
194194
name: Option[String],
195195
dispatches: util.EnumSet[DispatcherType],

jetty-server/src/main/scala/org/http4s/jetty/server/JettyLifeCycle.scala

+2-2
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ private[jetty] object JettyLifeCycle {
5656
*/
5757
private[this] def stopLifeCycle[F[_]](lifeCycle: LifeCycle)(implicit F: Async[F]): F[Unit] =
5858
F.async_[Unit] { cb =>
59-
lifeCycle.addLifeCycleListener(
59+
lifeCycle.addEventListener(
6060
new LifeCycle.Listener {
6161
override def lifeCycleStopped(a: LifeCycle): Unit =
6262
cb(Right(()))
@@ -96,7 +96,7 @@ private[jetty] object JettyLifeCycle {
9696
*/
9797
private[this] def startLifeCycle[F[_]](lifeCycle: LifeCycle)(implicit F: Async[F]): F[Unit] =
9898
F.async_[Unit] { cb =>
99-
lifeCycle.addLifeCycleListener(
99+
lifeCycle.addEventListener(
100100
new LifeCycle.Listener {
101101
override def lifeCycleStarted(a: LifeCycle): Unit =
102102
cb(Right(()))

0 commit comments

Comments
 (0)