Skip to content

Commit

Permalink
KTOR-3757 Allow specifying custom CacheControl directives (ktorio#3318)
Browse files Browse the repository at this point in the history
  • Loading branch information
rsinukov authored and Rattenkrieg committed Jan 5, 2023
1 parent c2f49e8 commit c287bd4
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 5 deletions.
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

0 comments on commit c287bd4

Please sign in to comment.