Skip to content

Commit

Permalink
[netty#4793] Correctly add newlines when encode base64
Browse files Browse the repository at this point in the history
Motivation:

We not correctly added newlines if the src data needed to be padded. This regression was introduced by '63426fc3ed083513c07a58b45381f5c10dd47061'

Modifications:

- Correctly handling newlines
- Add unit test that proves the fix.

Result:

No more invalid base64 encoded data.
  • Loading branch information
normanmaurer committed Feb 6, 2016
1 parent 8588824 commit 29ab4bf
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 5 deletions.
12 changes: 7 additions & 5 deletions codec/src/main/java/io/netty/handler/codec/base64/Base64.java
Original file line number Diff line number Diff line change
Expand Up @@ -126,15 +126,12 @@ public static ByteBuf encode(
int e = 0;
int len2 = len - 2;
int lineLength = 0;
for (; d < len2; e += 4) {
for (; d < len2; d += 3, e += 4) {
encode3to4(src, d + off, 3, dest, e, dialect);

lineLength += 4;
d += 3;

if (breakLines && lineLength == MAX_LINE_LENGTH
// Only add NEW_LINE if we not ended directly on the MAX_LINE_LENGTH
&& d < len2) {
if (breakLines && lineLength == MAX_LINE_LENGTH) {
dest.setByte(e + 4, NEW_LINE);
e ++;
lineLength = 0;
Expand All @@ -146,6 +143,11 @@ public static ByteBuf encode(
e += 4;
} // end if: some padding needed

// Remove last byte if it's a newline
if (e > 1 && dest.getByte(e - 1) == NEW_LINE) {
e--;
}

return dest.slice(0, e);
}

Expand Down
62 changes: 62 additions & 0 deletions codec/src/test/java/io/netty/handler/codec/base64/Base64Test.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,16 @@
package io.netty.handler.codec.base64;

import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.util.CharsetUtil;
import org.junit.Test;


import java.io.ByteArrayInputStream;
import java.nio.charset.Charset;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;

import static io.netty.buffer.Unpooled.copiedBuffer;
import static org.junit.Assert.assertEquals;

Expand All @@ -45,6 +51,62 @@ public void testAddNewLine() {
testEncode(src, expectedEncoded);
}

@Test
public void testEncodeEmpty() {
ByteBuf src = Unpooled.EMPTY_BUFFER;
ByteBuf expectedEncoded = Unpooled.EMPTY_BUFFER;
testEncode(src, expectedEncoded);
}

@Test
public void testPaddingNewline() throws Exception {
String cert = "-----BEGIN CERTIFICATE-----\n" +
"MIICqjCCAjGgAwIBAgICI1YwCQYHKoZIzj0EATAmMSQwIgYDVQQDDBtUcnVzdGVk\n" +
"IFRoaW4gQ2xpZW50IFJvb3QgQ0EwIhcRMTYwMTI0MTU0OTQ1LTA2MDAXDTE2MDQy\n" +
"NTIyNDk0NVowYzEwMC4GA1UEAwwnREMgMGRlYzI0MGYtOTI2OS00MDY5LWE2MTYt\n" +
"YjJmNTI0ZjA2ZGE0MREwDwYDVQQLDAhEQyBJUFNFQzEcMBoGA1UECgwTVHJ1c3Rl\n" +
"ZCBUaGluIENsaWVudDB2MBAGByqGSM49AgEGBSuBBAAiA2IABOB7pZYC24sF5gJm\n" +
"OHXhasxmrNYebdtSAiQRgz0M0pIsogsFeTU/W0HTlTOqwDDckphHESAKHVxa6EBL\n" +
"d+/8HYZ1AaCmXtG73XpaOyaRr3TipJl2IaJzwuehgDHs0L+qcqOB8TCB7jAwBgYr\n" +
"BgEBEAQEJgwkMGRlYzI0MGYtOTI2OS00MDY5LWE2MTYtYjJmNTI0ZjA2ZGE0MCMG\n" +
"CisGAQQBjCHbZwEEFQwTNDkwNzUyMjc1NjM3MTE3Mjg5NjAUBgorBgEEAYwh22cC\n" +
"BAYMBDIwNTkwCwYDVR0PBAQDAgXgMAkGA1UdEwQCMAAwHQYDVR0OBBYEFGWljaKj\n" +
"wiGqW61PgLL/zLxj4iirMB8GA1UdIwQYMBaAFA2FRBtG/dGnl0iXP2uKFwJHmEQI\n" +
"MCcGA1UdJQQgMB4GCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYBBQUHAwkwCQYHKoZI\n" +
"zj0EAQNoADBlAjAQFP8rMLUxl36u8610LsSCiRG8pP3gjuLaaJMm3tjbVue/TI4C\n" +
"z3iL8i96YWK0VxcCMQC7pf6Wk3RhUU2Sg6S9e6CiirFLDyzLkaWxuCnXcOwTvuXT\n" +
"HUQSeUCp2Q6ygS5qKyc=\n" +
"-----END CERTIFICATE-----";

String expected = "MIICqjCCAjGgAwIBAgICI1YwCQYHKoZIzj0EATAmMSQwIgYDVQQDDBtUcnVzdGVkIFRoaW4gQ2xp\n" +
"ZW50IFJvb3QgQ0EwIhcRMTYwMTI0MTU0OTQ1LTA2MDAXDTE2MDQyNTIyNDk0NVowYzEwMC4GA1UE\n" +
"AwwnREMgMGRlYzI0MGYtOTI2OS00MDY5LWE2MTYtYjJmNTI0ZjA2ZGE0MREwDwYDVQQLDAhEQyBJ\n" +
"UFNFQzEcMBoGA1UECgwTVHJ1c3RlZCBUaGluIENsaWVudDB2MBAGByqGSM49AgEGBSuBBAAiA2IA\n" +
"BOB7pZYC24sF5gJmOHXhasxmrNYebdtSAiQRgz0M0pIsogsFeTU/W0HTlTOqwDDckphHESAKHVxa\n" +
"6EBLd+/8HYZ1AaCmXtG73XpaOyaRr3TipJl2IaJzwuehgDHs0L+qcqOB8TCB7jAwBgYrBgEBEAQE\n" +
"JgwkMGRlYzI0MGYtOTI2OS00MDY5LWE2MTYtYjJmNTI0ZjA2ZGE0MCMGCisGAQQBjCHbZwEEFQwT\n" +
"NDkwNzUyMjc1NjM3MTE3Mjg5NjAUBgorBgEEAYwh22cCBAYMBDIwNTkwCwYDVR0PBAQDAgXgMAkG\n" +
"A1UdEwQCMAAwHQYDVR0OBBYEFGWljaKjwiGqW61PgLL/zLxj4iirMB8GA1UdIwQYMBaAFA2FRBtG\n" +
"/dGnl0iXP2uKFwJHmEQIMCcGA1UdJQQgMB4GCCsGAQUFBwMCBggrBgEFBQcDAQYIKwYBBQUHAwkw\n" +
"CQYHKoZIzj0EAQNoADBlAjAQFP8rMLUxl36u8610LsSCiRG8pP3gjuLaaJMm3tjbVue/TI4Cz3iL\n" +
"8i96YWK0VxcCMQC7pf6Wk3RhUU2Sg6S9e6CiirFLDyzLkaWxuCnXcOwTvuXTHUQSeUCp2Q6ygS5q\n" +
"Kyc=";

ByteBuf src = Unpooled.wrappedBuffer(certFromString(cert).getEncoded());
ByteBuf expectedEncoded = copiedBuffer(expected, CharsetUtil.US_ASCII);
testEncode(src, expectedEncoded);
}

private static X509Certificate certFromString(String string) throws Exception {
CertificateFactory factory = CertificateFactory.getInstance("X.509");
ByteArrayInputStream bin = new ByteArrayInputStream(string.getBytes(CharsetUtil.US_ASCII));
try {
return (X509Certificate) factory.generateCertificate(bin);
} finally {
bin.close();
}
}

private static void testEncode(ByteBuf src, ByteBuf expectedEncoded) {
ByteBuf encoded = Base64.encode(src, true, Base64Dialect.STANDARD);
try {
Expand Down

0 comments on commit 29ab4bf

Please sign in to comment.