Skip to content

Commit 273a898

Browse files
committed
Merge branch 'series/0.5' into series/0.7
2 parents a74f633 + b3b7610 commit 273a898

File tree

9 files changed

+87
-29
lines changed

9 files changed

+87
-29
lines changed

.github/workflows/ci.yml

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ jobs:
3636
timeout-minutes: 60
3737
steps:
3838
- name: Checkout current branch (full)
39-
uses: actions/checkout@v4
39+
uses: actions/checkout@v5
4040
with:
4141
fetch-depth: 0
4242

@@ -46,7 +46,7 @@ jobs:
4646
- name: Setup Java (temurin@17)
4747
id: setup-java-temurin-17
4848
if: matrix.java == 'temurin@17'
49-
uses: actions/setup-java@v4
49+
uses: actions/setup-java@v5
5050
with:
5151
distribution: temurin
5252
java-version: 17
@@ -92,7 +92,7 @@ jobs:
9292

9393
- name: Upload target directories
9494
if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main')
95-
uses: actions/upload-artifact@v4
95+
uses: actions/upload-artifact@v5
9696
with:
9797
name: target-${{ matrix.os }}-${{ matrix.java }}-${{ matrix.scala }}-${{ matrix.project }}
9898
path: targets.tar
@@ -108,7 +108,7 @@ jobs:
108108
runs-on: ${{ matrix.os }}
109109
steps:
110110
- name: Checkout current branch (full)
111-
uses: actions/checkout@v4
111+
uses: actions/checkout@v5
112112
with:
113113
fetch-depth: 0
114114

@@ -118,7 +118,7 @@ jobs:
118118
- name: Setup Java (temurin@17)
119119
id: setup-java-temurin-17
120120
if: matrix.java == 'temurin@17'
121-
uses: actions/setup-java@v4
121+
uses: actions/setup-java@v5
122122
with:
123123
distribution: temurin
124124
java-version: 17
@@ -129,7 +129,7 @@ jobs:
129129
run: sbt +update
130130

131131
- name: Download target directories (2.13, rootJVM)
132-
uses: actions/download-artifact@v4
132+
uses: actions/download-artifact@v6
133133
with:
134134
name: target-${{ matrix.os }}-${{ matrix.java }}-2.13-rootJVM
135135

@@ -139,7 +139,7 @@ jobs:
139139
rm targets.tar
140140
141141
- name: Download target directories (2.12, rootJVM)
142-
uses: actions/download-artifact@v4
142+
uses: actions/download-artifact@v6
143143
with:
144144
name: target-${{ matrix.os }}-${{ matrix.java }}-2.12-rootJVM
145145

@@ -149,7 +149,7 @@ jobs:
149149
rm targets.tar
150150
151151
- name: Download target directories (3, rootJVM)
152-
uses: actions/download-artifact@v4
152+
uses: actions/download-artifact@v6
153153
with:
154154
name: target-${{ matrix.os }}-${{ matrix.java }}-3-rootJVM
155155

@@ -192,7 +192,7 @@ jobs:
192192
runs-on: ${{ matrix.os }}
193193
steps:
194194
- name: Checkout current branch (full)
195-
uses: actions/checkout@v4
195+
uses: actions/checkout@v5
196196
with:
197197
fetch-depth: 0
198198

@@ -202,7 +202,7 @@ jobs:
202202
- name: Setup Java (temurin@17)
203203
id: setup-java-temurin-17
204204
if: matrix.java == 'temurin@17'
205-
uses: actions/setup-java@v4
205+
uses: actions/setup-java@v5
206206
with:
207207
distribution: temurin
208208
java-version: 17
@@ -227,12 +227,12 @@ jobs:
227227
runs-on: ${{ matrix.os }}
228228
steps:
229229
- name: Checkout current branch (fast)
230-
uses: actions/checkout@v4
230+
uses: actions/checkout@v5
231231

232232
- name: Setup Java (temurin@11)
233233
id: setup-java-temurin-11
234234
if: matrix.java == 'temurin@11'
235-
uses: actions/setup-java@v4
235+
uses: actions/setup-java@v5
236236
with:
237237
distribution: temurin
238238
java-version: 11

.scalafmt.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version = 3.9.4
1+
version = 3.10.2
22
runner.dialect = scala213
33
style = default
44

build.sbt

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import com.typesafe.tools.mima.core._
22

33
val Scala212 = "2.12.20"
4-
val Scala213 = "2.13.16"
4+
val Scala213 = "2.13.18"
55

66
inThisBuild(
77
Seq(
@@ -13,21 +13,21 @@ inThisBuild(
1313
),
1414
licenses := Seq(License.Apache2),
1515
tlBaseVersion := "0.7",
16-
crossScalaVersions := Seq(Scala213, Scala212, "3.3.6"),
16+
crossScalaVersions := Seq(Scala213, Scala212, "3.3.7"),
1717
ThisBuild / scalaVersion := Scala213,
1818
tlJdkRelease := Some(11),
1919
githubWorkflowJavaVersions := Seq(JavaSpec.temurin("17"))
2020
)
2121
)
2222

23-
val http4sVersion = "0.23.30"
23+
val http4sVersion = "0.23.33"
2424

25-
val jetty = "12.0.25"
25+
val jetty = "12.1.5"
2626

27-
val netty = "4.2.4.Final"
27+
val netty = "4.2.7.Final"
2828

29-
val munit = "1.1.1"
30-
val munitScalaCheck = "1.1.0"
29+
val munit = "1.2.1"
30+
val munitScalaCheck = "1.2.0"
3131

3232
val nativeNettyModules =
3333
Seq(
@@ -51,7 +51,7 @@ lazy val core = project
5151
libraryDependencies ++= List(
5252
"co.fs2" %% "fs2-core" % "3.12.0",
5353
"org.reactivestreams" % "reactive-streams-flow-adapters" % "1.0.2",
54-
("org.playframework.netty" % "netty-reactive-streams-http" % "3.0.4")
54+
("org.playframework.netty" % "netty-reactive-streams-http" % "3.0.6")
5555
.exclude("io.netty", "netty-codec-http")
5656
.exclude("io.netty", "netty-handler"),
5757
"io.netty" % "netty-codec-http" % netty,

project/build.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
sbt.version=1.11.4
1+
sbt.version=1.11.7

project/plugins.sbt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
addSbtPlugin("org.http4s" % "sbt-http4s-org" % "2.0.0")
1+
addSbtPlugin("org.http4s" % "sbt-http4s-org" % "2.0.3")

server/src/main/scala/org/http4s/netty/server/ServerNettyModelConversion.scala

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import org.http4s.Response
4242
import org.http4s.internal.tls._
4343
import org.http4s.netty.NettyModelConversion
4444
import org.http4s.netty.NettyModelConversion.bytebufToArray
45+
import org.http4s.netty.server.websocket.ZeroCopyBinaryText
4546
import org.http4s.server.SecureSession
4647
import org.http4s.server.ServerRequestKeys
4748
import org.http4s.websocket.WebSocketCombinedPipe
@@ -210,6 +211,9 @@ private[server] final class ServerNettyModelConversion[F[_]](implicit F: Async[F
210211
private[this] def wsbitsToNetty(w: WebSocketFrame): WSFrame =
211212
w match {
212213
case Text(str, last) => new TextWebSocketFrame(last, 0, str)
214+
case ZeroCopyBinaryText(data, last) =>
215+
// data.toArrayUnsafe to avoid copying the underlying array
216+
new TextWebSocketFrame(last, 0, Unpooled.wrappedBuffer(data.toArrayUnsafe))
213217
case Binary(data, last) =>
214218
new BinaryWebSocketFrame(last, 0, Unpooled.wrappedBuffer(data.toArray))
215219
case Ping(data) => new PingWebSocketFrame(Unpooled.wrappedBuffer(data.toArray))
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/*
2+
* Copyright 2020 http4s.org
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.http4s.netty.server.websocket
18+
19+
import org.http4s.websocket.WebSocketFrame
20+
import scodec.bits.ByteVector
21+
22+
import java.nio.charset.StandardCharsets
23+
24+
final case class ZeroCopyBinaryText(data: ByteVector, last: Boolean) extends WebSocketFrame {
25+
26+
lazy val str: String = new String(data.toArray, StandardCharsets.UTF_8)
27+
28+
override val opcode: Int = 0x1
29+
30+
override def toString: String = s"ZeroCopyBinaryText('$str', last: $last)"
31+
}
32+
33+
object ZeroCopyBinaryText {
34+
def unsafe(data: Array[Byte], last: Boolean): ZeroCopyBinaryText =
35+
ZeroCopyBinaryText(ByteVector.view(data), last)
36+
}

server/src/test/scala/org/http4s/netty/server/ServerTest.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,6 @@ abstract class ServerTest extends IOSuite {
168168
server.use { server =>
169169
IO.delay {
170170
val http2 = new HttpClientTransportOverHTTP2(new HTTP2Client())
171-
http2.setUseALPN(false)
172-
173171
val client = new HttpClient(http2)
174172
client.start()
175173
try {

server/src/test/scala/org/http4s/netty/server/WebsocketTest.scala

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,16 @@ import org.http4s.dsl.io._
2929
import org.http4s.implicits._
3030
import org.http4s.jdkhttpclient.JdkWSClient
3131
import org.http4s.netty.client.NettyWSClientBuilder
32+
import org.http4s.netty.server.websocket.ZeroCopyBinaryText
3233
import org.http4s.server.websocket.WebSocketBuilder2
34+
import org.http4s.websocket.WebSocketFrame
3335
import scodec.bits.ByteVector
3436

3537
import java.net.http.HttpClient
3638
import scala.concurrent.duration.DurationInt
3739

3840
abstract class WebsocketTest(_client: Resource[IO, WSClient[IO]]) extends IOSuite {
41+
3942
import WebsocketTest._
4043

4144
val server: IOFixture[Uri] = resourceFixture(
@@ -62,6 +65,7 @@ abstract class WebsocketTest(_client: Resource[IO, WSClient[IO]]) extends IOSuit
6265
.use { conn =>
6366
for {
6467
_ <- conn.send(WSFrame.Text("bar"))
68+
_ <- conn.send(WSFrame.Text("zero-copy"))
6569
_ <- conn.sendMany(List(WSFrame.Binary(ByteVector(3, 99, 12)), WSFrame.Text("foo")))
6670
_ <- conn.send(WSFrame.Close(1000, "goodbye"))
6771
recv <- conn.receiveStream.compile.toList
@@ -70,6 +74,7 @@ abstract class WebsocketTest(_client: Resource[IO, WSClient[IO]]) extends IOSuit
7074
.assertEquals(
7175
List(
7276
WSFrame.Text("bar"),
77+
WSFrame.Text("zero-copy"),
7378
WSFrame.Binary(ByteVector(3, 99, 12)),
7479
WSFrame.Text("foo"),
7580
WSFrame.Close(1000, "goodbye")
@@ -82,15 +87,22 @@ abstract class WebsocketTest(_client: Resource[IO, WSClient[IO]]) extends IOSuit
8287
.use { conn =>
8388
for {
8489
_ <- conn.send(WSFrame.Binary(ByteVector(15, 2, 3)))
85-
_ <- conn.sendMany(List(WSFrame.Text("foo"), WSFrame.Text("bar")))
86-
recv <- conn.receiveStream.take(3).compile.toList
90+
_ <- conn.sendMany(
91+
List(
92+
WSFrame.Text("foo"),
93+
WSFrame.Text("bar"),
94+
WSFrame.Text("zero-copy"),
95+
WSFrame.Text("zero-copy-unsafe")))
96+
recv <- conn.receiveStream.take(5).compile.toList
8797
} yield recv
8898
}
8999
.assertEquals(
90100
List(
91101
WSFrame.Binary(ByteVector(15, 2, 3)),
92102
WSFrame.Text("foo"),
93-
WSFrame.Text("bar")
103+
WSFrame.Text("bar"),
104+
WSFrame.Text("zero-copy"),
105+
WSFrame.Text("zero-copy-unsafe")
94106
)
95107
)
96108
}
@@ -99,7 +111,15 @@ abstract class WebsocketTest(_client: Resource[IO, WSClient[IO]]) extends IOSuit
99111
object WebsocketTest {
100112
def echoRoutes(ws: WebSocketBuilder2[IO]): HttpRoutes[IO] =
101113
HttpRoutes.of[IO] { case _ -> Root / "echo" =>
102-
ws.build(identity)
114+
ws.build {
115+
_.map {
116+
case t: WebSocketFrame.Text if t.str == "zero-copy-unsafe" =>
117+
ZeroCopyBinaryText.unsafe("zero-copy-unsafe".getBytes, last = true)
118+
case t: WebSocketFrame.Text if t.str == "zero-copy" =>
119+
ZeroCopyBinaryText(ByteVector("zero-copy".getBytes), last = true)
120+
case frame => frame
121+
}
122+
}
103123
}
104124
}
105125

0 commit comments

Comments
 (0)