Skip to content

Commit 167ed77

Browse files
authored
Fix custom MIME type serialization incompatibility (#261)
Fixes #260
1 parent 1163db9 commit 167ed77

File tree

3 files changed

+78
-3
lines changed

3 files changed

+78
-3
lines changed

rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/frame/io/mimeType.kt

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,13 @@ internal fun ByteReadPacket.readAuthType(): AuthType = readType(
4747

4848
private fun BytePacketBuilder.writeTextWithLength(text: String) {
4949
val typeBytes = text.encodeToByteArray()
50-
writeByte(typeBytes.size.toByte()) //write length
51-
writeFully(typeBytes) //write mime type
50+
// The first byte indicates MIME type encoding:
51+
// - Values 0x00 to 0x7F represent predefined "well-known" MIME types, directly using the byte as the type ID.
52+
// - Values 0x80 to 0xFF denote custom MIME types, where the byte represents the length of the MIME type name that follows.
53+
// For custom types, the length stored (byte value minus 0x80) is adjusted by -1 when writing, and adjusted by +1 when reading,
54+
// mapping to an effective range of 1 to 128 characters for the MIME type name length.
55+
writeByte((typeBytes.size - 1).toByte())
56+
writeFully(typeBytes)
5257
}
5358

5459
private const val KnownTypeFlag: Byte = Byte.MIN_VALUE
@@ -66,7 +71,12 @@ private inline fun <T> ByteReadPacket.readType(
6671
val identifier = byte xor KnownTypeFlag
6772
fromIdentifier(identifier)
6873
} else {
69-
val stringType = readTextExactBytes(byte.toInt())
74+
// The first byte indicates MIME type encoding:
75+
// - Values 0x00 to 0x7F represent predefined "well-known" MIME types, directly using the byte as the type ID.
76+
// - Values 0x80 to 0xFF denote custom MIME types, where the byte represents the length of the MIME type name that follows.
77+
// For custom types, the length stored (byte value minus 0x80) is adjusted by -1 when writing, and adjusted by +1 when reading,
78+
// mapping to an effective range of 1 to 128 characters for the MIME type name length.
79+
val stringType = readTextExactBytes(byte.toInt() + 1)
7080
fromText(stringType)
7181
}
7282
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright 2015-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.rsocket.kotlin.frame.io
18+
19+
import io.rsocket.kotlin.core.*
20+
import io.rsocket.kotlin.test.*
21+
import kotlin.test.*
22+
23+
class MimeTypeTest : TestWithLeakCheck {
24+
25+
@Test
26+
fun customMimeTypeSerialization() {
27+
testCustomMimeType("message/x.foo")
28+
testCustomMimeType(randomAsciiString(1))
29+
testCustomMimeType(randomAsciiString(127))
30+
testCustomMimeType(randomAsciiString(128))
31+
}
32+
33+
private fun testCustomMimeType(name: String) {
34+
val mimeType = CustomMimeType(name)
35+
val packet = packet {
36+
writeMimeType(mimeType)
37+
}
38+
assertEquals(name.length - 1, packet.tryPeek())
39+
assertEquals(mimeType, packet.readMimeType())
40+
}
41+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*
2+
* Copyright 2015-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.rsocket.kotlin.frame.io
18+
19+
20+
private val asciiChars = '!'..'~'
21+
22+
internal fun randomAsciiString(length: Int): String {
23+
return (1..length).joinToString(separator = "") { asciiChars.random().toString() }
24+
}

0 commit comments

Comments
 (0)