Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

KTOR-3757 Allow specifying custom CacheControl directives #3318

Merged
merged 1 commit into from Dec 15, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion ktor-http/api/ktor-http.api
Expand Up @@ -7,7 +7,7 @@ public final class io/ktor/http/BadContentTypeFormatException : java/lang/Except
}

public abstract class io/ktor/http/CacheControl {
public synthetic fun <init> (Lio/ktor/http/CacheControl$Visibility;Lkotlin/jvm/internal/DefaultConstructorMarker;)V
public fun <init> (Lio/ktor/http/CacheControl$Visibility;)V
public final fun getVisibility ()Lio/ktor/http/CacheControl$Visibility;
}

Expand Down
2 changes: 1 addition & 1 deletion ktor-http/common/src/io/ktor/http/CacheControl.kt
Expand Up @@ -9,7 +9,7 @@ package io.ktor.http
*
* @param visibility specifies an optional visibility such as private or public
*/
public sealed class CacheControl(public val visibility: Visibility?) {
public abstract class CacheControl(public val visibility: Visibility?) {

/**
* Controls caching by proxies
Expand Down
Expand Up @@ -12,8 +12,8 @@ import io.ktor.http.*
* Currently, visibility is pinned to the expiration directive,
* then to the first no-cache,
* then to the no-store directive.
* The RFC doesn't state, where a visibility modifier should be so we can place it at any place
* so there is nothing behind the rule beyond, therefore could be changed.
* The RFC doesn't state where a visibility modifier should be, so we can place it at any place
* so there is nothing behind the rule beyond, therefore, could be changed.
*
* Only one visibility specifier is kept.
*
Expand All @@ -26,7 +26,7 @@ import io.ktor.http.*
*
* Revalidation directives are collected as well.
* Currently, revalidation directives are tied to max age by-design.
* This is not fair according to RFC so will be changed in the future.
* This is not fair, according to RFC, so it will be changed in the future.
*/
internal fun List<CacheControl>.mergeCacheControlDirectives(): List<CacheControl> {
if (size < 2) return this
Expand All @@ -50,6 +50,12 @@ internal fun List<CacheControl>.mergeCacheControlDirectives(): List<CacheControl
noCacheDirective?.let { add(CacheControl.NoCache(null)) }
noStoreDirective?.let { add(CacheControl.NoStore(null)) }

this@mergeCacheControlDirectives
.filter {
it !is CacheControl.NoCache && it !is CacheControl.NoStore && it !is CacheControl.MaxAge
}
.let { addAll(it) }

if (maxAgeDirectives.isNotEmpty()) {
add(
CacheControl.MaxAge(
Expand Down
Expand Up @@ -62,6 +62,26 @@ class CachingHeadersTest {
}
)

object Immutable: CacheControl(null) {
override fun toString(): String = "immutable"
}

@Test
fun testCustomCacheControl(): Unit = test(
configure = {
install(CachingHeaders) {
options { _, _ -> CachingOptions(CacheControl.NoStore(CacheControl.Visibility.Private)) }
options { _, _ -> CachingOptions(Immutable) }
}
},
test = { response ->
assertEquals(
"no-cache, private, no-store, immutable",
response.headers[HttpHeaders.CacheControl]
)
}
)

@Test
fun testSetInCall() = testApplication {
install(CachingHeaders)
Expand Down