1
1
package no.nav.helse.dusseldorf.ktor.core
2
2
3
- import io.ktor.server.application.ApplicationCall
4
- import io.ktor.server.application.ApplicationCallPipeline
5
- import io.ktor.server.application.BaseApplicationPlugin
6
- import io.ktor.server.plugins.callid.callId
7
- import io.ktor.server.plugins.callid.CallIdConfig
8
3
import io.ktor.http.HttpHeaders
9
4
import io.ktor.http.encodeURLParameter
10
- import io.ktor.server.application.PipelineCall
5
+ import io.ktor.server.plugins.callid.CallIdConfig
11
6
import io.ktor.server.request.header
12
- import io.ktor.server.routing.Route
13
- import io.ktor.server.routing.application
14
- import io.ktor.util.AttributeKey
15
- import io.ktor.util.pipeline.PipelineContext
16
7
import org.slf4j.Logger
17
8
import org.slf4j.LoggerFactory
18
9
import java.util.*
@@ -22,21 +13,27 @@ internal object IdVerifier {
22
13
private const val NorskeBokstaver = " æøåÆØÅ"
23
14
private const val GeneratedIdPrefix = " generated-"
24
15
25
- private val idRegex = " [a-zA-Z0-9_.\\ -${NorskeBokstaver } ]{5,200}" .toRegex()
26
- internal fun verifyId (type : String , id : String ) = idRegex.matches(id).also { valid ->
16
+ private val idRegex = " [a-zA-Z0-9_.\\ -${NorskeBokstaver } ]{5,200}" .toRegex()
17
+ internal fun verifyId (type : String , id : String ) = idRegex.matches(id).also { valid ->
27
18
if (! valid) logger.warn(" Ugyldig $type =[${id.encodeURLParameter()} ] (url-encoded)" )
28
19
}
20
+
29
21
internal fun generate () = " $GeneratedIdPrefix${UUID .randomUUID()} "
30
22
internal fun String.trimId () = removePrefix(GeneratedIdPrefix )
31
23
}
32
24
33
- fun CallIdConfig.fromFirstNonNullHeader (headers : List <String >, generateOnInvalid : Boolean = false, generateOnNotSet : Boolean = false) {
25
+ fun CallIdConfig.fromFirstNonNullHeader (
26
+ headers : List <String >,
27
+ generateOnInvalid : Boolean = false,
28
+ generateOnNotSet : Boolean = false,
29
+ ) {
34
30
retrieve { call ->
35
31
when (val fromHeaders = headers.mapNotNull { call.request.header(it) }.firstOrNull()) {
36
32
null -> when (generateOnNotSet) {
37
33
true -> IdVerifier .generate()
38
34
false -> fromHeaders
39
35
}
36
+
40
37
else -> when (IdVerifier .verifyId(type = HttpHeaders .XCorrelationId , id = fromHeaders)) {
41
38
true -> fromHeaders
42
39
false -> when (generateOnInvalid) {
@@ -51,52 +48,12 @@ fun CallIdConfig.fromFirstNonNullHeader(headers: List<String>, generateOnInvalid
51
48
}
52
49
53
50
// Henter fra CorrelationID (backend tjenester)
54
- fun CallIdConfig.fromXCorrelationIdHeader (generateOnInvalid : Boolean = false, generateOnNotSet : Boolean = false) = fromFirstNonNullHeader(
55
- headers = listOf (HttpHeaders .XCorrelationId ), generateOnInvalid = generateOnInvalid, generateOnNotSet = false
56
- )
51
+ fun CallIdConfig.fromXCorrelationIdHeader (generateOnInvalid : Boolean = false, generateOnNotSet : Boolean = false) =
52
+ fromFirstNonNullHeader(
53
+ headers = listOf (HttpHeaders .XCorrelationId ), generateOnInvalid = generateOnInvalid, generateOnNotSet = false
54
+ )
57
55
58
56
// Genererer CorrelationID (frontend tjeneste)
59
57
fun CallIdConfig.generated () {
60
58
generate { IdVerifier .generate() }
61
59
}
62
-
63
- class Configuration
64
- class CallIdRequired (private val configure : Configuration ) {
65
-
66
- private val logger = LoggerFactory .getLogger(" no.nav.helse.dusseldorf.ktor.core.CallIdRequired" )
67
-
68
- private val problemDetails = ValidationProblemDetails (
69
- setOf (Violation (
70
- parameterName = HttpHeaders .XCorrelationId ,
71
- parameterType = ParameterType .HEADER ,
72
- reason = " Correlation ID må settes." ,
73
- invalidValue = null
74
- ))
75
- )
76
-
77
- fun interceptPipeline (route : Route ) {
78
- route.application.intercept(ApplicationCallPipeline .Monitoring ) {
79
- require(this )
80
- }
81
- }
82
-
83
- private suspend fun require (context : PipelineContext <Unit , PipelineCall >) {
84
- val callId = context.context.callId
85
- if (callId == null ) {
86
- context.context.respondProblemDetails(problemDetails, logger)
87
- context.finish()
88
- } else {
89
- context.proceed()
90
- }
91
- }
92
-
93
- companion object Feature :
94
- BaseApplicationPlugin <ApplicationCallPipeline , Configuration , CallIdRequired > {
95
-
96
- override fun install (pipeline : ApplicationCallPipeline , configure : Configuration .() -> Unit ): CallIdRequired {
97
- return CallIdRequired (Configuration ().apply (configure))
98
- }
99
-
100
- override val key = AttributeKey <CallIdRequired >(" CallIdRequired" )
101
- }
102
- }
0 commit comments