@@ -12,7 +12,7 @@ import io.ktor.server.response.*
1212import io.ktor.util.*
1313import io.ktor.util.logging.*
1414
15- private val LOGGER = KtorSimpleLogger (" io.ktor.server.plugins.cors.CORS" )
15+ internal val LOGGER = KtorSimpleLogger (" io.ktor.server.plugins.cors.CORS" )
1616
1717/* *
1818 * A plugin that allows you to configure handling cross-origin requests.
@@ -87,19 +87,27 @@ internal fun PluginBuilder<CORSConfig>.buildPlugin() {
8787 return @onCall
8888 }
8989
90+ LOGGER .info { " ${call.request.id()} : Start handler" }
91+
9092 if (! allowsAnyHost || allowCredentials) {
9193 call.corsVary()
9294 }
9395
94- val origin = call.request.headers.getAll(HttpHeaders .Origin )?.singleOrNull() ? : return @onCall
96+ val origin = call.request.headers.getAll(HttpHeaders .Origin )?.singleOrNull()
97+
98+ if (origin == null ) {
99+ LOGGER .info { " ${call.request.id()} : Skip CORS handler because request lacks the Origin header" }
100+ return @onCall
101+ }
95102
96103 val checkOrigin = checkOrigin(
97104 origin,
98- call.request.origin ,
105+ call.request,
99106 allowSameOrigin,
100107 allowsAnyHost,
101108 hostsNormalized,
102109 hostsWithWildcard,
110+ pluginConfig.hosts,
103111 originPredicates
104112 )
105113 when (checkOrigin) {
@@ -108,7 +116,7 @@ internal fun PluginBuilder<CORSConfig>.buildPlugin() {
108116
109117 OriginCheckResult .SkipCORS -> return @onCall
110118 OriginCheckResult .Failed -> {
111- LOGGER .trace( " Respond forbidden ${call.request.uri } : origin doesn't match ${call.request. origin} " )
119+ LOGGER .info { " ${call.request.id() } : CORS check fails because Origin $ origin does not match " }
112120 call.respondCorsFailed()
113121 return @onCall
114122 }
@@ -118,15 +126,18 @@ internal fun PluginBuilder<CORSConfig>.buildPlugin() {
118126 val contentType = call.request.header(HttpHeaders .ContentType )?.let { ContentType .parse(it) }
119127 if (contentType != null ) {
120128 if (contentType.withoutParameters() !in CORSConfig .CorsSimpleContentTypes ) {
121- LOGGER .trace(" Respond forbidden ${call.request.uri} : Content-Type isn't allowed $contentType " )
129+ LOGGER .info {
130+ " ${call.request.id()} : CORS check fails because the requested content type $contentType " +
131+ " is not in the list of the only allowed simple types ${CORSConfig .CorsSimpleContentTypes } "
132+ }
122133 call.respondCorsFailed()
123134 return @onCall
124135 }
125136 }
126137 }
127138
128139 if (call.request.httpMethod == HttpMethod .Options ) {
129- LOGGER .trace( " Respond preflight on OPTIONS for ${call.request.uri} " )
140+ LOGGER .info { " ${call.request.id()} : Start preflight handler " }
130141 call.respondPreflight(
131142 origin,
132143 methodsListHeaderValue,
@@ -142,11 +153,16 @@ internal fun PluginBuilder<CORSConfig>.buildPlugin() {
142153 }
143154
144155 if (! call.corsCheckCurrentMethod(methods)) {
145- LOGGER .trace(" Respond forbidden ${call.request.uri} : method doesn't match ${call.request.httpMethod} " )
156+ LOGGER .info {
157+ " ${call.request.id()} : CORS check fails because HTTP method ${call.request.httpMethod.value} " +
158+ " is not allowed. Allowed methods: $methods "
159+ }
146160 call.respondCorsFailed()
147161 return @onCall
148162 }
149163
164+ LOGGER .info { " ${call.request.id()} : CORS check is succeeded" }
165+
150166 call.accessControlAllowOrigin(origin, allowsAnyHost, allowCredentials)
151167 call.accessControlAllowCredentials(allowCredentials)
152168
@@ -156,6 +172,10 @@ internal fun PluginBuilder<CORSConfig>.buildPlugin() {
156172 }
157173}
158174
175+ internal fun ApplicationRequest.id (): String {
176+ return " ${httpMethod.value} $uri "
177+ }
178+
159179private enum class OriginCheckResult {
160180 OK ,
161181 SkipCORS ,
@@ -164,20 +184,29 @@ private enum class OriginCheckResult {
164184
165185private fun checkOrigin (
166186 origin : String ,
167- point : RequestConnectionPoint ,
187+ request : ApplicationRequest ,
168188 allowSameOrigin : Boolean ,
169189 allowsAnyHost : Boolean ,
170190 hostsNormalized : Set <String >,
171191 hostsWithWildcard : Set <Pair <String , String >>,
192+ allowedHosts : Set <String >,
172193 originPredicates : List <(String ) -> Boolean >
173194): OriginCheckResult = when {
174- ! isValidOrigin(origin) -> OriginCheckResult .SkipCORS
175- allowSameOrigin && isSameOrigin(origin, point) -> OriginCheckResult .SkipCORS
195+ ! isValidOrigin(origin) -> {
196+ LOGGER .info { " ${request.id()} : Skip CORS handler because Origin $origin is malformed" }
197+ OriginCheckResult .SkipCORS
198+ }
199+ allowSameOrigin && isSameOrigin(origin, request.origin) -> {
200+ LOGGER .info { " ${request.id()} : Skip CORS handler because Origin $origin matches the server origin exactly" }
201+ OriginCheckResult .SkipCORS
202+ }
176203 ! corsCheckOrigins(
204+ request,
177205 origin,
178206 allowsAnyHost,
179207 hostsNormalized,
180208 hostsWithWildcard,
209+ allowedHosts,
181210 originPredicates
182211 ) -> OriginCheckResult .Failed
183212
@@ -204,13 +233,23 @@ private suspend fun ApplicationCall.respondPreflight(
204233 } ? : emptyList()
205234
206235 if (! corsCheckRequestMethod(methods)) {
207- LOGGER .trace( " Return Forbidden for ${ this . request.uri } : CORS method doesn't match ${request.httpMethod} " )
236+ LOGGER .info { " ${ request.id() } : Preflight: Request method check fails " }
208237 respond(HttpStatusCode .Forbidden )
209238 return
210239 }
211240
212241 if (! corsCheckRequestHeaders(requestHeaders, allHeadersSet, headerPredicates)) {
213- LOGGER .trace(" Return Forbidden for ${this .request.uri} : request has not allowed headers." )
242+ LOGGER .info {
243+ val disallowedHeaders = requestHeaders.filterNot { header ->
244+ header in allHeadersSet || headerMatchesAPredicate(header, headerPredicates)
245+ }
246+
247+ " ${request.id()} : Preflight: Headers $disallowedHeaders are not allowed. " +
248+ " Allowed headers: $allHeadersSet . " +
249+ if (headerPredicates.isNotEmpty()) " Allowed Header predicates: $headerPredicates " else " "
250+ }
251+
252+ LOGGER .info { " ${request.id()} : Preflight: Check on headers from Access-Control-Request-Headers fails" }
214253 respond(HttpStatusCode .Forbidden )
215254 return
216255 }
0 commit comments