org.apache.camel.component.netty.http.NettyHttpHelper Maven / Gradle / Ivy
The newest version!
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.component.netty.http;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Map;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpMethod;
import org.apache.camel.Exchange;
import org.apache.camel.Message;
import org.apache.camel.RuntimeExchangeException;
import org.apache.camel.util.CollectionHelper;
import org.apache.camel.util.IOHelper;
import org.apache.camel.util.ObjectHelper;
import org.apache.camel.util.URISupport;
import org.apache.camel.util.UnsafeUriCharactersEncoder;
/**
* Helpers.
*/
public final class NettyHttpHelper {
private NettyHttpHelper() {
}
/**
* Appends the key/value to the headers.
*
* This implementation supports keys with multiple values. In such situations the value will be a
* {@link java.util.List} that contains the multiple values.
*
* @param headers headers
* @param key the key
* @param value the value
*/
public static void appendHeader(Map headers, String key, Object value) {
CollectionHelper.appendEntry(headers, key, value);
}
/**
* Creates the {@link HttpMethod} to use to call the remote server, often either its GET or POST.
*
* @param message the Camel message
* @return the created method
*/
public static HttpMethod createMethod(Message message, boolean hasPayload) {
// use header first
HttpMethod m = message.getHeader(NettyHttpConstants.HTTP_METHOD, HttpMethod.class);
if (m != null) {
return m;
}
String name = message.getHeader(NettyHttpConstants.HTTP_METHOD, String.class);
if (name != null) {
// must be in upper case
name = name.toUpperCase();
return HttpMethod.valueOf(name);
}
if (hasPayload) {
// use POST if we have payload
return HttpMethod.POST;
} else {
// fallback to GET
return HttpMethod.GET;
}
}
public static Exception populateNettyHttpOperationFailedException(
Exchange exchange, String url, FullHttpResponse response, int responseCode, boolean transferException) {
String statusText = response.status().reasonPhrase();
if (responseCode >= 300 && responseCode < 400) {
String redirectLocation = response.headers().get("location");
if (redirectLocation != null) {
return new NettyHttpOperationFailedException(url, responseCode, statusText, redirectLocation, response);
} else {
// no redirect location
return new NettyHttpOperationFailedException(url, responseCode, statusText, null, response);
}
}
if (transferException) {
String contentType = response.headers().get(NettyHttpConstants.CONTENT_TYPE);
if (NettyHttpConstants.CONTENT_TYPE_JAVA_SERIALIZED_OBJECT.equals(contentType)) {
// if the response was a serialized exception then use that
InputStream is = exchange.getContext().getTypeConverter().convertTo(InputStream.class, response);
if (is != null) {
try {
Object body = deserializeJavaObjectFromStream(is);
if (body instanceof Exception) {
return (Exception) body;
}
} catch (Exception e) {
return e;
} finally {
IOHelper.close(is);
}
}
}
}
// internal server error (error code 500)
return new NettyHttpOperationFailedException(url, responseCode, statusText, null, response);
}
public static Object deserializeJavaObjectFromStream(InputStream is) throws ClassNotFoundException, IOException {
if (is == null) {
return null;
}
Object answer = null;
ObjectInputStream ois = new ObjectInputStream(is);
try {
answer = ois.readObject();
} finally {
IOHelper.close(ois);
}
return answer;
}
/**
* Creates the URL to invoke.
*
* @param exchange the exchange
* @param endpoint the endpoint
* @return the URL to invoke
*/
public static String createURL(Exchange exchange, NettyHttpEndpoint endpoint) {
// rest producer may provide an override url to be used which we should discard if using (hence the remove)
String uri = (String) exchange.getIn().removeHeader(Exchange.REST_HTTP_URI);
if (uri == null) {
uri = endpoint.getEndpointUri();
}
// resolve placeholders in uri
try {
uri = exchange.getContext().resolvePropertyPlaceholders(uri);
} catch (Exception e) {
throw new RuntimeExchangeException("Cannot resolve property placeholders with uri: " + uri, exchange, e);
}
// append HTTP_PATH to HTTP_URI if it is provided in the header
String path = exchange.getIn().getHeader(NettyHttpConstants.HTTP_PATH, String.class);
// NOW the HTTP_PATH is just related path, we don't need to trim it
if (path != null && !path.isEmpty()) {
if (path.startsWith("/")) {
path = path.substring(1);
}
// inject the dynamic path before the query params, if there are any
int idx = uri.indexOf('?');
// if there are no query params
if (idx == -1) {
// make sure that there is exactly one "/" between HTTP_URI and HTTP_PATH
uri = uri.endsWith("/") ? uri : uri + "/";
uri = uri.concat(path);
} else {
// there are query params, so inject the relative path in the right place
String base = uri.substring(0, idx);
base = base.endsWith("/") ? base : base + "/";
base = base.concat(path);
uri = base.concat(uri.substring(idx));
}
}
// ensure uri is encoded to be valid
uri = UnsafeUriCharactersEncoder.encodeHttpURI(uri);
return uri;
}
/**
* Creates the URI to invoke.
*
* @param exchange the exchange
* @param url the url to invoke
* @return the URI to invoke
*/
public static URI createURI(Exchange exchange, String url) throws URISyntaxException {
URI uri = new URI(url);
// rest producer may provide an override query string to be used which we should discard if using (hence the remove)
String queryString = (String) exchange.getIn().removeHeader(Exchange.REST_HTTP_QUERY);
// is a query string provided in the endpoint URI or in a header
// (header overrules endpoint, raw query header overrules query header)
if (queryString == null) {
queryString = exchange.getIn().getHeader(NettyHttpConstants.HTTP_RAW_QUERY, String.class);
}
if (queryString == null) {
queryString = exchange.getIn().getHeader(NettyHttpConstants.HTTP_QUERY, String.class);
}
if (queryString == null) {
// use raw as we encode just below
queryString = uri.getRawQuery();
}
if (queryString != null) {
// need to encode query string
queryString = UnsafeUriCharactersEncoder.encodeHttpURI(queryString);
if (ObjectHelper.isEmpty(uri.getPath())) {
// If queryString is present, the path cannot be empty - CAMEL-13707
uri = new URI(url + "/");
}
uri = URISupport.createURIWithQuery(uri, queryString);
}
return uri;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy