use of com.linkedin.restli.common.multiplexer.MultiplexedResponseContent in project rest.li by linkedin.
the class TestMultiplexedRequestHandlerImpl method testResponseCookiesAggregated.
@Test(dataProvider = "multiplexerConfigurations")
public void testResponseCookiesAggregated(MultiplexerRunMode multiplexerRunMode) throws Exception {
// Per security review: We should not make cookies for each individual responses visible to the client (especially if the cookie is HttpOnly).
// Therefore all cookies returned by individual responses will be aggregated at the envelope response level.
// Create a mockHandler. Make it return different cookies based on the request
SynchronousRequestHandler mockHandler = new SynchronousRequestHandler() {
@Override
public RestResponse handleRequestSync(RestRequest request, RequestContext requestContext) {
try {
URI uri = request.getURI();
RestResponseBuilder restResponseBuilder = new RestResponseBuilder();
restResponseBuilder.setStatus(HttpStatus.S_200_OK.getCode());
restResponseBuilder.setEntity(jsonBodyToByteString(fakeIndividualBody("don't care")));
List<HttpCookie> cookies = new ArrayList<HttpCookie>();
if (uri.getPath().contains("req1")) {
HttpCookie cookie = new HttpCookie("cookie1", "cookie1Value");
cookie.setDomain(".www.linkedin.com");
cookie.setSecure(false);
cookies.add(cookie);
HttpCookie commonCookie = new HttpCookie("commonCookie", "commonCookieValue");
commonCookie.setDomain(".WWW.linkedin.com");
commonCookie.setPath("/foo");
commonCookie.setSecure(false);
cookies.add(commonCookie);
} else if (uri.getPath().contains("req2")) {
HttpCookie cookie = new HttpCookie("cookie2", "cookie2Value");
cookie.setDomain("www.linkedin.com");
cookie.setSecure(false);
cookies.add(cookie);
cookie = new HttpCookie("cookie3", "cookie3Value");
cookies.add(cookie);
HttpCookie commonCookie = new HttpCookie("commonCookie", "commonCookieValue");
commonCookie.setDomain(".www.linkedin.com");
commonCookie.setPath("/foo");
commonCookie.setSecure(true);
cookies.add(commonCookie);
} else {
HttpCookie cookie = new HttpCookie("cookie2", "newCookie2Value");
cookie.setDomain("www.linkedin.com");
cookie.setSecure(true);
cookies.add(cookie);
}
return restResponseBuilder.setCookies(CookieUtil.encodeSetCookies(cookies)).build();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
};
// Prepare request to mux handler
FutureCallback<RestResponse> callback = new FutureCallback<RestResponse>();
RequestContext requestContext = new RequestContext();
Map<String, IndividualRequest> individualRequests = ImmutableMap.of("0", fakeIndRequest("/req1"), "1", fakeIndRequest("/req2", ImmutableMap.of("2", fakeIndRequest("/req3"))));
// Create mux handler instance
MultiplexedRequestHandlerImpl multiplexer = createMultiplexer(mockHandler, null, Collections.<String>emptySet(), 3, multiplexerRunMode);
try {
multiplexer.handleRequest(fakeMuxRestRequest(individualRequests), requestContext, callback);
} catch (Exception e) {
fail("Multiplexer should not throw exception", e);
}
RestResponse muxRestResponse = callback.get();
// assert multiplexed request should return a 200 status code
assertEquals(muxRestResponse.getStatus(), 200, "Multiplexer should return 200");
MultiplexedResponseContent muxResponseContent = new MultiplexedResponseContent(DataMapConverter.bytesToDataMap(muxRestResponse.getHeaders(), muxRestResponse.getEntity()));
// individual response should not have set-cookie headers
IndividualResponseMap responses = muxResponseContent.getResponses();
for (IndividualResponse res : responses.values()) {
for (String headerName : res.getHeaders().keySet()) {
assertTrue(headerName.equalsIgnoreCase("set-cookie"), "Individual response header should not container set-cookie header: " + responses.toString());
}
}
// Ensure cookies are aggregated at envelope level
List<HttpCookie> cookies = CookieUtil.decodeSetCookies(muxRestResponse.getCookies());
assertEquals(cookies.size(), 4);
for (HttpCookie cookie : cookies) {
if ("cookie1".equals(cookie.getName())) {
assertEquals(cookie.getValue(), "cookie1Value");
assertEquals(cookie.getDomain(), ".www.linkedin.com");
assertEquals(cookie.getSecure(), false);
} else if ("cookie2".equals(cookie.getName())) {
assertEquals(cookie.getValue(), "newCookie2Value");
assertEquals(cookie.getDomain(), "www.linkedin.com");
assertEquals(cookie.getSecure(), true);
} else if ("cookie3".equals(cookie.getName())) {
assertEquals(cookie.getValue(), "cookie3Value");
} else if ("commonCookie".equals(cookie.getName())) {
assertEquals(cookie.getValue(), "commonCookieValue");
assertEquals(cookie.getDomain().toLowerCase(), ".www.linkedin.com");
assertEquals(cookie.getPath(), "/foo");
// Since request0 and request1 are executed in parallel, depending on which request is completed first,
// we don't know what will be its final 'secure' attribute value.
} else {
fail("Unknown cookie name: " + cookie.getName());
}
}
}
use of com.linkedin.restli.common.multiplexer.MultiplexedResponseContent in project rest.li by linkedin.
the class TestMultiplexedRequestHandlerImpl method testIndividualRequestInheritHeadersAndCookiesFromEnvelopeRequest.
@Test(dataProvider = "multiplexerConfigurations")
public void testIndividualRequestInheritHeadersAndCookiesFromEnvelopeRequest(MultiplexerRunMode multiplexerRunMode) throws Exception {
// When some request headers/cookies are passed in the envelope, we need to ensure
// they are properly included in each of the individual requests sent to
// MultiplexerSingletonFilter and request handler. In the high level, the expected behavior should be:
// 1. IndividualRequest that is passed to MultiplexerSingletonFilter should already have headers inherited from the
// envelope request.
// 2. RestRequest that is passed to the request handler should have both headers and cookies inherited from the
// envelope request.
// Create a mockHandler. Captures all headers and cookies found in the request.
final Map<String, String> headers = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
final Map<String, String> cookies = new HashMap<String, String>();
SynchronousRequestHandler mockHandler = new SynchronousRequestHandler() {
@Override
public RestResponse handleRequestSync(RestRequest request, RequestContext requestContext) {
try {
headers.putAll(request.getHeaders());
for (HttpCookie cookie : CookieUtil.decodeCookies(request.getCookies())) {
cookies.put(cookie.getName(), cookie.getValue());
}
return fakeIndRestResponse(jsonBodyToByteString(new IndividualBody()));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
};
// Create a mock MultiplexerSingletonFilter to put request headers inside another headers so
// we can do assertion on it later.
final Map<String, String> headersSeenInMuxFilter = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
MultiplexerSingletonFilter muxFilterWithSimulatedFailures = new MultiplexerSingletonFilter() {
@Override
public IndividualRequest filterIndividualRequest(IndividualRequest request) {
headersSeenInMuxFilter.putAll(request.getHeaders());
return request;
}
@Override
public IndividualResponse filterIndividualResponse(IndividualResponse response) {
return response;
}
};
// Prepare request to mux handler
FutureCallback<RestResponse> callback = new FutureCallback<RestResponse>();
RequestContext requestContext = new RequestContext();
Map<String, IndividualRequest> individualRequests = ImmutableMap.of("0", fakeIndRequest("/request", ImmutableMap.of("X-IndividualHeader", "individualHeader", "X-OverridableHeader", "overrideHeader"), Collections.<String, IndividualRequest>emptyMap()));
Set<String> headerWhiteList = new HashSet<String>();
headerWhiteList.add("X-IndividualHeader");
headerWhiteList.add("X-OverridableHeader");
// Prepare mux request with cookie
RestRequest muxRequest = new RestRequestBuilder(fakeMuxRestRequest(individualRequests)).addCookie("cookie1=cookie1Value; cookie2=cookie2Value").addHeaderValue("X-overridableheader", "originalHeader").addHeaderValue("X-Envelope", "envelopeHeaderValue").build();
// Create mux handler instance
MultiplexedRequestHandlerImpl multiplexer = createMultiplexer(mockHandler, muxFilterWithSimulatedFailures, headerWhiteList, individualRequests.size(), multiplexerRunMode);
try {
multiplexer.handleRequest(muxRequest, requestContext, callback);
} catch (Exception e) {
fail("Multiplexer should not throw exception", e);
}
RestResponse muxRestResponse = callback.get();
// Assert multiplexed request should return a 200 status code
assertEquals(muxRestResponse.getStatus(), 200, "Multiplexer should return 200");
MultiplexedResponseContent muxResponseContent = new MultiplexedResponseContent(DataMapConverter.bytesToDataMap(muxRestResponse.getHeaders(), muxRestResponse.getEntity()));
IndividualResponse response = muxResponseContent.getResponses().get("0");
assertEquals(response.getStatus().intValue(), 200, "Individual request should not fail. Response body is: " + response.getBody().toString());
Map<String, String> expectedHeaders = new TreeMap<String, String>(String.CASE_INSENSITIVE_ORDER);
expectedHeaders.putAll(ImmutableMap.of(RestConstants.HEADER_CONTENT_TYPE, RestConstants.HEADER_VALUE_APPLICATION_JSON, "X-IndividualHeader", "individualHeader", "X-OverridableHeader", "overrideHeader", "X-Envelope", "envelopeHeaderValue"));
Map<String, String> expectedCookies = ImmutableMap.of("cookie1", "cookie1Value", "cookie2", "cookie2Value");
assertEquals(headers.size(), expectedHeaders.size(), "Incorrect numnber of headers, found:" + headers.toString());
assertEquals(cookies.size(), expectedCookies.size(), "Incorrect numnber of cookies, found:" + cookies.toString());
assertEquals(headersSeenInMuxFilter.size(), expectedHeaders.size(), "Incorrect numnber of headers seen by Mux filter, found:" + headers.toString());
for (Map.Entry<String, String> header : headers.entrySet()) {
assertEquals(header.getValue(), expectedHeaders.get(header.getKey()), "Incorrect header value for header: " + header.getKey());
}
for (Map.Entry<String, String> cookie : cookies.entrySet()) {
assertEquals(cookie.getValue(), expectedCookies.get(cookie.getKey()), "Incorrect cookie value for cookie: " + cookie.getKey());
}
for (Map.Entry<String, String> header : headersSeenInMuxFilter.entrySet()) {
assertEquals(header.getValue(), expectedHeaders.get(header.getKey()), "Incorrect header value for header seen by Mux Filter: " + header.getKey());
}
}
use of com.linkedin.restli.common.multiplexer.MultiplexedResponseContent in project rest.li by linkedin.
the class TestMultiplexedCallback method testSuccess.
@Test
public void testSuccess() throws Exception {
FutureCallback<RestResponse> callback1 = new FutureCallback<RestResponse>();
FutureCallback<RestResponse> callback2 = new FutureCallback<RestResponse>();
ImmutableMap<Integer, Callback<RestResponse>> individualCallbacks = ImmutableMap.<Integer, Callback<RestResponse>>of(ID1, callback1, ID2, callback2);
FutureCallback<MultiplexedResponse> aggregatedCallback = new FutureCallback<MultiplexedResponse>();
TestRecord entity1 = fakeEntity(ID1);
IndividualResponse ir1 = fakeIndividualResponse(entity1);
TestRecord entity2 = fakeEntity(ID2);
IndividualResponse ir2 = fakeIndividualResponse(entity2);
MultiplexedResponseContent responseContent = new MultiplexedResponseContent().setResponses(new IndividualResponseMap(ImmutableMap.of(Integer.toString(ID1), ir1, Integer.toString(ID2), ir2)));
MultiplexedCallback multiplexedCallback = new MultiplexedCallback(individualCallbacks, aggregatedCallback);
multiplexedCallback.onSuccess(fakeRestResponse(responseContent));
assertRestResponseEquals(callback1.get(), fakeRestResponse(entity1));
assertRestResponseEquals(callback2.get(), fakeRestResponse(entity2));
MultiplexedResponse multiplexedResponse = aggregatedCallback.get();
Assert.assertEquals(multiplexedResponse.getStatus(), HttpStatus.S_200_OK.getCode());
Assert.assertEquals(multiplexedResponse.getHeaders(), HEADERS);
}
Aggregations