@Nullable @Override public Object convertRequest(ServiceRequestContext ctx, AggregatedHttpMessage request, Class<?> expectedResultType) throws Exception { final MediaType mediaType = request.headers().contentType(); if (mediaType != null && mediaType.is(MediaType.PLAIN_TEXT_UTF_8)) { return new Request(request.content().toStringUtf8()); } return RequestConverterFunction.fallthrough(); } }
/** * Converts the {@link AggregatedHttpMessage} into a new {@link HttpRequest} and closes the stream. */ static HttpRequest of(AggregatedHttpMessage message) { return of(message.headers(), message.content(), message.trailingHeaders()); }
/** * Converts the {@link AggregatedHttpMessage} into a new complete {@link HttpResponse}. */ static HttpResponse of(AggregatedHttpMessage res) { requireNonNull(res, "res"); final List<HttpHeaders> informationals = res.informationals(); final HttpHeaders headers = res.headers(); final HttpData content = res.content(); final HttpHeaders trailingHeaders = res.trailingHeaders(); if (informationals.isEmpty()) { return of(headers, content, trailingHeaders); } final int numObjects = informationals.size() + 1 /* headers */ + (!content.isEmpty() ? 1 : 0) + (!trailingHeaders.isEmpty() ? 1 : 0); final HttpObject[] objs = new HttpObject[numObjects]; int writerIndex = 0; for (HttpHeaders informational : informationals) { objs[writerIndex++] = informational; } objs[writerIndex++] = headers; if (!content.isEmpty()) { objs[writerIndex++] = content; } if (!trailingHeaders.isEmpty()) { objs[writerIndex] = trailingHeaders; } return new RegularFixedHttpResponse(objs); }
@Test public void shouldRespondAuthnRequest_HttpPost() throws Exception { final AggregatedHttpMessage resp = client.get("/post").aggregate().join(); assertThat(resp.status()).isEqualTo(HttpStatus.OK); assertThat(resp.headers().contentType()).isEqualTo(MediaType.HTML_UTF_8); final Document doc = Jsoup.parse(resp.content().toStringUtf8()); assertThat(doc.body().attr("onLoad")).isEqualTo("document.forms[0].submit()"); // SAMLRequest will be posted to the IdP's SSO URL. final Element form = doc.body().child(0); assertThat(form.attr("method")).isEqualTo("post"); assertThat(form.attr("action")).isEqualTo("http://idp.example.com/saml/sso/post"); assertThat(form.child(0).attr("name")).isEqualTo(SAML_REQUEST); assertThat(form.child(1).attr("name")).isEqualTo(RELAY_STATE); }
/** * Returns the {@link HttpHeaderNames#METHOD METHOD} of this message. * * @return the method, or {@code null} if there's no such header */ @Nullable default HttpMethod method() { return headers().method(); }
final String body = message.content().toString( contentType.charset().orElse(StandardCharsets.US_ASCII)); if (!body.isEmpty()) {
@Test public void shouldRespondAuthnRequest_HttpRedirect() throws Exception { final AggregatedHttpMessage resp = client.get("/redirect").aggregate().join(); assertThat(resp.status()).isEqualTo(HttpStatus.FOUND); // Check the order of the parameters in the quest string. final String location = resp.headers().get(HttpHeaderNames.LOCATION); final Pattern p = Pattern.compile( "http://idp\\.example\\.com/saml/sso/redirect\\?" + "SAMLRequest=([^&]+)&RelayState=([^&]+)&SigAlg=([^&]+)&Signature=(.+)$"); assertThat(p.matcher(location).matches()).isTrue(); final QueryStringDecoder decoder = new QueryStringDecoder(location, true); assertThat(decoder.parameters().get(SIGNATURE_ALGORITHM).get(0)).isEqualTo(signatureAlgorithm); }
/** * Creates a {@link SamlParameters} instance with the specified {@link AggregatedHttpMessage}. */ SamlParameters(AggregatedHttpMessage msg) { requireNonNull(msg, "msg"); final MediaType contentType = msg.headers().contentType(); final QueryStringDecoder decoder; if (contentType != null && contentType.belongsTo(MediaType.FORM_DATA)) { final String query = msg.content().toString( contentType.charset().orElse(StandardCharsets.UTF_8)); decoder = new QueryStringDecoder(query, false); } else { final String path = msg.path(); assert path != null : "path"; decoder = new QueryStringDecoder(path, true); } parameters = decoder.parameters(); }
final Request coyoteReq = new Request(); coyoteReq.scheme().setString(req.scheme()); coyoteReq.setLocalPort(localAddr.getPort()); final String hostHeader = req.headers().authority(); final int colonPos = hostHeader.indexOf(':'); if (colonPos < 0) { final HttpMethod method = req.method(); coyoteReq.method().setString(method.name()); convertHeaders(req.headers(), cHeaders); convertHeaders(req.trailingHeaders(), cHeaders); final HttpData content = req.content(); coyoteReq.setInputBuffer((InputBuffer) INPUT_BUFFER_CONSTRUCTOR.invoke(content));
@Override public CompletableFuture<Boolean> isHealthy(Endpoint endpoint) { return httpClient.get(healthCheckPath) .aggregate() .thenApply(message -> HttpStatus.OK.equals(message.status())); } }
@Test public void shouldConsumeLogoutRequest_HttpPost() throws Exception { final LogoutRequest logoutRequest = getLogoutRequest("http://" + spHostname + ':' + rule.httpPort() + "/saml/slo/post", "http://idp.example.com/post"); final AggregatedHttpMessage msg = sendViaHttpPostBindingProtocol("/saml/slo/post", SAML_REQUEST, logoutRequest); assertThat(msg.status()).isEqualTo(HttpStatus.OK); assertThat(msg.headers().contentType()).isEqualTo(MediaType.HTML_UTF_8); final Document doc = Jsoup.parse(msg.content().toStringUtf8()); assertThat(doc.body().attr("onLoad")).isEqualTo("document.forms[0].submit()"); // SAMLResponse will be posted to the IdP's logout response URL. final Element form = doc.body().child(0); assertThat(form.attr("method")).isEqualTo("post"); assertThat(form.attr("action")).isEqualTo("http://idp.example.com/saml/slo/post"); assertThat(form.child(0).attr("name")).isEqualTo(SAML_RESPONSE); }
/** * Returns the {@link HttpHeaderNames#AUTHORITY AUTHORITY} of this message, in the form of * {@code "hostname:port"}. * * @return the authority, or {@code null} if there's no such header */ @Nullable default String authority() { return headers().authority(); }
@Test public void https() throws Exception { final ClientFactory clientFactory = new ClientFactoryBuilder() .sslContextCustomizer(b -> b.trustManager(InsecureTrustManagerFactory.INSTANCE)) .build(); final HttpClient client = HttpClient.of(clientFactory, server().httpsUri("/")); final AggregatedHttpMessage response = client.get("/jsp/index.jsp").aggregate().get(); final String actualContent = CR_OR_LF.matcher(response.content().toStringUtf8()) .replaceAll(""); assertThat(actualContent).isEqualTo( "<html><body>" + "<p>Hello, Armerian World!</p>" + "<p>Have you heard about the class 'org.slf4j.Logger'?</p>" + "<p>Context path: </p>" + // ROOT context path "<p>Request URI: /index.jsp</p>" + "<p>Scheme: https</p>" + "</body></html>"); }
@Test public void shouldConsumeAssertion_HttpPost() throws Exception { final Response response = getAuthResponse("http://" + spHostname + ':' + rule.httpPort() + "/saml/acs/post"); final AggregatedHttpMessage msg = sendViaHttpPostBindingProtocol("/saml/acs/post", SAML_RESPONSE, response); assertThat(msg.status()).isEqualTo(HttpStatus.FOUND); assertThat(msg.headers().get(HttpHeaderNames.LOCATION)).isEqualTo("/"); }
@Test public void failure() { final HttpClient client = HttpClient.of(rule.uri("/failure")); AggregatedHttpMessage msg; msg = client.get("/immediate1").aggregate().join(); assertThat(msg.status()).isEqualTo(HttpStatus.BAD_REQUEST); msg = client.get("/immediate2").aggregate().join(); assertThat(msg.status()).isEqualTo(HttpStatus.BAD_REQUEST); msg = client.get("/defer1").aggregate().join(); assertThat(msg.status()).isEqualTo(HttpStatus.BAD_REQUEST); msg = client.get("/defer2").aggregate().join(); assertThat(msg.status()).isEqualTo(HttpStatus.BAD_REQUEST); } }
/** * Converts the specified {@link AggregatedHttpMessage} to an object of {@code expectedResultType}. * This converter allows only {@code byte[]} and {@link HttpData} as its return type, and * {@link AggregatedHttpMessage} would be consumed only if it does not have a {@code Content-Type} header * or if it has {@code Content-Type: application/octet-stream} or {@code Content-Type: application/binary}. */ @Override public Object convertRequest(ServiceRequestContext ctx, AggregatedHttpMessage request, Class<?> expectedResultType) throws Exception { final MediaType mediaType = request.headers().contentType(); if (mediaType == null || mediaType.is(MediaType.OCTET_STREAM) || mediaType.is(MediaType.APPLICATION_BINARY)) { if (expectedResultType == byte[].class) { return request.content().array(); } if (expectedResultType == HttpData.class) { return request.content(); } } return RequestConverterFunction.fallthrough(); } }
@Test public void testPathPatternService() { AggregatedHttpMessage res; res = client.get("/pathPattern/path/armeria").aggregate().join(); assertThat(res.content().toStringUtf8()).isEqualTo("path: armeria"); assertThat(res.status()).isEqualTo(HttpStatus.OK); res = client.get("/pathPattern/regex/armeria").aggregate().join(); assertThat(res.content().toStringUtf8()).isEqualTo("regex: armeria"); assertThat(res.status()).isEqualTo(HttpStatus.OK); res = client.get("/pathPattern/glob/armeria").aggregate().join(); assertThat(res.content().toStringUtf8()).isEqualTo("glob: armeria"); assertThat(res.status()).isEqualTo(HttpStatus.OK); }
@Test public void testMessageConverterService() { AggregatedHttpMessage res; String body; // JSON for (final String path : Arrays.asList("/messageConverter/node/node", "/messageConverter/node/obj", "/messageConverter/obj/obj", "/messageConverter/obj/future")) { res = client.execute(HttpHeaders.of(HttpMethod.POST, path) .contentType(MediaType.JSON_UTF_8), "{\"name\":\"armeria\"}").aggregate().join(); assertThat(res.status()).isEqualTo(HttpStatus.OK); assertThat(res.headers().contentType().is(MediaType.JSON_UTF_8)).isTrue(); body = res.content().toStringUtf8(); assertThatJson(body).node("result").isStringEqualTo("success"); assertThatJson(body).node("from").isStringEqualTo("armeria"); } // custom(text protocol) res = client.execute(HttpHeaders.of(HttpMethod.POST, "/messageConverter/custom") .contentType(MediaType.PLAIN_TEXT_UTF_8), "armeria").aggregate().join(); assertThat(res.status()).isEqualTo(HttpStatus.OK); assertThat(res.headers().contentType().is(MediaType.PLAIN_TEXT_UTF_8)).isTrue(); assertThat(res.content().toStringUtf8()).isEqualTo("success:armeria"); }
requireNonNull(res, "res"); final HttpHeaders headers = res.headers(); final HttpStatus status = headers.status(); checkArgument(status != null, "res does not contain :status."); final HttpData content = res.content(); final HttpHeaders trailingHeaders = res.trailingHeaders();