@@ -47,23 +47,39 @@ public void onNext(ByteBuffer byteBuffer) {
4747 byte [] buf = BinaryUtils .copyBytesFrom (byteBuffer , amountToReadFromByteBuffer );
4848 outputBuffer = cipher .update (buf , 0 , amountToReadFromByteBuffer );
4949 if (outputBuffer == null || outputBuffer .length == 0 ) {
50- // The underlying data is too short to fill in the block cipher.
51- // Note that while the JCE Javadoc specifies that the outputBuffer is null in this case,
52- // in practice SunJCE and ACCP return an empty buffer instead, hence checks for
53- // null OR length == 0.
54- if (contentRead .get () == contentLength ) {
55- // All content has been read, so complete to get the final bytes
56- this .onComplete ();
57- }
58- // Otherwise, wait for more bytes. To avoid blocking,
59- // send an empty buffer to the wrapped subscriber.
60- wrappedSubscriber .onNext (ByteBuffer .allocate (0 ));
50+ // No bytes provided from upstream; just return.
51+ // No need to emit empty bytes to downstream; this can be misinterpreted.
52+ return ;
6153 } else {
62- wrappedSubscriber .onNext (ByteBuffer .wrap (outputBuffer ));
54+ boolean atEnd = isLastPart && contentRead .get () + amountToReadFromByteBuffer >= contentLength ;
55+
56+ if (atEnd ) {
57+ // If all content has been read, send the final bytes in this onNext call.
58+ // The final bytes must be sent with the final onNext call, not during the onComplete call.
59+ byte [] finalBytes ;
60+ try {
61+ finalBytes = cipher .doFinal ();
62+ } catch (final GeneralSecurityException exception ) {
63+ wrappedSubscriber .onError (exception );
64+ throw new S3EncryptionClientSecurityException (exception .getMessage (), exception );
65+ }
66+
67+ // Combine outputBuffer and finalBytes if both exist
68+ byte [] combinedBuffer ;
69+ if (outputBuffer != null && outputBuffer .length > 0 ) {
70+ combinedBuffer = new byte [outputBuffer .length + finalBytes .length ];
71+ System .arraycopy (outputBuffer , 0 , combinedBuffer , 0 , outputBuffer .length );
72+ System .arraycopy (finalBytes , 0 , combinedBuffer , outputBuffer .length , finalBytes .length );
73+ } else {
74+ combinedBuffer = finalBytes ;
75+ }
76+ wrappedSubscriber .onNext (ByteBuffer .wrap (combinedBuffer ));
77+ return ;
78+ } else {
79+ // Not at end; send content so far
80+ wrappedSubscriber .onNext (ByteBuffer .wrap (outputBuffer ));
81+ }
6382 }
64- } else {
65- // Do nothing
66- wrappedSubscriber .onNext (byteBuffer );
6783 }
6884 }
6985
@@ -91,20 +107,6 @@ public void onError(Throwable t) {
91107
92108 @ Override
93109 public void onComplete () {
94- if (!isLastPart ) {
95- // If this isn't the last part, skip doFinal, we aren't done
96- wrappedSubscriber .onComplete ();
97- return ;
98- }
99- try {
100- outputBuffer = cipher .doFinal ();
101- // Send the final bytes to the wrapped subscriber
102- wrappedSubscriber .onNext (ByteBuffer .wrap (outputBuffer ));
103- } catch (final GeneralSecurityException exception ) {
104- // Forward error, else the wrapped subscriber waits indefinitely
105- wrappedSubscriber .onError (exception );
106- throw new S3EncryptionClientSecurityException (exception .getMessage (), exception );
107- }
108110 wrappedSubscriber .onComplete ();
109111 }
110112
0 commit comments