Skip to content

Commit 1e0092f

Browse files
authored
Merge pull request #118 from sgjbryan/series/0.23
Upgrade http4s, http4s-servlet
2 parents a4d40e4 + 56872e5 commit 1e0092f

File tree

4 files changed

+79
-86
lines changed

4 files changed

+79
-86
lines changed

.github/workflows/ci.yml

+6-6
Original file line numberDiff line numberDiff line change
@@ -29,16 +29,16 @@ jobs:
2929
fail-fast: false
3030
matrix:
3131
os: [ubuntu-latest]
32-
scala: [2.13.8, 2.12.17, 3.2.0]
32+
scala: [2.13.8, 2.12.17, 3.3.0]
3333
java: [temurin@8, temurin@11, temurin@17]
3434
exclude:
3535
- scala: 2.12.17
3636
java: temurin@11
3737
- scala: 2.12.17
3838
java: temurin@17
39-
- scala: 3.2.0
39+
- scala: 3.3.0
4040
java: temurin@11
41-
- scala: 3.2.0
41+
- scala: 3.3.0
4242
java: temurin@17
4343
runs-on: ${{ matrix.os }}
4444
steps:
@@ -244,12 +244,12 @@ jobs:
244244
tar xf targets.tar
245245
rm targets.tar
246246
247-
- name: Download target directories (3.2.0)
247+
- name: Download target directories (3.3.0)
248248
uses: actions/download-artifact@v2
249249
with:
250-
name: target-${{ matrix.os }}-${{ matrix.java }}-3.2.0
250+
name: target-${{ matrix.os }}-${{ matrix.java }}-3.3.0
251251

252-
- name: Inflate target directories (3.2.0)
252+
- name: Inflate target directories (3.3.0)
253253
run: |
254254
tar xf targets.tar
255255
rm targets.tar

build.sbt

+3-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ ThisBuild / developers := List(
1212
ThisBuild / tlSitePublishBranch := Some("main")
1313

1414
val Scala213 = "2.13.8"
15-
ThisBuild / crossScalaVersions := Seq(Scala213, "2.12.17", "3.2.0")
15+
ThisBuild / crossScalaVersions := Seq(Scala213, "2.12.17", "3.3.0")
1616
ThisBuild / scalaVersion := Scala213 // the default Scala
1717

1818
ThisBuild / resolvers +=
@@ -24,8 +24,8 @@ lazy val root = project
2424
.aggregate(jettyServer, jettyClient)
2525

2626
val jettyVersion = "9.4.50.v20221201"
27-
val http4sVersion = "0.23.17"
28-
val http4sServletVersion = "0.23.13"
27+
val http4sVersion = "0.23.22"
28+
val http4sServletVersion = "0.23.15"
2929
val munitCatsEffectVersion = "1.0.7"
3030
val slf4jVersion = "1.7.25"
3131

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

+68-63
Original file line numberDiff line numberDiff line change
@@ -55,36 +55,39 @@ private[jetty] object JettyLifeCycle {
5555
* internally, e.g. due to some internal error occurring.
5656
*/
5757
private[this] def stopLifeCycle[F[_]](lifeCycle: LifeCycle)(implicit F: Async[F]): F[Unit] =
58-
F.async_[Unit] { cb =>
59-
lifeCycle.addLifeCycleListener(
60-
new LifeCycle.Listener {
61-
override def lifeCycleStopped(a: LifeCycle): Unit =
62-
cb(Right(()))
63-
override def lifeCycleFailure(a: LifeCycle, error: Throwable): Unit =
64-
cb(Left(error))
65-
}
66-
)
58+
F.async[Unit] { cb =>
59+
F.delay {
60+
val listener =
61+
new LifeCycle.Listener {
62+
override def lifeCycleStopped(a: LifeCycle): Unit =
63+
cb(Right(()))
64+
override def lifeCycleFailure(a: LifeCycle, error: Throwable): Unit =
65+
cb(Left(error))
66+
}
67+
lifeCycle.addLifeCycleListener(listener)
6768

68-
// In the general case, it is not sufficient to merely call stop(). For
69-
// example, the concrete implementation of stop() for the canonical
70-
// Jetty Server instance will shortcut to a `return` call taking no
71-
// action if the server is "stopping". This method _can't_ return until
72-
// we are _actually stopped_, so we have to check three different states
73-
// here.
69+
// In the general case, it is not sufficient to merely call stop(). For
70+
// example, the concrete implementation of stop() for the canonical
71+
// Jetty Server instance will shortcut to a `return` call taking no
72+
// action if the server is "stopping". This method _can't_ return until
73+
// we are _actually stopped_, so we have to check three different states
74+
// here.
7475

75-
if (lifeCycle.isStopped) {
76-
// If the first case, we are already stopped, so our listener won't be
77-
// called and we just return.
78-
cb(Right(()))
79-
} else if (lifeCycle.isStopping()) {
80-
// If it is stopping, we need to wait for our listener to get invoked.
81-
()
82-
} else {
83-
// If it is neither stopped nor stopping, we need to request a stop
84-
// and then wait for the event. It is imperative that we add the
85-
// listener beforehand here. Otherwise we have some very annoying race
86-
// conditions.
87-
lifeCycle.stop()
76+
if (lifeCycle.isStopped) {
77+
// If the first case, we are already stopped, so our listener won't be
78+
// called and we just return.
79+
cb(Right(()))
80+
} else if (lifeCycle.isStopping()) {
81+
// If it is stopping, we need to wait for our listener to get invoked.
82+
()
83+
} else {
84+
// If it is neither stopped nor stopping, we need to request a stop
85+
// and then wait for the event. It is imperative that we add the
86+
// listener beforehand here. Otherwise we have some very annoying race
87+
// conditions.
88+
lifeCycle.stop()
89+
}
90+
Some(F.delay(lifeCycle.removeLifeCycleListener(listener)))
8891
}
8992
}
9093

@@ -95,51 +98,53 @@ private[jetty] object JettyLifeCycle {
9598
* (or starting) this will fail.
9699
*/
97100
private[this] def startLifeCycle[F[_]](lifeCycle: LifeCycle)(implicit F: Async[F]): F[Unit] =
98-
F.async_[Unit] { cb =>
99-
lifeCycle.addLifeCycleListener(
100-
new LifeCycle.Listener {
101+
F.async[Unit] { cb =>
102+
F.delay {
103+
val listener = new LifeCycle.Listener {
101104
override def lifeCycleStarted(a: LifeCycle): Unit =
102105
cb(Right(()))
103106
override def lifeCycleFailure(a: LifeCycle, error: Throwable): Unit =
104107
cb(Left(error))
105108
}
106-
)
109+
lifeCycle.addLifeCycleListener(listener)
107110

108-
// Sanity check to ensure the LifeCycle component is not already
109-
// started. A couple of notes here.
110-
//
111-
// - There is _always_ going to be a small chance of a race condition
112-
// here in the final branch where we invoke `lifeCycle.start()` _if_
113-
// something else has a reference to the `LifeCycle`
114-
// value. Thankfully, unlike the stopLifeCycle function, this is
115-
// completely in the control of the caller. As long as the caller
116-
// doesn't leak the reference (or call .start() themselves) nothing
117-
// internally to Jetty should ever invoke .start().
118-
// - Jetty components allow for reuse in many cases, unless the
119-
// .destroy() method is invoked (and the particular type implements
120-
// `Destroyable`, it's not part of `LifeCycle`). Jetty uses this for
121-
// "soft" resets of the `LifeCycle` component. Thus it is possible
122-
// that this `LifeCycle` component has been started before, though I
123-
// don't recommend this and we don't (at this time) do that in the
124-
// http4s codebase.
125-
if (lifeCycle.isStarted) {
126-
cb(
127-
Left(
128-
new IllegalStateException(
129-
"Attempting to start Jetty LifeCycle component, but it is already started."
111+
// Sanity check to ensure the LifeCycle component is not already
112+
// started. A couple of notes here.
113+
//
114+
// - There is _always_ going to be a small chance of a race condition
115+
// here in the final branch where we invoke `lifeCycle.start()` _if_
116+
// something else has a reference to the `LifeCycle`
117+
// value. Thankfully, unlike the stopLifeCycle function, this is
118+
// completely in the control of the caller. As long as the caller
119+
// doesn't leak the reference (or call .start() themselves) nothing
120+
// internally to Jetty should ever invoke .start().
121+
// - Jetty components allow for reuse in many cases, unless the
122+
// .destroy() method is invoked (and the particular type implements
123+
// `Destroyable`, it's not part of `LifeCycle`). Jetty uses this for
124+
// "soft" resets of the `LifeCycle` component. Thus it is possible
125+
// that this `LifeCycle` component has been started before, though I
126+
// don't recommend this and we don't (at this time) do that in the
127+
// http4s codebase.
128+
if (lifeCycle.isStarted) {
129+
cb(
130+
Left(
131+
new IllegalStateException(
132+
"Attempting to start Jetty LifeCycle component, but it is already started."
133+
)
130134
)
131135
)
132-
)
133-
} else if (lifeCycle.isStarting) {
134-
cb(
135-
Left(
136-
new IllegalStateException(
137-
"Attempting to start Jetty LifeCycle component, but it is already starting."
136+
} else if (lifeCycle.isStarting) {
137+
cb(
138+
Left(
139+
new IllegalStateException(
140+
"Attempting to start Jetty LifeCycle component, but it is already starting."
141+
)
138142
)
139143
)
140-
)
141-
} else {
142-
lifeCycle.start()
144+
} else {
145+
lifeCycle.start()
146+
}
147+
Some(F.delay(lifeCycle.removeLifeCycleListener(listener)))
143148
}
144149
}
145150
}

jetty-server/src/test/scala/org/http4s/jetty/server/JettyServerSuite.scala

+2-14
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,6 @@ import cats.effect.Temporal
2424
import munit.CatsEffectSuite
2525
import org.eclipse.jetty.client.HttpClient
2626
import org.eclipse.jetty.client.api.Request
27-
import org.eclipse.jetty.client.api.Response
28-
import org.eclipse.jetty.client.api.Result
29-
import org.eclipse.jetty.client.util.BufferingResponseListener
3027
import org.eclipse.jetty.client.util.StringContentProvider
3128
import org.http4s.dsl.io._
3229
import org.http4s.server.Server
@@ -62,7 +59,7 @@ class JettyServerSuite extends CatsEffectSuite {
6259
Ok(req.body)
6360

6461
case GET -> Root / "never" =>
65-
IO.never
62+
IO.async(_ => IO.pure(Some(IO.unit)))
6663

6764
case GET -> Root / "slow" =>
6865
Temporal[IO].sleep(50.millis) *> Ok("slow")
@@ -74,16 +71,7 @@ class JettyServerSuite extends CatsEffectSuite {
7471
private val jettyServer = ResourceFixture[Server](serverR)
7572

7673
private def fetchBody(req: Request): IO[String] =
77-
IO.async_ { cb =>
78-
val listener = new BufferingResponseListener() {
79-
override def onFailure(resp: Response, t: Throwable) =
80-
cb(Left(t))
81-
82-
override def onComplete(result: Result) =
83-
cb(Right(getContentAsString))
84-
}
85-
req.send(listener)
86-
}
74+
IO.interruptible(req.send().getContentAsString())
8775

8876
private def get(server: Server, path: String): IO[String] = {
8977
val req = client().newRequest(s"http://127.0.0.1:${server.address.getPort}$path")

0 commit comments

Comments
 (0)