Skip to content

Commit f41691d

Browse files
authored
Merge pull request #926 from danicheg/merge-series/0.23-into-main
Merge `series/0.23` into `main`
2 parents 0b4a944 + e5ee8ba commit f41691d

File tree

42 files changed

+432
-242
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+432
-242
lines changed

.github/workflows/ci.yml

Lines changed: 23 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,18 @@ jobs:
3434
runs-on: ${{ matrix.os }}
3535
timeout-minutes: 60
3636
steps:
37+
- name: Install sbt
38+
uses: sbt/setup-sbt@v1
39+
3740
- name: Checkout current branch (full)
38-
uses: actions/checkout@v3
41+
uses: actions/checkout@v4
3942
with:
4043
fetch-depth: 0
4144

4245
- name: Setup Java (temurin@8)
4346
id: setup-java-temurin-8
4447
if: matrix.java == 'temurin@8'
45-
uses: actions/setup-java@v3
48+
uses: actions/setup-java@v4
4649
with:
4750
distribution: temurin
4851
java-version: 8
@@ -91,7 +94,7 @@ jobs:
9194

9295
- name: Upload target directories
9396
if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main')
94-
uses: actions/upload-artifact@v3
97+
uses: actions/upload-artifact@v4
9598
with:
9699
name: target-${{ matrix.os }}-${{ matrix.java }}-${{ matrix.scala }}
97100
path: targets.tar
@@ -106,15 +109,18 @@ jobs:
106109
java: [temurin@8]
107110
runs-on: ${{ matrix.os }}
108111
steps:
112+
- name: Install sbt
113+
uses: sbt/setup-sbt@v1
114+
109115
- name: Checkout current branch (full)
110-
uses: actions/checkout@v3
116+
uses: actions/checkout@v4
111117
with:
112118
fetch-depth: 0
113119

114120
- name: Setup Java (temurin@8)
115121
id: setup-java-temurin-8
116122
if: matrix.java == 'temurin@8'
117-
uses: actions/setup-java@v3
123+
uses: actions/setup-java@v4
118124
with:
119125
distribution: temurin
120126
java-version: 8
@@ -125,7 +131,7 @@ jobs:
125131
run: sbt +update
126132

127133
- name: Download target directories (3)
128-
uses: actions/download-artifact@v3
134+
uses: actions/download-artifact@v4
129135
with:
130136
name: target-${{ matrix.os }}-${{ matrix.java }}-3
131137

@@ -135,7 +141,7 @@ jobs:
135141
rm targets.tar
136142
137143
- name: Download target directories (2.13)
138-
uses: actions/download-artifact@v3
144+
uses: actions/download-artifact@v4
139145
with:
140146
name: target-${{ matrix.os }}-${{ matrix.java }}-2.13
141147

@@ -149,15 +155,15 @@ jobs:
149155
env:
150156
PGP_SECRET: ${{ secrets.PGP_SECRET }}
151157
PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }}
152-
run: echo $PGP_SECRET | base64 -di | gpg --import
158+
run: echo $PGP_SECRET | base64 -d -i - | gpg --import
153159

154160
- name: Import signing key and strip passphrase
155161
if: env.PGP_SECRET != '' && env.PGP_PASSPHRASE != ''
156162
env:
157163
PGP_SECRET: ${{ secrets.PGP_SECRET }}
158164
PGP_PASSPHRASE: ${{ secrets.PGP_PASSPHRASE }}
159165
run: |
160-
echo "$PGP_SECRET" | base64 -di > /tmp/signing-key.gpg
166+
echo "$PGP_SECRET" | base64 -d -i - > /tmp/signing-key.gpg
161167
echo "$PGP_PASSPHRASE" | gpg --pinentry-mode loopback --passphrase-fd 0 --import /tmp/signing-key.gpg
162168
(echo "$PGP_PASSPHRASE"; echo; echo) | gpg --command-fd 0 --pinentry-mode loopback --change-passphrase $(gpg --list-secret-keys --with-colons 2> /dev/null | grep '^sec:' | cut --delimiter ':' --fields 5 | tail -n 1)
163169
@@ -170,22 +176,25 @@ jobs:
170176

171177
dependency-submission:
172178
name: Submit Dependencies
173-
if: github.event_name != 'pull_request'
179+
if: github.event.repository.fork == false && github.event_name != 'pull_request'
174180
strategy:
175181
matrix:
176182
os: [ubuntu-latest]
177183
java: [temurin@8]
178184
runs-on: ${{ matrix.os }}
179185
steps:
186+
- name: Install sbt
187+
uses: sbt/setup-sbt@v1
188+
180189
- name: Checkout current branch (full)
181-
uses: actions/checkout@v3
190+
uses: actions/checkout@v4
182191
with:
183192
fetch-depth: 0
184193

185194
- name: Setup Java (temurin@8)
186195
id: setup-java-temurin-8
187196
if: matrix.java == 'temurin@8'
188-
uses: actions/setup-java@v3
197+
uses: actions/setup-java@v4
189198
with:
190199
distribution: temurin
191200
java-version: 8
@@ -210,12 +219,12 @@ jobs:
210219
runs-on: ${{ matrix.os }}
211220
steps:
212221
- name: Checkout current branch (fast)
213-
uses: actions/checkout@v3
222+
uses: actions/checkout@v4
214223

215224
- name: Setup Java (temurin@11)
216225
id: setup-java-temurin-11
217226
if: matrix.java == 'temurin@11'
218-
uses: actions/setup-java@v3
227+
uses: actions/setup-java@v4
219228
with:
220229
distribution: temurin
221230
java-version: 11

blaze-client/src/main/scala/org/http4s/blaze/client/Http1Connection.scala

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import org.http4s.Uri.RegName
3131
import org.http4s.blaze.core.Http1Stage
3232
import org.http4s.blaze.core.IdleTimeoutStage
3333
import org.http4s.blaze.core.util.Http1Writer
34+
import org.http4s.blaze.core.util.NullWriter
3435
import org.http4s.blaze.pipeline.Command.EOF
3536
import org.http4s.client.RequestKey
3637
import org.http4s.headers.Host
@@ -200,10 +201,8 @@ private final class Http1Connection[F[_]](
200201
if (userAgent.nonEmpty && !req.headers.contains[`User-Agent`])
201202
rr << userAgent.get << "\r\n"
202203

203-
val mustClose: Boolean = req.headers.get[HConnection] match {
204-
case Some(conn) => checkCloseConnection(conn, rr)
205-
case None => getHttpMinor(req) == 0
206-
}
204+
val mustClose: Boolean =
205+
checkRequestCloseConnection(req.headers.get[HConnection], getHttpMinor(req), NullWriter)
207206

208207
val writeRequest: F[Boolean] = getChunkEncoder(req, mustClose, rr)
209208
.write(rr, req.entity)

blaze-client/src/test/scala/org/http4s/blaze/client/BlazeClientBase.scala

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ package client
2020
import cats.effect._
2121
import cats.effect.kernel.Resource
2222
import cats.effect.std.Dispatcher
23-
import cats.implicits.catsSyntaxApplicativeId
2423
import cats.syntax.all._
2524
import fs2.Stream
2625
import io.netty.channel.ChannelHandlerContext
@@ -141,9 +140,9 @@ trait BlazeClientBase extends CatsEffectSuite {
141140
)
142141

143142
val server: IOFixture[ServerScaffold[IO]] =
144-
ResourceSuiteLocalFixture("http", makeScaffold(2, false))
143+
ResourceSuiteLocalFixture("http", makeScaffold(2, secure = false))
145144
val secureServer: IOFixture[ServerScaffold[IO]] =
146-
ResourceSuiteLocalFixture("https", makeScaffold(1, true))
145+
ResourceSuiteLocalFixture("https", makeScaffold(1, secure = true))
147146

148147
override val munitFixtures = List(
149148
server,

blaze-client/src/test/scala/org/http4s/blaze/client/BlazeClientSuite.scala

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -317,7 +317,7 @@ class BlazeClientSuite extends BlazeClientBase {
317317
}
318318
override def onRequestEnd(ctx: ChannelHandlerContext, request: HttpRequest): Unit = ()
319319
})
320-
ServerScaffold[IO](1, false, HandlersToNettyAdapter[IO](handlers)).use { server =>
320+
ServerScaffold[IO](1, secure = false, HandlersToNettyAdapter[IO](handlers)).use { server =>
321321
val address = server.addresses.head
322322
val name = address.host
323323
val port = address.port
@@ -343,7 +343,7 @@ class BlazeClientSuite extends BlazeClientBase {
343343
}
344344
override def onRequestEnd(ctx: ChannelHandlerContext, request: HttpRequest): Unit = ()
345345
})
346-
ServerScaffold[IO](1, false, HandlersToNettyAdapter[IO](handlers)).use { server =>
346+
ServerScaffold[IO](1, secure = false, HandlersToNettyAdapter[IO](handlers)).use { server =>
347347
val address = server.addresses.head
348348
val name = address.host
349349
val port = address.port
@@ -366,7 +366,7 @@ class BlazeClientSuite extends BlazeClientBase {
366366
}
367367
override def onRequestEnd(ctx: ChannelHandlerContext, request: HttpRequest): Unit = ()
368368
})
369-
ServerScaffold[IO](1, false, HandlersToNettyAdapter[IO](handlers)).use { server =>
369+
ServerScaffold[IO](1, secure = false, HandlersToNettyAdapter[IO](handlers)).use { server =>
370370
val address = server.addresses.head
371371
val name = address.host
372372
val port = address.port

blaze-client/src/test/scala/org/http4s/blaze/client/Http1ClientStageSuite.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import cats.effect._
2222
import cats.effect.kernel.Deferred
2323
import cats.effect.std.Dispatcher
2424
import cats.effect.std.Queue
25-
import cats.syntax.all._
2625
import fs2.Stream
2726
import munit.CatsEffectSuite
2827
import org.http4s.BuildInfo

blaze-core/src/main/scala/org/http4s/blaze/core/Http1Stage.scala

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ private[blaze] trait Http1Stage[F[_]] { self: TailStage[ByteBuffer] =>
6767
protected def contentComplete(): Boolean
6868

6969
/** Check Connection header and add applicable headers to response */
70+
@deprecated("Use checkConnectionPersistence(Option[Connection], Int, Writer) instead", "0.23.17")
7071
protected final def checkCloseConnection(conn: Connection, rr: StringWriter): Boolean =
7172
if (conn.hasKeepAlive) { // connection, look to the request
7273
logger.trace("Found Keep-Alive header")
@@ -83,6 +84,42 @@ private[blaze] trait Http1Stage[F[_]] { self: TailStage[ByteBuffer] =>
8384
true
8485
}
8586

87+
/** Checks whether the connection should be closed per the request's Connection header
88+
* and the HTTP version.
89+
*
90+
* As a side effect, writes a "Connection: close" header to the StringWriter if
91+
* the request explicitly requests the connection is closed.
92+
*
93+
* @see [[https://datatracker.ietf.org/doc/html/rfc9112#name-persistence RFC 9112, Section 9.3, Persistence]]
94+
*/
95+
private[http4s] final def checkRequestCloseConnection(
96+
conn: Option[Connection],
97+
minorVersion: Int,
98+
rr: Writer,
99+
): Boolean =
100+
if (conn.fold(false)(_.hasClose)) {
101+
logger.trace(s"Closing ${conn} due to explicit close option in request's Connection header")
102+
// This side effect doesn't really belong here, but is relied
103+
// upon in multiple places as we look for the encoder. The
104+
// related problem of writing the keep-alive header in HTTP/1.0
105+
// is handled elsewhere.
106+
if (minorVersion >= 1) {
107+
rr << "Connection: close\r\n"
108+
}
109+
true
110+
} else if (minorVersion >= 1) {
111+
logger.trace(s"Keeping ${conn} alive per default behavior of HTTP >= 1.1")
112+
false
113+
} else if (conn.fold(false)(_.hasKeepAlive)) {
114+
logger.trace(
115+
s"Keeping ${conn} alive due to explicit keep-alive option in request's Connection header"
116+
)
117+
false
118+
} else {
119+
logger.trace(s"Closing ${conn} per default behavior of HTTP/1.0")
120+
true
121+
}
122+
86123
/** Get the proper body encoder based on the request */
87124
protected final def getEncoder(
88125
req: Request[F],

blaze-core/src/main/scala/org/http4s/blaze/core/util/CachingChunkWriter.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ private[blaze] class CachingChunkWriter[F[_]](
103103
pipe.channelWrite(hbuff)
104104
}
105105
} else if (!chunk.isEmpty) {
106-
writeBodyChunk(chunk, true).flatMap { _ =>
106+
writeBodyChunk(chunk, flush = true).flatMap { _ =>
107107
writeTrailer(pipe, trailer)
108108
}
109109
} else {

blaze-core/src/main/scala/org/http4s/blaze/core/util/FlushingChunkWriter.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ private[blaze] class FlushingChunkWriter[F[_]](pipe: TailStage[ByteBuffer], trai
4040
else pipe.channelWrite(encodeChunk(chunk, Nil))
4141

4242
protected def writeEnd(chunk: Chunk[Byte]): Future[Boolean] = {
43-
if (!chunk.isEmpty) writeBodyChunk(chunk, true).flatMap { _ =>
43+
if (!chunk.isEmpty) writeBodyChunk(chunk, flush = true).flatMap { _ =>
4444
writeTrailer(pipe, trailer)
4545
}
4646
else writeTrailer(pipe, trailer)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* Copyright 2014 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
18+
package blaze.core.util
19+
20+
import org.http4s.util.Writer
21+
22+
/** A writer that does not write. Not to be confused with an
23+
* [[EntityBodyWriter]].
24+
*/
25+
private[http4s] object NullWriter extends Writer {
26+
def append(s: String): NullWriter.type = NullWriter
27+
}

blaze-core/src/test/scala/org/http4s/blaze/core/util/Http1WriterSpec.scala

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,13 +133,25 @@ class Http1WriterSpec extends CatsEffectSuite with DispatcherIOFixture {
133133
runNonChunkedTests(
134134
"CachingChunkWriter",
135135
implicit dispatcher =>
136-
tail => new CachingChunkWriter[IO](tail, IO.pure(Headers.empty), 1024 * 1024, false),
136+
tail =>
137+
new CachingChunkWriter[IO](
138+
tail,
139+
IO.pure(Headers.empty),
140+
1024 * 1024,
141+
omitEmptyContentLength = false,
142+
),
137143
)
138144

139145
runNonChunkedTests(
140146
"CachingStaticWriter",
141147
implicit dispatcher =>
142-
tail => new CachingChunkWriter[IO](tail, IO.pure(Headers.empty), 1024 * 1024, false),
148+
tail =>
149+
new CachingChunkWriter[IO](
150+
tail,
151+
IO.pure(Headers.empty),
152+
1024 * 1024,
153+
omitEmptyContentLength = false,
154+
),
143155
)
144156

145157
def builder(tail: TailStage[ByteBuffer])(implicit D: Dispatcher[IO]): FlushingChunkWriter[IO] =

0 commit comments

Comments
 (0)