*/
package org.sonar.db.source;
+import com.google.protobuf.CodedInputStream;
+import com.google.protobuf.InvalidProtocolBufferException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class FileSourceDto {
+ private static final String SIZE_LIMIT_EXCEEDED_EXCEPTION_MESSAGE = "Protocol message was too large. May be malicious. " +
+ "Use CodedInputStream.setSizeLimit() to increase the size limit.";
+
private Long id;
private String projectUuid;
private String fileUuid;
public DbFileSources.Data decodeSourceData(byte[] binaryData) {
try {
- return decodeSourceDataImpl(new ByteArrayInputStream(binaryData));
+ return decodeRegularSourceData(binaryData);
} catch (IOException e) {
throw new IllegalStateException(
format("Fail to decompress and deserialize source data [id=%s,fileUuid=%s,projectUuid=%s]", id, fileUuid, projectUuid),
}
}
- /**
- * Decompress and deserialize content of column FILE_SOURCES.BINARY_DATA.
- * The parameter "input" is always closed by this method.
- */
- public static DbFileSources.Data decodeSourceData(InputStream binaryInput) {
- try {
- return decodeSourceDataImpl(binaryInput);
- } catch (IOException e) {
- throw new IllegalStateException("Fail to decompress and deserialize source data", e);
+ private static DbFileSources.Data decodeRegularSourceData(byte[] binaryData) throws IOException {
+ try (LZ4BlockInputStream lz4Input = new LZ4BlockInputStream(new ByteArrayInputStream(binaryData))) {
+ return DbFileSources.Data.parseFrom(lz4Input);
+ } catch (InvalidProtocolBufferException e) {
+ if (SIZE_LIMIT_EXCEEDED_EXCEPTION_MESSAGE.equals(e.getMessage())) {
+ return decodeHugeSourceData(binaryData);
+ }
+ throw e;
}
}
- private static DbFileSources.Data decodeSourceDataImpl(InputStream binaryInput) throws IOException {
- try (LZ4BlockInputStream lz4Input = new LZ4BlockInputStream(binaryInput)) {
- return DbFileSources.Data.parseFrom(lz4Input);
+ private static DbFileSources.Data decodeHugeSourceData(byte[] binaryData) throws IOException {
+ try (LZ4BlockInputStream lz4Input = new LZ4BlockInputStream(new ByteArrayInputStream(binaryData))) {
+ CodedInputStream input = CodedInputStream.newInstance(lz4Input);
+ input.setSizeLimit(Integer.MAX_VALUE);
+ return DbFileSources.Data.parseFrom(input);
}
}
import static org.assertj.core.api.Assertions.assertThat;
public class FileSourceDtoTest {
+ private static final String LOREM_IPSUM = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aliquam ac magna libero. " +
+ "Integer eu quam vulputate, interdum ante quis, sodales mauris. Nam mollis ornare dolor at maximus. Cras pharetra aliquam fringilla. " +
+ "Nunc hendrerit, elit eu mattis fermentum, ligula metus malesuada nunc, non fermentum augue tellus eu odio. Praesent ut vestibulum nibh. " +
+ "Curabitur sit amet dignissim magna, at efficitur dolor. Ut non felis aliquam justo euismod gravida. Morbi eleifend vitae ante eu pulvinar. " +
+ "Aliquam rhoncus magna quis lorem posuere semper.";
+
@Rule
public ExpectedException expectedException = ExpectedException.none();
String fileUuid = "file uuid";
String projectUuid = "project uuid";
FileSourceDto underTest = new FileSourceDto()
- .setBinaryData(new byte[]{1, 2, 3, 4, 5})
- .setId(id)
- .setFileUuid(fileUuid)
- .setProjectUuid(projectUuid);
+ .setBinaryData(new byte[] {1, 2, 3, 4, 5})
+ .setId(id)
+ .setFileUuid(fileUuid)
+ .setProjectUuid(projectUuid);
expectedException.expect(IllegalStateException.class);
expectedException.expectMessage("Fail to decompress and deserialize source data [id=" + id + ",fileUuid=" + fileUuid + ",projectUuid=" + projectUuid + "]");
underTest.getSourceData();
}
+
+ @Test
+ public void getSourceData_reads_Data_object_bigger_than_default_size_limit() {
+ DbFileSources.Data build = createOver64MBDataStructure();
+ byte[] bytes = FileSourceDto.encodeSourceData(build);
+
+ DbFileSources.Data data = new FileSourceDto().decodeSourceData(bytes);
+ assertThat(data.getLinesCount()).isEqualTo(build.getLinesCount());
+ }
+
+ private static DbFileSources.Data createOver64MBDataStructure() {
+ DbFileSources.Data.Builder dataBuilder = DbFileSources.Data.newBuilder();
+ DbFileSources.Line.Builder lineBuilder = DbFileSources.Line.newBuilder();
+ for (int i = 0; i < 199999; i++) {
+ dataBuilder.addLines(
+ lineBuilder.setSource(LOREM_IPSUM)
+ .setLine(i)
+ .build());
+ }
+ return dataBuilder.build();
+ }
}
*/
package org.sonar.db.version.v51;
-import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
pstmt.setLong(1, fileSourceId);
rs = pstmt.executeQuery();
rs.next();
- InputStream data = rs.getBinaryStream(1);
- return FileSourceDto.decodeSourceData(data);
+ return new FileSourceDto().decodeSourceData(rs.getBytes(1));
} finally {
DbUtils.closeQuietly(rs);
DbUtils.closeQuietly(pstmt);