use of com.linkedin.data.ByteString in project rest.li by linkedin.
the class TestMIMEReaderClientCallbackExceptions method testMultiPartMIMEReaderCallbackExceptionOnDrainComplete.
@Test(dataProvider = "allTypesOfBodiesDataSource")
public void testMultiPartMIMEReaderCallbackExceptionOnDrainComplete(final int chunkSize, final List<MimeBodyPart> bodyPartList) throws Exception {
MimeMultipart multiPartMimeBody = new MimeMultipart();
// Add your body parts
for (final MimeBodyPart bodyPart : bodyPartList) {
multiPartMimeBody.addBodyPart(bodyPart);
}
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
multiPartMimeBody.writeTo(byteArrayOutputStream);
final ByteString requestPayload = ByteString.copy(byteArrayOutputStream.toByteArray());
final CountDownLatch countDownLatch = executeRequestPartialReadWithException(requestPayload, chunkSize, multiPartMimeBody.getContentType(), MultiPartMIMEThrowOnFlag.THROW_ON_DRAIN_COMPLETE, SinglePartMIMEThrowOnFlag.NO_THROW);
countDownLatch.await(_testTimeout, TimeUnit.MILLISECONDS);
Assert.assertTrue(_currentMultiPartMIMEReaderCallback.getStreamError() instanceof IllegalMonitorStateException);
Assert.assertEquals(_currentMultiPartMIMEReaderCallback.getSinglePartMIMEReaderCallbacks().size(), 0);
// Verify this is unusable.
try {
_currentMultiPartMIMEReaderCallback.getReader().drainAllParts();
Assert.fail();
} catch (MultiPartReaderFinishedException multiPartReaderFinishedException) {
// pass
}
}
use of com.linkedin.data.ByteString in project rest.li by linkedin.
the class TestMIMEReaderClientCallbackExceptions method testSinglePartMIMEReaderCallbackExceptionOnPartDataAvailable.
// /////////////////////////////////////////////////////////////////////////////////////
// SinglePartMIMEReader callback invocations throwing exceptions:
// These tests all verify the resilience of the single part mime reader when single part mime reader client callbacks throw runtime exceptions
@Test(dataProvider = "allTypesOfBodiesDataSource")
public void testSinglePartMIMEReaderCallbackExceptionOnPartDataAvailable(final int chunkSize, final List<MimeBodyPart> bodyPartList) throws Exception {
MimeMultipart multiPartMimeBody = new MimeMultipart();
// Add your body parts
for (final MimeBodyPart bodyPart : bodyPartList) {
multiPartMimeBody.addBodyPart(bodyPart);
}
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
multiPartMimeBody.writeTo(byteArrayOutputStream);
final ByteString requestPayload = ByteString.copy(byteArrayOutputStream.toByteArray());
final CountDownLatch countDownLatch = executeRequestPartialReadWithException(requestPayload, chunkSize, multiPartMimeBody.getContentType(), MultiPartMIMEThrowOnFlag.NO_THROW, SinglePartMIMEThrowOnFlag.THROW_ON_PART_DATA_AVAILABLE);
countDownLatch.await(_testTimeout, TimeUnit.MILLISECONDS);
Assert.assertTrue(_currentMultiPartMIMEReaderCallback.getStreamError() instanceof IllegalMonitorStateException);
// Verify this is unusable.
try {
_currentMultiPartMIMEReaderCallback.getReader().drainAllParts();
Assert.fail();
} catch (MultiPartReaderFinishedException multiPartReaderFinishedException) {
// pass
}
Assert.assertEquals(_currentMultiPartMIMEReaderCallback.getSinglePartMIMEReaderCallbacks().size(), 1);
Assert.assertTrue(_currentMultiPartMIMEReaderCallback.getSinglePartMIMEReaderCallbacks().get(0).getStreamError() instanceof IllegalMonitorStateException);
try {
_currentMultiPartMIMEReaderCallback.getSinglePartMIMEReaderCallbacks().get(0).getSinglePartMIMEReader().requestPartData();
Assert.fail();
} catch (SinglePartFinishedException singlePartFinishedException) {
// pass
}
}
use of com.linkedin.data.ByteString in project rest.li by linkedin.
the class TestMIMEReaderExceptions method boundaryPrematurelyTerminatedNoSubsequentCRLFs.
@Test(dataProvider = "multiplePartsDataSource")
public void boundaryPrematurelyTerminatedNoSubsequentCRLFs(final int chunkSize, final List<MimeBodyPart> bodyPartList) throws Exception {
MimeMultipart multiPartMimeBody = new MimeMultipart();
// Add your body parts
for (final MimeBodyPart bodyPart : bodyPartList) {
multiPartMimeBody.addBodyPart(bodyPart);
}
final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
multiPartMimeBody.writeTo(byteArrayOutputStream);
final byte[] mimePayload = byteArrayOutputStream.toByteArray();
// At this point the mimePayload's ending looks something like the following. Consider that
// --1234 is the boundary:
// <ending of some part data>--1234--/r/n
// What we want to test this particular code path is:
// <ending of some part data>--1234678
// So we trim off an element in the array at the end which results in:
// <ending of some part data>--1234--/r
// And then we modify the last three bytes to end up with:
// <ending of some part data>--1234678
final byte[] trimmedMimePayload = Arrays.copyOf(mimePayload, mimePayload.length - 1);
trimmedMimePayload[trimmedMimePayload.length - 1] = 8;
trimmedMimePayload[trimmedMimePayload.length - 2] = 7;
trimmedMimePayload[trimmedMimePayload.length - 3] = 6;
final ByteString requestPayload = ByteString.copy(trimmedMimePayload);
executeRequestWithDesiredException(requestPayload, chunkSize, multiPartMimeBody.getContentType(), "Malformed multipart mime request. Premature termination of multipart " + "mime body due to a boundary without a subsequent consecutive CRLF.");
// In this case we want all the parts to still make it over
List<SinglePartMIMEExceptionReaderCallbackImpl> singlePartMIMEReaderCallbacks = _currentMultiPartMIMEReaderCallback.getSinglePartMIMEReaderCallbacks();
Assert.assertEquals(singlePartMIMEReaderCallbacks.size(), multiPartMimeBody.getCount());
// Everything should have made it over
for (int i = 0; i < singlePartMIMEReaderCallbacks.size(); i++) {
// Actual
final SinglePartMIMEExceptionReaderCallbackImpl currentCallback = singlePartMIMEReaderCallbacks.get(i);
// Expected
final BodyPart currentExpectedPart = multiPartMimeBody.getBodyPart(i);
// Construct expected headers and verify they match
final Map<String, String> expectedHeaders = new HashMap<>();
@SuppressWarnings("unchecked") final Enumeration<Header> allHeaders = currentExpectedPart.getAllHeaders();
while (allHeaders.hasMoreElements()) {
final Header header = allHeaders.nextElement();
expectedHeaders.put(header.getName(), header.getValue());
}
Assert.assertEquals(currentCallback.getHeaders(), expectedHeaders);
// Verify the body matches
Assert.assertNotNull(currentCallback.getFinishedData());
if (currentExpectedPart.getContent() instanceof byte[]) {
Assert.assertEquals(currentCallback.getFinishedData().copyBytes(), currentExpectedPart.getContent());
} else {
// Default is String
Assert.assertEquals(new String(currentCallback.getFinishedData().copyBytes()), currentExpectedPart.getContent());
}
}
}
use of com.linkedin.data.ByteString in project rest.li by linkedin.
the class AbstractMIMEUnitTest method mockR2AndWrite.
// This is used when we need to mock out R2 and write a payload for our reader to read
protected void mockR2AndWrite(final ByteString payload, final int chunkSize, final String contentType) {
_entityStream = mock(EntityStream.class);
_readHandle = mock(ReadHandle.class);
_streamRequest = mock(StreamRequest.class);
// We have to use the AtomicReference holder technique to modify the current remaining buffer since the inner class
// in doAnswer() can only access final variables.
final AtomicReference<MultiPartMIMEReader.R2MultiPartMIMEReader> r2Reader = new AtomicReference<>();
// This takes the place of VariableByteStringWriter if we were to use R2 directly.
final VariableByteStringViewer variableByteStringViewer = new VariableByteStringViewer(payload, chunkSize);
// When data is requested, we write
doAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
final MultiPartMIMEReader.R2MultiPartMIMEReader reader = r2Reader.get();
Object[] args = invocation.getArguments();
// will always be 1 since MultiPartMIMEReader only does _rh.request(1)
final int chunksRequested = (Integer) args[0];
for (int i = 0; i < chunksRequested; i++) {
// Our tests will run into a stack overflow unless we use a thread pool here to fire off the callbacks.
// Especially in cases where the chunk size is 1. When the chunk size is one, the MultiPartMIMEReader
// ends up doing many _rh.request(1) since each write is only 1 byte.
// R2 uses a different technique to avoid stack overflows here which is unnecessary to emulate.
_scheduledExecutorService.submit(new Runnable() {
@Override
public void run() {
ByteString clientData = variableByteStringViewer.onWritePossible();
if (clientData.equals(ByteString.empty())) {
reader.onDone();
} else {
reader.onDataAvailable(clientData);
}
}
});
}
return null;
}
}).when(_readHandle).request(isA(Integer.class));
// We need a final version of the read handle since its passed to an inner class below.
final ReadHandle readHandleRef = _readHandle;
doAnswer(new Answer<Object>() {
@Override
public Object answer(InvocationOnMock invocation) throws Throwable {
Object[] args = invocation.getArguments();
final MultiPartMIMEReader.R2MultiPartMIMEReader reader = (MultiPartMIMEReader.R2MultiPartMIMEReader) args[0];
r2Reader.set(reader);
// R2 calls init immediately upon setting the reader
reader.onInit(readHandleRef);
return null;
}
}).when(_entityStream).setReader(isA(MultiPartMIMEReader.R2MultiPartMIMEReader.class));
when(_streamRequest.getEntityStream()).thenReturn(_entityStream);
final String contentTypeHeader = contentType + ";somecustomparameter=somecustomvalue" + ";anothercustomparameter=anothercustomvalue";
when(_streamRequest.getHeader(MultiPartMIMEUtils.CONTENT_TYPE_HEADER)).thenReturn(contentTypeHeader);
}
use of com.linkedin.data.ByteString in project rest.li by linkedin.
the class MultiPartMIMEChainReaderCallback method onNewDataSource.
@Override
public void onNewDataSource(final MultiPartMIMEDataSourceWriter multiPartMIMEDataSourceWriter) {
multiPartMIMEDataSourceWriter.onInit(new WriteHandle() {
@Override
public void write(ByteString data) {
_writeHandle.write(data);
}
@Override
public void done() {
// We intentionally ignore this, since we will be responsible for calling writeHandle.done() when all the data
// sources represented by the MultiPartMIMEDataSourceIterator have finished.
}
@Override
public void error(Throwable throwable) {
_writeHandle.error(throwable);
}
@Override
public int remaining() {
return _writeHandle.remaining();
}
});
_currentDataSource = multiPartMIMEDataSourceWriter;
ByteString serializedBoundaryAndHeaders = null;
try {
serializedBoundaryAndHeaders = MultiPartMIMEUtils.serializeBoundaryAndHeaders(_normalEncapsulationBoundary, multiPartMIMEDataSourceWriter);
} catch (IOException ioException) {
// Should never happen
onStreamError(ioException);
}
_writeHandle.write(serializedBoundaryAndHeaders);
if (_writeHandle.remaining() > 0) {
multiPartMIMEDataSourceWriter.onWritePossible();
}
}
Aggregations