@@ -167,6 +167,7 @@ private[engine] final class HttpHeaderParser private (
167167 private def parseRawHeader (input : ByteString , lineStart : Int , cursor : Int , nodeIx : Int ): Int = {
168168 val colonIx = input.indexOf(':' , cursor, lineStart + 1 + maxHeaderNameLength)
169169 if (colonIx == - 1 ) {
170+ scanIllegalHeaderNameCharacters(input, cursor, lineStart + 1 + maxHeaderNameLength)
170171 fail(s " HTTP header name exceeds the configured limit of $maxHeaderNameLength characters " ,
171172 StatusCodes .RequestHeaderFieldsTooLarge )
172173 } else {
@@ -210,6 +211,32 @@ private[engine] final class HttpHeaderParser private (
210211 if (start == end) " " else build()
211212 }
212213
214+ // similar to scanAsciiString but only scans for illegal characters and fails or warns if it finds one
215+ private def scanIllegalHeaderNameCharacters (input : ByteString , start : Int , end : Int ): Unit = {
216+ @ tailrec def check (ix : Int = start): Unit =
217+ if (ix == end) {
218+ ()
219+ } else {
220+ val c = input(ix).toChar
221+ if (tchar(c)) {
222+ check(ix + 1 )
223+ } else {
224+ settings.illegalResponseHeaderNameProcessingMode match {
225+ case IllegalResponseHeaderNameProcessingMode .Error =>
226+ fail(s " Illegal character ' ${escape(c)}' in header name " )
227+ case IllegalResponseHeaderNameProcessingMode .Warn =>
228+ log.warning(s " Header key contains illegal character ' ${escape(c)}' " )
229+ check(ix + 1 )
230+ case IllegalResponseHeaderNameProcessingMode .Ignore =>
231+ ()
232+ }
233+ }
234+ }
235+ if (start == end || settings.illegalResponseHeaderNameProcessingMode == IllegalResponseHeaderNameProcessingMode .Ignore )
236+ ()
237+ else check()
238+ }
239+
213240 @ tailrec
214241 private def parseHeaderValue (input : ByteString , valueStart : Int , branch : ValueBranch )(cursor : Int = valueStart,
215242 nodeIx : Int = branch.branchRootNodeIx): Int = {
0 commit comments