18
18
import static org .assertj .core .api .AssertionsForClassTypes .assertThat ;
19
19
20
20
import io .reactivex .Flowable ;
21
+ import io .reactivex .subscribers .TestSubscriber ;
21
22
import java .nio .ByteBuffer ;
22
23
import java .nio .charset .StandardCharsets ;
23
24
import java .util .ArrayList ;
26
27
import java .util .List ;
27
28
import java .util .PrimitiveIterator ;
28
29
import java .util .Random ;
30
+ import java .util .concurrent .TimeUnit ;
29
31
import java .util .stream .Collectors ;
30
32
import java .util .stream .Stream ;
31
33
import org .junit .jupiter .api .BeforeEach ;
@@ -56,6 +58,7 @@ public void subscribe_publisherEmpty_onlyProducesTrailer() {
56
58
.addTrailer (() -> Pair .of ("foo" , Collections .singletonList ("1" )))
57
59
.addTrailer (() -> Pair .of ("bar" , Collections .singletonList ("2" )))
58
60
.addEmptyTrailingChunk (true )
61
+ .contentLength (0 )
59
62
.build ();
60
63
61
64
List <ByteBuffer > chunks = getAllElements (build );
@@ -73,12 +76,14 @@ public void subscribe_publisherEmpty_onlyProducesTrailer() {
73
76
74
77
@ Test
75
78
void subscribe_trailerProviderPresent_trailerPartAdded () {
79
+ int contentLength = 8 ;
76
80
TestPublisher upstream = randomPublisherOfLength (8 );
77
81
78
82
TrailerProvider trailerProvider = new StaticTrailerProvider ("foo" , "bar" );
79
83
80
84
ChunkedEncodedPublisher chunkedPublisher = ChunkedEncodedPublisher .builder ()
81
85
.publisher (upstream )
86
+ .contentLength (contentLength )
82
87
.chunkSize (CHUNK_SIZE )
83
88
.addEmptyTrailingChunk (true )
84
89
.addTrailer (trailerProvider )
@@ -93,12 +98,14 @@ void subscribe_trailerProviderPresent_trailerPartAdded() {
93
98
94
99
@ Test
95
100
void subscribe_trailerProviderPresent_multipleValues_trailerPartAdded () {
96
- TestPublisher upstream = randomPublisherOfLength (8 );
101
+ int contentLength = 8 ;
102
+ TestPublisher upstream = randomPublisherOfLength (contentLength );
97
103
98
104
TrailerProvider trailerProvider = new StaticTrailerProvider ("foo" , Arrays .asList ("bar1" , "bar2" , "bar3" ));
99
105
100
106
ChunkedEncodedPublisher chunkedPublisher = ChunkedEncodedPublisher .builder ()
101
107
.publisher (upstream )
108
+ .contentLength (contentLength )
102
109
.chunkSize (CHUNK_SIZE )
103
110
.addEmptyTrailingChunk (true )
104
111
.addTrailer (trailerProvider )
@@ -113,14 +120,16 @@ void subscribe_trailerProviderPresent_multipleValues_trailerPartAdded() {
113
120
114
121
@ Test
115
122
void subscribe_trailerProviderPresent_onlyInvokedOnce () {
116
- TestPublisher upstream = randomPublisherOfLength (8 );
123
+ int contentLength = 8 ;
124
+ TestPublisher upstream = randomPublisherOfLength (contentLength );
117
125
118
126
TrailerProvider trailerProvider = Mockito .spy (new StaticTrailerProvider ("foo" , "bar" ));
119
127
120
128
ChunkedEncodedPublisher chunkedPublisher = ChunkedEncodedPublisher .builder ()
121
129
.publisher (upstream )
122
130
.addEmptyTrailingChunk (true )
123
131
.chunkSize (CHUNK_SIZE )
132
+ .contentLength (contentLength )
124
133
.addTrailer (trailerProvider ).build ();
125
134
126
135
getAllElements (chunkedPublisher );
@@ -130,13 +139,15 @@ void subscribe_trailerProviderPresent_onlyInvokedOnce() {
130
139
131
140
@ Test
132
141
void subscribe_trailerPresent_trailerFormattedCorrectly () {
133
- TestPublisher testPublisher = randomPublisherOfLength (32 );
142
+ int contentLength = 32 ;
143
+ TestPublisher testPublisher = randomPublisherOfLength (contentLength );
134
144
135
145
TrailerProvider trailerProvider = new StaticTrailerProvider ("foo" , "bar" );
136
146
137
147
ChunkedEncodedPublisher chunkedPublisher = newChunkedBuilder (testPublisher )
138
148
.addTrailer (trailerProvider )
139
149
.addEmptyTrailingChunk (true )
150
+ .contentLength (contentLength )
140
151
.build ();
141
152
142
153
List <ByteBuffer > chunks = getAllElements (chunkedPublisher );
@@ -152,11 +163,13 @@ void subscribe_trailerPresent_trailerFormattedCorrectly() {
152
163
153
164
@ Test
154
165
void subscribe_wrappedDoesNotFillBuffer_allDataInSingleChunk () {
155
- ByteBuffer element = ByteBuffer .wrap ("hello world" .getBytes (StandardCharsets .UTF_8 ));
166
+ byte [] content = "hello world" .getBytes (StandardCharsets .UTF_8 );
167
+ ByteBuffer element = ByteBuffer .wrap (content );
156
168
Flowable <ByteBuffer > upstream = Flowable .just (element .duplicate ());
157
169
158
170
ChunkedEncodedPublisher publisher = ChunkedEncodedPublisher .builder ()
159
171
.chunkSize (CHUNK_SIZE )
172
+ .contentLength (content .length )
160
173
.publisher (upstream )
161
174
.build ();
162
175
@@ -169,7 +182,8 @@ void subscribe_wrappedDoesNotFillBuffer_allDataInSingleChunk() {
169
182
170
183
@ Test
171
184
void subscribe_extensionHasNoValue_formattedCorrectly () {
172
- TestPublisher testPublisher = randomPublisherOfLength (8 );
185
+ int contentLength = 8 ;
186
+ TestPublisher testPublisher = randomPublisherOfLength (contentLength );
173
187
174
188
ChunkExtensionProvider extensionProvider = new StaticExtensionProvider ("foo" , "" );
175
189
@@ -178,6 +192,7 @@ void subscribe_extensionHasNoValue_formattedCorrectly() {
178
192
.publisher (testPublisher )
179
193
.addExtension (extensionProvider )
180
194
.chunkSize (CHUNK_SIZE )
195
+ .contentLength (contentLength )
181
196
.build ();
182
197
183
198
List <ByteBuffer > chunks = getAllElements (chunkPublisher );
@@ -187,11 +202,13 @@ void subscribe_extensionHasNoValue_formattedCorrectly() {
187
202
188
203
@ Test
189
204
void subscribe_multipleExtensions_formattedCorrectly () {
190
- TestPublisher testPublisher = randomPublisherOfLength (8 );
205
+ int contentLength = 8 ;
206
+ TestPublisher testPublisher = randomPublisherOfLength (contentLength );
191
207
192
208
ChunkedEncodedPublisher .Builder chunkPublisher =
193
209
ChunkedEncodedPublisher .builder ()
194
210
.publisher (testPublisher )
211
+ .contentLength (contentLength )
195
212
.chunkSize (CHUNK_SIZE );
196
213
197
214
Stream .of ("1" , "2" , "3" )
@@ -207,10 +224,12 @@ void subscribe_multipleExtensions_formattedCorrectly() {
207
224
void subscribe_randomElementSizes_dataChunkedCorrectly () {
208
225
for (int i = 0 ; i < 512 ; ++i ) {
209
226
int nChunks = 24 ;
210
- TestPublisher byteBufferPublisher = randomPublisherOfLength (CHUNK_SIZE * 24 );
227
+ int contentLength = nChunks * CHUNK_SIZE ;
228
+ TestPublisher byteBufferPublisher = randomPublisherOfLength (contentLength );
211
229
212
230
ChunkedEncodedPublisher chunkedPublisher = ChunkedEncodedPublisher .builder ()
213
231
.publisher (byteBufferPublisher )
232
+ .contentLength (contentLength )
214
233
.chunkSize (CHUNK_SIZE )
215
234
.build ();
216
235
@@ -232,14 +251,16 @@ void subscribe_randomElementSizes_dataChunkedCorrectly() {
232
251
void subscribe_randomElementSizes_chunksHaveExtensions_dataChunkedCorrectly () {
233
252
for (int i = 0 ; i < 512 ; ++i ) {
234
253
int nChunks = 24 ;
235
- TestPublisher byteBufferPublisher = randomPublisherOfLength (CHUNK_SIZE * 24 );
254
+ int contentLength = CHUNK_SIZE * nChunks ;
255
+ TestPublisher byteBufferPublisher = randomPublisherOfLength (contentLength );
236
256
237
257
StaticExtensionProvider extensionProvider = Mockito .spy (new StaticExtensionProvider ("foo" , "bar" ));
238
258
239
259
ChunkedEncodedPublisher chunkedPublisher = ChunkedEncodedPublisher .builder ()
240
260
.publisher (byteBufferPublisher )
241
261
.addExtension (extensionProvider )
242
262
.chunkSize (CHUNK_SIZE )
263
+ .contentLength (contentLength )
243
264
.build ();
244
265
245
266
List <ByteBuffer > chunks = getAllElements (chunkedPublisher );
@@ -264,12 +285,14 @@ void subscribe_randomElementSizes_chunksHaveExtensions_dataChunkedCorrectly() {
264
285
265
286
@ Test
266
287
void subscribe_addTrailingChunkTrue_trailingChunkAdded () {
267
- TestPublisher testPublisher = randomPublisherOfLength (CHUNK_SIZE * 2 );
288
+ int contentLength = CHUNK_SIZE * 2 ;
289
+ TestPublisher testPublisher = randomPublisherOfLength (contentLength );
268
290
269
291
ChunkedEncodedPublisher chunkedPublisher = ChunkedEncodedPublisher .builder ()
270
292
.publisher (testPublisher )
271
293
.chunkSize (CHUNK_SIZE )
272
294
.addEmptyTrailingChunk (true )
295
+ .contentLength (contentLength )
273
296
.build ();
274
297
275
298
List <ByteBuffer > chunks = getAllElements (chunkedPublisher );
@@ -285,7 +308,12 @@ void subscribe_addTrailingChunkTrue_upstreamEmpty_trailingChunkAdded() {
285
308
Publisher <ByteBuffer > empty = Flowable .empty ();
286
309
287
310
ChunkedEncodedPublisher chunkedPublisher =
288
- ChunkedEncodedPublisher .builder ().publisher (empty ).chunkSize (CHUNK_SIZE ).addEmptyTrailingChunk (true ).build ();
311
+ ChunkedEncodedPublisher .builder ()
312
+ .publisher (empty )
313
+ .chunkSize (CHUNK_SIZE )
314
+ .addEmptyTrailingChunk (true )
315
+ .contentLength (0 )
316
+ .build ();
289
317
290
318
List <ByteBuffer > chunks = getAllElements (chunkedPublisher );
291
319
@@ -297,10 +325,15 @@ void subscribe_extensionsPresent_extensionsInvokedForEachChunk() {
297
325
ChunkExtensionProvider mockProvider = Mockito .spy (new StaticExtensionProvider ("foo" , "bar" ));
298
326
299
327
int nChunks = 16 ;
300
- TestPublisher elements = randomPublisherOfLength (nChunks * CHUNK_SIZE );
328
+ int contentLength = CHUNK_SIZE * nChunks ;
329
+ TestPublisher elements = randomPublisherOfLength (contentLength );
301
330
302
- ChunkedEncodedPublisher chunkPublisher =
303
- ChunkedEncodedPublisher .builder ().publisher (elements ).chunkSize (CHUNK_SIZE ).addExtension (mockProvider ).build ();
331
+ ChunkedEncodedPublisher chunkPublisher = ChunkedEncodedPublisher .builder ()
332
+ .publisher (elements )
333
+ .contentLength (contentLength )
334
+ .chunkSize (CHUNK_SIZE )
335
+ .addExtension (mockProvider )
336
+ .build ();
304
337
305
338
List <ByteBuffer > chunks = getAllElements (chunkPublisher );
306
339
@@ -316,6 +349,28 @@ void subscribe_extensionsPresent_extensionsInvokedForEachChunk() {
316
349
}
317
350
}
318
351
352
+ @ Test
353
+ void subscribe_wrappedExceedsContentLength_dataTruncatedToLength () {
354
+ int contentLength = CHUNK_SIZE * 4 - 1 ;
355
+ TestPublisher elements = randomPublisherOfLength (contentLength * 2 );
356
+
357
+ TestSubscriber <ByteBuffer > subscriber = new TestSubscriber <>();
358
+ ChunkedEncodedPublisher chunkPublisher = newChunkedBuilder (elements ).contentLength (contentLength )
359
+ .build ();
360
+
361
+ chunkPublisher .subscribe (subscriber );
362
+
363
+ subscriber .awaitTerminalEvent (30 , TimeUnit .SECONDS );
364
+
365
+ int totalRemaining = subscriber .values ()
366
+ .stream ()
367
+ .map (this ::stripEncoding )
368
+ .mapToInt (ByteBuffer ::remaining )
369
+ .sum ();
370
+
371
+ assertThat (totalRemaining ).isEqualTo (contentLength );
372
+ }
373
+
319
374
private static ChunkedEncodedPublisher .Builder newChunkedBuilder (Publisher <ByteBuffer > publisher ) {
320
375
return ChunkedEncodedPublisher .builder ().publisher (publisher ).chunkSize (CHUNK_SIZE );
321
376
}
@@ -401,6 +456,10 @@ private ByteBuffer stripEncoding(ByteBuffer chunk) {
401
456
return stripped ;
402
457
}
403
458
459
+ private long totalRemaining (List <ByteBuffer > buffers ) {
460
+ return buffers .stream ().mapToLong (ByteBuffer ::remaining ).sum ();
461
+ }
462
+
404
463
private static class TestPublisher implements Publisher <ByteBuffer > {
405
464
private final Publisher <ByteBuffer > wrapped ;
406
465
private final byte [] wrappedChecksum ;
0 commit comments