Skip to content

Commit c80b3cb

Browse files
committed
Polishing contribution
Closes rsocketgh-998 Signed-off-by: Rossen Stoyanchev <[email protected]>
1 parent 7370128 commit c80b3cb

File tree

2 files changed

+72
-79
lines changed

2 files changed

+72
-79
lines changed

rsocket-core/src/main/java/io/rsocket/metadata/MimeTypeMetadataCodec.java

Lines changed: 51 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2015-2018 the original author or authors.
2+
* Copyright 2015-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -24,7 +24,7 @@
2424
import java.util.List;
2525

2626
/**
27-
* Provides support for encoding and/or decoding the per-stream MIME type to use for payload data.
27+
* Provides support for encoding and decoding the per-stream MIME type to use for payload data.
2828
*
2929
* <p>For more on the format of the metadata, see the <a
3030
* href="https://github.com/rsocket/rsocket/blob/master/Extensions/PerStreamDataMimeTypesDefinition.md">
@@ -33,30 +33,34 @@
3333
* @since 1.1.1
3434
*/
3535
public class MimeTypeMetadataCodec {
36+
3637
private static final int STREAM_METADATA_KNOWN_MASK = 0x80; // 1000 0000
38+
3739
private static final byte STREAM_METADATA_LENGTH_MASK = 0x7F; // 0111 1111
3840

3941
private MimeTypeMetadataCodec() {}
4042

4143
/**
42-
* Encode a {@link WellKnownMimeType} into a newly allocated {@link ByteBuf} and this can then be
43-
* decoded using {@link #decode(ByteBuf)}.
44+
* Encode a {@link WellKnownMimeType} into a newly allocated single byte {@link ByteBuf}.
45+
*
46+
* @param allocator the allocator to create the buffer with
47+
* @param mimeType well-known MIME type to encode
48+
* @return the resulting buffer
4449
*/
4550
public static ByteBuf encode(ByteBufAllocator allocator, WellKnownMimeType mimeType) {
4651
return allocator.buffer(1, 1).writeByte(mimeType.getIdentifier() | STREAM_METADATA_KNOWN_MASK);
4752
}
4853

4954
/**
50-
* Encode either a {@link WellKnownMimeType} or a custom mime type into a newly allocated {@link
51-
* ByteBuf}.
55+
* Encode the given MIME type into a newly allocated {@link ByteBuf}.
5256
*
53-
* @param allocator the {@link ByteBufAllocator} to use to create the buffer
54-
* @param mimeType mime type
55-
* @return the encoded mime type
57+
* @param allocator the allocator to create the buffer with
58+
* @param mimeType MIME type to encode
59+
* @return the resulting buffer
5660
*/
5761
public static ByteBuf encode(ByteBufAllocator allocator, String mimeType) {
5862
if (mimeType == null || mimeType.length() == 0) {
59-
throw new IllegalArgumentException("Mime type null or length is zero");
63+
throw new IllegalArgumentException("MIME type is required");
6064
}
6165
WellKnownMimeType wkn = WellKnownMimeType.fromString(mimeType);
6266
if (wkn == WellKnownMimeType.UNPARSEABLE_MIME_TYPE) {
@@ -67,79 +71,65 @@ public static ByteBuf encode(ByteBufAllocator allocator, String mimeType) {
6771
}
6872

6973
/**
70-
* Encode multiple {@link WellKnownMimeType} or custom mime type into a newly allocated {@link
71-
* ByteBuf}.
74+
* Encode multiple MIME types into a newly allocated {@link ByteBuf}.
7275
*
73-
* @param allocator the {@link ByteBufAllocator} to use to create the buffer
74-
* @param mimeTypes mime types
75-
* @return the encoded mime types
76+
* @param allocator the allocator to create the buffer with
77+
* @param mimeTypes MIME types to encode
78+
* @return the resulting buffer
7679
*/
7780
public static ByteBuf encode(ByteBufAllocator allocator, List<String> mimeTypes) {
7881
if (mimeTypes == null || mimeTypes.size() == 0) {
79-
throw new IllegalArgumentException("Mime types empty");
82+
throw new IllegalArgumentException("No MIME types provided");
8083
}
81-
CompositeByteBuf compositeMimeByteBuf = allocator.compositeBuffer();
84+
CompositeByteBuf compositeByteBuf = allocator.compositeBuffer();
8285
for (String mimeType : mimeTypes) {
83-
compositeMimeByteBuf.addComponents(true, encode(allocator, mimeType));
86+
ByteBuf byteBuf = encode(allocator, mimeType);
87+
compositeByteBuf.addComponents(true, byteBuf);
8488
}
85-
return compositeMimeByteBuf;
89+
return compositeByteBuf;
8690
}
8791

88-
/**
89-
* Encode a custom mime type into a newly allocated {@link ByteBuf}.
90-
*
91-
* <p>This larger representation encodes the mime type representation's length on a single byte,
92-
* then the representation itself.
93-
*
94-
* @param allocator the {@link ByteBufAllocator} to use to create the buffer
95-
* @param customMimeType a custom mime type to encode
96-
* @return the encoded mime type
97-
*/
9892
private static ByteBuf encodeCustomMimeType(ByteBufAllocator allocator, String customMimeType) {
99-
ByteBuf mime = allocator.buffer(1 + customMimeType.length());
100-
// reserve 1 byte for the customMime length
101-
// /!\ careful not to read that first byte, which is random at this point
102-
mime.writerIndex(1);
93+
ByteBuf byteBuf = allocator.buffer(1 + customMimeType.length());
94+
95+
byteBuf.writerIndex(1);
96+
int length = ByteBufUtil.writeUtf8(byteBuf, customMimeType);
10397

104-
// write the custom mime in UTF8 but validate it is all ASCII-compatible
105-
// (which produces the right result since ASCII chars are still encoded on 1 byte in UTF8)
106-
int customMimeLength = ByteBufUtil.writeUtf8(mime, customMimeType);
107-
if (!ByteBufUtil.isText(mime, mime.readerIndex() + 1, customMimeLength, CharsetUtil.US_ASCII)) {
108-
mime.release();
109-
throw new IllegalArgumentException("custom mime type must be US_ASCII characters only");
98+
if (!ByteBufUtil.isText(byteBuf, 1, length, CharsetUtil.US_ASCII)) {
99+
byteBuf.release();
100+
throw new IllegalArgumentException("MIME type must be ASCII characters only");
110101
}
111-
if (customMimeLength < 1 || customMimeLength > 128) {
112-
mime.release();
102+
103+
if (length < 1 || length > 128) {
104+
byteBuf.release();
113105
throw new IllegalArgumentException(
114-
"custom mime type must have a strictly positive length that fits on 7 unsigned bits, ie 1-128");
106+
"MIME type must have a strictly positive length that fits on 7 unsigned bits, ie 1-128");
115107
}
116-
mime.markWriterIndex();
117-
// go back to beginning and write the length
118-
// encoded length is one less than actual length, since 0 is never a valid length, which gives
119-
// wider representation range
120-
mime.writerIndex(0);
121-
mime.writeByte(customMimeLength - 1);
122108

123-
// go back to post-mime type
124-
mime.resetWriterIndex();
125-
return mime;
109+
byteBuf.markWriterIndex();
110+
byteBuf.writerIndex(0);
111+
byteBuf.writeByte(length - 1);
112+
byteBuf.resetWriterIndex();
113+
114+
return byteBuf;
126115
}
127116

128117
/**
129-
* Decode mime types from a {@link ByteBuf} that contains at least enough bytes for one mime type.
118+
* Decode the per-stream MIME type metadata encoded in the given {@link ByteBuf}.
130119
*
131-
* @return decoded mime types
120+
* @return the decoded MIME types
132121
*/
133-
public static List<String> decode(ByteBuf buf) {
122+
public static List<String> decode(ByteBuf byteBuf) {
134123
List<String> mimeTypes = new ArrayList<>();
135-
while (buf.isReadable()) {
136-
byte mimeIdOrLength = buf.readByte();
137-
if ((mimeIdOrLength & STREAM_METADATA_KNOWN_MASK) == STREAM_METADATA_KNOWN_MASK) {
138-
byte mimeIdentifier = (byte) (mimeIdOrLength & STREAM_METADATA_LENGTH_MASK);
139-
mimeTypes.add(WellKnownMimeType.fromIdentifier(mimeIdentifier).toString());
124+
while (byteBuf.isReadable()) {
125+
byte idOrLength = byteBuf.readByte();
126+
if ((idOrLength & STREAM_METADATA_KNOWN_MASK) == STREAM_METADATA_KNOWN_MASK) {
127+
byte id = (byte) (idOrLength & STREAM_METADATA_LENGTH_MASK);
128+
WellKnownMimeType wellKnownMimeType = WellKnownMimeType.fromIdentifier(id);
129+
mimeTypes.add(wellKnownMimeType.toString());
140130
} else {
141-
int mimeLen = Byte.toUnsignedInt(mimeIdOrLength) + 1;
142-
mimeTypes.add(buf.readCharSequence(mimeLen, CharsetUtil.US_ASCII).toString());
131+
int length = Byte.toUnsignedInt(idOrLength) + 1;
132+
mimeTypes.add(byteBuf.readCharSequence(length, CharsetUtil.US_ASCII).toString());
143133
}
144134
}
145135
return mimeTypes;

rsocket-core/src/test/java/io/rsocket/metadata/MimeMetadataCodecTest.java renamed to rsocket-core/src/test/java/io/rsocket/metadata/MimeTypeMetadataCodecTest.java

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -15,39 +15,42 @@
1515
*/
1616
package io.rsocket.metadata;
1717

18+
import static org.assertj.core.api.Assertions.assertThat;
19+
1820
import io.netty.buffer.ByteBuf;
1921
import io.netty.buffer.ByteBufAllocator;
2022
import java.util.List;
21-
import org.assertj.core.api.Assertions;
2223
import org.assertj.core.util.Lists;
2324
import org.junit.Test;
2425

25-
public class MimeMetadataCodecTest {
26+
/** Unit tests for {@link MimeTypeMetadataCodec}. */
27+
public class MimeTypeMetadataCodecTest {
2628

2729
@Test
28-
public void customMimeType() {
29-
String customMimeType = "aaa/bb";
30-
ByteBuf byteBuf = MimeTypeMetadataCodec.encode(ByteBufAllocator.DEFAULT, customMimeType);
30+
public void wellKnownMimeType() {
31+
WellKnownMimeType mimeType = WellKnownMimeType.APPLICATION_HESSIAN;
32+
ByteBuf byteBuf = MimeTypeMetadataCodec.encode(ByteBufAllocator.DEFAULT, mimeType);
3133
List<String> mimeTypes = MimeTypeMetadataCodec.decode(byteBuf);
32-
Assertions.assertThat(mimeTypes.size()).isEqualTo(1);
33-
Assertions.assertThat(customMimeType).isEqualTo(mimeTypes.get(0));
34+
35+
assertThat(mimeTypes.size()).isEqualTo(1);
36+
assertThat(WellKnownMimeType.fromString(mimeTypes.get(0))).isEqualTo(mimeType);
3437
}
3538

3639
@Test
37-
public void wellKnowMimeType() {
38-
WellKnownMimeType wellKnownMimeType = WellKnownMimeType.APPLICATION_HESSIAN;
39-
ByteBuf byteBuf = MimeTypeMetadataCodec.encode(ByteBufAllocator.DEFAULT, wellKnownMimeType);
40-
List<String> mimes = MimeTypeMetadataCodec.decode(byteBuf);
41-
Assertions.assertThat(mimes.size()).isEqualTo(1);
42-
Assertions.assertThat(wellKnownMimeType).isEqualTo(WellKnownMimeType.fromString(mimes.get(0)));
40+
public void customMimeType() {
41+
String mimeType = "aaa/bb";
42+
ByteBuf byteBuf = MimeTypeMetadataCodec.encode(ByteBufAllocator.DEFAULT, mimeType);
43+
List<String> mimeTypes = MimeTypeMetadataCodec.decode(byteBuf);
44+
45+
assertThat(mimeTypes.size()).isEqualTo(1);
46+
assertThat(mimeTypes.get(0)).isEqualTo(mimeType);
4347
}
4448

4549
@Test
46-
public void multipleAndMixMimeType() {
47-
List<String> mimeTypes =
48-
Lists.newArrayList("aaa/bbb", WellKnownMimeType.APPLICATION_HESSIAN.getString());
50+
public void multipleMimeTypes() {
51+
List<String> mimeTypes = Lists.newArrayList("aaa/bbb", "application/x-hessian");
4952
ByteBuf byteBuf = MimeTypeMetadataCodec.encode(ByteBufAllocator.DEFAULT, mimeTypes);
50-
List<String> decodedMimeTypes = MimeTypeMetadataCodec.decode(byteBuf);
51-
Assertions.assertThat(decodedMimeTypes).isEqualTo(mimeTypes);
53+
54+
assertThat(MimeTypeMetadataCodec.decode(byteBuf)).isEqualTo(mimeTypes);
5255
}
5356
}

0 commit comments

Comments
 (0)