in ktor-http/ktor-http-cio/jvm/src/io/ktor/http/cio/Multipart.kt [479:557]
public fun parseBoundary(contentType: CharSequence): ByteBuffer {
val boundaryParameter = findBoundary(contentType)
if (boundaryParameter == -1) throw IOException("Failed to parse multipart: Content-Type's boundary parameter is missing")
val boundaryStart = boundaryParameter + 9
val boundaryBytes: ByteBuffer = ByteBuffer.allocate(74)
boundaryBytes.put(0x0d)
boundaryBytes.put(0x0a)
boundaryBytes.put(PrefixChar)
boundaryBytes.put(PrefixChar)
var state = 0 // 0 - skipping spaces, 1 - unquoted characters, 2 - quoted no escape, 3 - quoted after escape
loop@ for (i in boundaryStart until contentType.length) {
val ch = contentType[i]
val v = ch.toInt() and 0xffff
if (v and 0xffff > 0x7f) throw IOException("Failed to parse multipart: wrong boundary byte 0x${v.toString(16)} - should be 7bit character")
when (state) {
0 -> {
when (ch) {
' ' -> {
// skip space
}
'"' -> {
state = 2 // start quoted string parsing
}
';', ',' -> {
break@loop
}
else -> {
state = 1
boundaryBytes.put(v.toByte())
}
}
}
1 -> { // non-quoted string
if (ch == ' ' || ch == ',' || ch == ';') { // space, comma or semicolon (;)
break@loop
} else if (boundaryBytes.hasRemaining()) {
boundaryBytes.put(v.toByte())
} else {
// RFC 2046, sec 5.1.1
throw IOException("Failed to parse multipart: boundary shouldn't be longer than 70 characters")
}
}
2 -> {
if (ch == '\\') {
state = 3
} else if (ch == '"') {
break@loop
} else if (boundaryBytes.hasRemaining()) {
boundaryBytes.put(v.toByte())
} else {
// RFC 2046, sec 5.1.1
throw IOException("Failed to parse multipart: boundary shouldn't be longer than 70 characters")
}
}
3 -> {
if (boundaryBytes.hasRemaining()) {
boundaryBytes.put(v.toByte())
state = 2
} else {
// RFC 2046, sec 5.1.1
throw IOException("Failed to parse multipart: boundary shouldn't be longer than 70 characters")
}
}
}
}
boundaryBytes.flip()
if (boundaryBytes.remaining() == 4) {
throw IOException("Empty multipart boundary is not allowed")
}
return boundaryBytes
}