Skip to content

Commit

Permalink
KTOR-7934 Remove Content-Length for browser
Browse files Browse the repository at this point in the history
  • Loading branch information
bjhham committed Jan 24, 2025
1 parent 4fd2282 commit 359f2fc
Show file tree
Hide file tree
Showing 7 changed files with 34 additions and 15 deletions.
3 changes: 2 additions & 1 deletion ktor-client/ktor-client-core/api/ktor-client-core.api
Original file line number Diff line number Diff line change
Expand Up @@ -1557,7 +1557,8 @@ public final class io/ktor/client/utils/HeadersKt {
}

public final class io/ktor/client/utils/HeadersUtilsKt {
public static final fun dropCompressionHeaders (Lio/ktor/http/HeadersBuilder;Lio/ktor/http/HttpMethod;Lio/ktor/util/Attributes;)V
public static final fun dropCompressionHeaders (Lio/ktor/http/HeadersBuilder;Lio/ktor/http/HttpMethod;Lio/ktor/util/Attributes;Z)V
public static synthetic fun dropCompressionHeaders$default (Lio/ktor/http/HeadersBuilder;Lio/ktor/http/HttpMethod;Lio/ktor/util/Attributes;ZILjava/lang/Object;)V
}

public final class io/ktor/client/utils/HttpResponseReceiveFail {
Expand Down
2 changes: 1 addition & 1 deletion ktor-client/ktor-client-core/api/ktor-client-core.klib.api
Original file line number Diff line number Diff line change
Expand Up @@ -1394,7 +1394,7 @@ final fun (io.ktor.client/HttpClientConfig<*>).io.ktor.client.plugins/defaultReq
final fun (io.ktor.http.content/OutgoingContent).io.ktor.client.utils/wrapHeaders(kotlin/Function1<io.ktor.http/Headers, io.ktor.http/Headers>): io.ktor.http.content/OutgoingContent // io.ktor.client.utils/wrapHeaders|[email protected](kotlin.Function1<io.ktor.http.Headers,io.ktor.http.Headers>){}[0]
final fun (io.ktor.http/Cookie).io.ktor.client.plugins.cookies/fillDefaults(io.ktor.http/Url): io.ktor.http/Cookie // io.ktor.client.plugins.cookies/fillDefaults|[email protected](io.ktor.http.Url){}[0]
final fun (io.ktor.http/Cookie).io.ktor.client.plugins.cookies/matches(io.ktor.http/Url): kotlin/Boolean // io.ktor.client.plugins.cookies/matches|[email protected](io.ktor.http.Url){}[0]
final fun (io.ktor.http/HeadersBuilder).io.ktor.client.utils/dropCompressionHeaders(io.ktor.http/HttpMethod, io.ktor.util/Attributes) // io.ktor.client.utils/dropCompressionHeaders|[email protected](io.ktor.http.HttpMethod;io.ktor.util.Attributes){}[0]
final fun (io.ktor.http/HeadersBuilder).io.ktor.client.utils/dropCompressionHeaders(io.ktor.http/HttpMethod, io.ktor.util/Attributes, kotlin/Boolean = ...) // io.ktor.client.utils/dropCompressionHeaders|[email protected](io.ktor.http.HttpMethod;io.ktor.util.Attributes;kotlin.Boolean){}[0]
final fun (io.ktor.http/HttpMessageBuilder).io.ktor.client.request/accept(io.ktor.http/ContentType) // io.ktor.client.request/accept|[email protected](io.ktor.http.ContentType){}[0]
final fun (io.ktor.http/HttpMessageBuilder).io.ktor.client.request/basicAuth(kotlin/String, kotlin/String) // io.ktor.client.request/basicAuth|[email protected](kotlin.String;kotlin.String){}[0]
final fun (io.ktor.http/HttpMessageBuilder).io.ktor.client.request/bearerAuth(kotlin/String) // io.ktor.client.request/bearerAuth|[email protected](kotlin.String){}[0]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,16 @@ private val DecompressionListAttribute: AttributeKey<MutableList<String>> = Attr
* (like js and Curl) to make sure all the plugins and checks work with the correct content length and encoding.
*/
@InternalAPI
public fun HeadersBuilder.dropCompressionHeaders(method: HttpMethod, attributes: Attributes) {
public fun HeadersBuilder.dropCompressionHeaders(
method: HttpMethod,
attributes: Attributes,
alwaysRemove: Boolean = false,
) {
if (method == HttpMethod.Head || method == HttpMethod.Options) return
val header = get(HttpHeaders.ContentEncoding) ?: return
attributes.computeIfAbsent(DecompressionListAttribute) { mutableListOf<String>() }.add(header)
when (val header = get(HttpHeaders.ContentEncoding)) {
null -> if (!alwaysRemove) return
else -> attributes.computeIfAbsent(DecompressionListAttribute) { mutableListOf<String>() }.add(header)
}
remove(HttpHeaders.ContentEncoding)
remove(HttpHeaders.ContentLength)
}
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,13 @@ internal fun org.w3c.fetch.Headers.mapToKtor(method: HttpMethod, attributes: Att
append(key, value)
}

dropCompressionHeaders(method, attributes)
// Content-Encoding is hidden for cross-origin calls,
// so browser requests should always ignore Content-Length
dropCompressionHeaders(
method,
attributes,
alwaysRemove = PlatformUtils.IS_BROWSER
)
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ abstract class ClientLoader(private val timeout: Duration = 1.minutes) {
return EngineSelectionRule { pattern.matches(it) }
}

/** Includes the set of [engines] for the test */
fun only(vararg engines: String): EngineSelectionRule {
val includePatterns = engines.map(EnginePattern::parse)
return EngineSelectionRule { engineName -> includePatterns.any { it.matches(engineName) } }
}

/** Excludes the specified [engines] from test execution. */
fun except(vararg engines: String): EngineSelectionRule = except(engines.asList())

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class ContentEncodingIntegrationTest : ClientLoader() {

// GZipEncoder is implemented only on JVM.
@Test
fun testGzipWithContentLengthWithoutPlugin() = clientTests(only("jvm:*")) {
fun testGzipWithContentLengthWithoutPlugin() = clientTests(only("jvm:*", "web:Js")) {
test { client ->
val response = client.get("$TEST_URL/gzip-with-content-length")
val content = if (response.headers[HttpHeaders.ContentEncoding] == "gzip") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ class LoggingTest : ClientLoader() {
}

@Test
fun testLogLevelAll() = clientTests(except("native:CIO")) {
fun testLogLevelAll() = clientTests(except("native:CIO", "web:Js")) {
val logger = TestLogger(
"REQUEST: http://localhost:8080/logging",
"METHOD: HttpMethod(value=GET)",
Expand Down Expand Up @@ -103,7 +103,7 @@ class LoggingTest : ClientLoader() {
}

@Test
fun testLogLevelHeaders() = clientTests {
fun testLogLevelHeaders() = clientTests(except("web:Js")) {
val logger = TestLogger {
line("REQUEST: http://localhost:8080/logging")
line("METHOD: HttpMethod(value=GET)")
Expand Down Expand Up @@ -143,7 +143,7 @@ class LoggingTest : ClientLoader() {
}

@Test
fun testLogPostBody() = clientTests(except("native:CIO")) {
fun testLogPostBody() = clientTests(except("native:CIO", "web:Js")) {
val testLogger = TestLogger(
"REQUEST: http://localhost:8080/logging",
"METHOD: HttpMethod(value=POST)",
Expand Down Expand Up @@ -199,7 +199,7 @@ class LoggingTest : ClientLoader() {
}

@Test
fun testLogPostMalformedUtf8Body() = clientTests(except("native:CIO")) {
fun testLogPostMalformedUtf8Body() = clientTests(except("native:CIO", "web:Js")) {
val testLogger = TestLogger(
"REQUEST: http://localhost:8080/logging/non-utf",
"METHOD: HttpMethod(value=POST)",
Expand Down Expand Up @@ -255,7 +255,7 @@ class LoggingTest : ClientLoader() {
}

@Test
fun testRequestAndResponseBody() = clientTests(except("native:CIO")) {
fun testRequestAndResponseBody() = clientTests(except("native:CIO", "web:Js")) {
val testLogger = TestLogger(
"REQUEST: http://127.0.0.1:8080/content/echo",
"METHOD: HttpMethod(value=POST)",
Expand Down Expand Up @@ -305,7 +305,7 @@ class LoggingTest : ClientLoader() {
}

@Test
fun testRequestContentTypeInLog() = clientTests(except("Darwin", "native:CIO", "DarwinLegacy")) {
fun testRequestContentTypeInLog() = clientTests(except("Darwin", "native:CIO", "DarwinLegacy", "web:Js")) {
val testLogger = TestLogger(
"REQUEST: http://127.0.0.1:8080/content/echo",
"METHOD: HttpMethod(value=POST)",
Expand Down Expand Up @@ -357,7 +357,7 @@ class LoggingTest : ClientLoader() {
}

@Test
fun testLoggingWithCompression() = clientTests(except("Darwin", "DarwinLegacy", "native:CIO", "web:CIO")) {
fun testLoggingWithCompression() = clientTests(except("Darwin", "DarwinLegacy", "native:CIO", "web:*")) {
val testLogger = TestLogger(
"REQUEST: http://127.0.0.1:8080/compression/deflate",
"METHOD: HttpMethod(value=GET)",
Expand Down Expand Up @@ -504,7 +504,7 @@ class LoggingTest : ClientLoader() {
data class User(val name: String)

@Test
fun testLogPostBodyWithJson() = clientTests(retries = 5) {
fun testLogPostBodyWithJson() = clientTests(except("web:Js"), retries = 5) {
val testLogger = TestLogger(
"REQUEST: http://127.0.0.1:8080/content/echo",
"METHOD: HttpMethod(value=POST)",
Expand Down

0 comments on commit 359f2fc

Please sign in to comment.