Search in sources :

Example 6 with IndividualResponseMap

use of com.linkedin.restli.common.multiplexer.IndividualResponseMap in project rest.li by linkedin.

the class MultiplexedRequestHandlerImpl method handleRequest.

@Override
public void handleRequest(RestRequest request, RequestContext requestContext, final Callback<RestResponse> callback) {
    if (HttpMethod.POST != HttpMethod.valueOf(request.getMethod())) {
        _log.error("POST is expected, but " + request.getMethod() + " received");
        callback.onError(RestException.forError(HttpStatus.S_405_METHOD_NOT_ALLOWED.getCode(), "Invalid method"));
        return;
    }
    IndividualRequestMap individualRequests;
    try {
        individualRequests = extractIndividualRequests(request);
    } catch (RestException e) {
        _log.error("Invalid multiplexed request", e);
        callback.onError(e);
        return;
    } catch (Exception e) {
        _log.error("Invalid multiplexed request", e);
        callback.onError(RestException.forError(HttpStatus.S_400_BAD_REQUEST.getCode(), e));
        return;
    }
    // prepare the map of individual responses to be collected
    final IndividualResponseMap individualResponses = new IndividualResponseMap(individualRequests.size());
    final Map<String, HttpCookie> responseCookies = new HashMap<>();
    // all tasks are Void and side effect based, that will be useful when we add streaming
    Task<?> requestProcessingTask = createParallelRequestsTask(request, requestContext, individualRequests, individualResponses, responseCookies);
    Task<Void> responseAggregationTask = Task.action("send aggregated response", () -> {
        RestResponse aggregatedResponse = aggregateResponses(individualResponses, responseCookies);
        callback.onSuccess(aggregatedResponse);
    });
    _engine.run(requestProcessingTask.andThen(responseAggregationTask), MUX_PLAN_CLASS);
}
Also used : IndividualRequestMap(com.linkedin.restli.common.multiplexer.IndividualRequestMap) HashMap(java.util.HashMap) RestResponse(com.linkedin.r2.message.rest.RestResponse) RestException(com.linkedin.r2.message.rest.RestException) IndividualResponseMap(com.linkedin.restli.common.multiplexer.IndividualResponseMap) HttpCookie(java.net.HttpCookie) RestException(com.linkedin.r2.message.rest.RestException) MimeTypeParseException(javax.activation.MimeTypeParseException)

Example 7 with IndividualResponseMap

use of com.linkedin.restli.common.multiplexer.IndividualResponseMap 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());
        }
    }
}
Also used : MultiplexedResponseContent(com.linkedin.restli.common.multiplexer.MultiplexedResponseContent) RestResponse(com.linkedin.r2.message.rest.RestResponse) RestResponseBuilder(com.linkedin.r2.message.rest.RestResponseBuilder) ArrayList(java.util.ArrayList) ByteString(com.linkedin.data.ByteString) URI(java.net.URI) IndividualResponse(com.linkedin.restli.common.multiplexer.IndividualResponse) URISyntaxException(java.net.URISyntaxException) RestLiServiceException(com.linkedin.restli.server.RestLiServiceException) RestException(com.linkedin.r2.message.rest.RestException) IOException(java.io.IOException) ExecutionException(java.util.concurrent.ExecutionException) IndividualRequest(com.linkedin.restli.common.multiplexer.IndividualRequest) RestRequest(com.linkedin.r2.message.rest.RestRequest) RequestContext(com.linkedin.r2.message.RequestContext) HttpCookie(java.net.HttpCookie) IndividualResponseMap(com.linkedin.restli.common.multiplexer.IndividualResponseMap) FutureCallback(com.linkedin.common.callback.FutureCallback) Test(org.testng.annotations.Test)

Aggregations

IndividualResponseMap (com.linkedin.restli.common.multiplexer.IndividualResponseMap)7 RestResponse (com.linkedin.r2.message.rest.RestResponse)6 IndividualResponse (com.linkedin.restli.common.multiplexer.IndividualResponse)6 RestException (com.linkedin.r2.message.rest.RestException)5 MultiplexedResponseContent (com.linkedin.restli.common.multiplexer.MultiplexedResponseContent)5 FutureCallback (com.linkedin.common.callback.FutureCallback)4 Test (org.testng.annotations.Test)4 ByteString (com.linkedin.data.ByteString)3 IOException (java.io.IOException)3 HashMap (java.util.HashMap)3 Callback (com.linkedin.common.callback.Callback)2 RequestContext (com.linkedin.r2.message.RequestContext)2 RestRequest (com.linkedin.r2.message.rest.RestRequest)2 RestResponseBuilder (com.linkedin.r2.message.rest.RestResponseBuilder)2 TestRecord (com.linkedin.restli.client.test.TestRecord)2 IndividualRequest (com.linkedin.restli.common.multiplexer.IndividualRequest)2 IndividualRequestMap (com.linkedin.restli.common.multiplexer.IndividualRequestMap)2 RestLiServiceException (com.linkedin.restli.server.RestLiServiceException)2 HttpCookie (java.net.HttpCookie)2 URISyntaxException (java.net.URISyntaxException)2