PageRenderTime 42ms CodeModel.GetById 13ms RepoModel.GetById 1ms app.codeStats 0ms

/components/camel-netty4-http/src/main/java/org/apache/camel/component/netty4/http/NettyHttpHelper.java

https://gitlab.com/matticala/apache-camel
Java | 295 lines | 187 code | 28 blank | 80 comment | 50 complexity | 7f72c30078d2dfa683fc8370e4cfc69f MD5 | raw file
  1. /**
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package org.apache.camel.component.netty4.http;
  18. import java.io.IOException;
  19. import java.io.InputStream;
  20. import java.io.ObjectInputStream;
  21. import java.net.URI;
  22. import java.net.URISyntaxException;
  23. import java.util.ArrayList;
  24. import java.util.List;
  25. import java.util.Map;
  26. import io.netty.handler.codec.http.FullHttpResponse;
  27. import io.netty.handler.codec.http.HttpMethod;
  28. import org.apache.camel.Exchange;
  29. import org.apache.camel.Message;
  30. import org.apache.camel.RuntimeExchangeException;
  31. import org.apache.camel.converter.IOConverter;
  32. import org.apache.camel.util.IOHelper;
  33. import org.apache.camel.util.ObjectHelper;
  34. import org.apache.camel.util.StringHelper;
  35. import org.apache.camel.util.URISupport;
  36. import org.apache.camel.util.UnsafeUriCharactersEncoder;
  37. /**
  38. * Helpers.
  39. */
  40. public final class NettyHttpHelper {
  41. private NettyHttpHelper() {
  42. }
  43. @SuppressWarnings("deprecation")
  44. public static void setCharsetFromContentType(String contentType, Exchange exchange) {
  45. String charset = getCharsetFromContentType(contentType);
  46. if (charset != null) {
  47. exchange.setProperty(Exchange.CHARSET_NAME, IOConverter.normalizeCharset(charset));
  48. }
  49. }
  50. public static String getCharsetFromContentType(String contentType) {
  51. if (contentType != null) {
  52. // find the charset and set it to the Exchange
  53. int index = contentType.indexOf("charset=");
  54. if (index > 0) {
  55. String charset = contentType.substring(index + 8);
  56. // there may be another parameter after a semi colon, so skip that
  57. if (charset.contains(";")) {
  58. charset = ObjectHelper.before(charset, ";");
  59. }
  60. return IOHelper.normalizeCharset(charset);
  61. }
  62. }
  63. return null;
  64. }
  65. /**
  66. * Appends the key/value to the headers.
  67. * <p/>
  68. * This implementation supports keys with multiple values. In such situations the value
  69. * will be a {@link java.util.List} that contains the multiple values.
  70. *
  71. * @param headers headers
  72. * @param key the key
  73. * @param value the value
  74. */
  75. @SuppressWarnings("unchecked")
  76. public static void appendHeader(Map<String, Object> headers, String key, Object value) {
  77. if (headers.containsKey(key)) {
  78. Object existing = headers.get(key);
  79. List<Object> list;
  80. if (existing instanceof List) {
  81. list = (List<Object>) existing;
  82. } else {
  83. list = new ArrayList<>();
  84. list.add(existing);
  85. }
  86. list.add(value);
  87. value = list;
  88. }
  89. headers.put(key, value);
  90. }
  91. /**
  92. * Creates the {@link HttpMethod} to use to call the remote server, often either its GET or POST.
  93. *
  94. * @param message the Camel message
  95. * @return the created method
  96. */
  97. public static HttpMethod createMethod(Message message, boolean hasPayload) {
  98. // use header first
  99. HttpMethod m = message.getHeader(Exchange.HTTP_METHOD, HttpMethod.class);
  100. if (m != null) {
  101. return m;
  102. }
  103. String name = message.getHeader(Exchange.HTTP_METHOD, String.class);
  104. if (name != null) {
  105. // must be in upper case
  106. name = name.toUpperCase();
  107. return HttpMethod.valueOf(name);
  108. }
  109. if (hasPayload) {
  110. // use POST if we have payload
  111. return HttpMethod.POST;
  112. } else {
  113. // fallback to GET
  114. return HttpMethod.GET;
  115. }
  116. }
  117. public static Exception populateNettyHttpOperationFailedException(Exchange exchange, String url, FullHttpResponse response, int responseCode, boolean transferException) {
  118. String uri = url;
  119. String statusText = response.status().reasonPhrase();
  120. if (responseCode >= 300 && responseCode < 400) {
  121. String redirectLocation = response.headers().get("location");
  122. if (redirectLocation != null) {
  123. return new NettyHttpOperationFailedException(uri, responseCode, statusText, redirectLocation, response);
  124. } else {
  125. // no redirect location
  126. return new NettyHttpOperationFailedException(uri, responseCode, statusText, null, response);
  127. }
  128. }
  129. if (transferException) {
  130. String contentType = response.headers().get(Exchange.CONTENT_TYPE);
  131. if (NettyHttpConstants.CONTENT_TYPE_JAVA_SERIALIZED_OBJECT.equals(contentType)) {
  132. // if the response was a serialized exception then use that
  133. InputStream is = exchange.getContext().getTypeConverter().convertTo(InputStream.class, response);
  134. if (is != null) {
  135. try {
  136. Object body = deserializeJavaObjectFromStream(is);
  137. if (body instanceof Exception) {
  138. return (Exception) body;
  139. }
  140. } catch (Exception e) {
  141. return e;
  142. } finally {
  143. IOHelper.close(is);
  144. }
  145. }
  146. }
  147. }
  148. // internal server error (error code 500)
  149. return new NettyHttpOperationFailedException(uri, responseCode, statusText, null, response);
  150. }
  151. public static Object deserializeJavaObjectFromStream(InputStream is) throws ClassNotFoundException, IOException {
  152. if (is == null) {
  153. return null;
  154. }
  155. Object answer = null;
  156. ObjectInputStream ois = new ObjectInputStream(is);
  157. try {
  158. answer = ois.readObject();
  159. } finally {
  160. IOHelper.close(ois);
  161. }
  162. return answer;
  163. }
  164. /**
  165. * Creates the URL to invoke.
  166. *
  167. * @param exchange the exchange
  168. * @param endpoint the endpoint
  169. * @return the URL to invoke
  170. */
  171. public static String createURL(Exchange exchange, NettyHttpEndpoint endpoint) throws URISyntaxException {
  172. // rest producer may provide an override url to be used which we should discard if using (hence the remove)
  173. String uri = (String) exchange.getIn().removeHeader(Exchange.REST_HTTP_URI);
  174. if (uri == null) {
  175. uri = endpoint.getEndpointUri();
  176. }
  177. // resolve placeholders in uri
  178. try {
  179. uri = exchange.getContext().resolvePropertyPlaceholders(uri);
  180. } catch (Exception e) {
  181. throw new RuntimeExchangeException("Cannot resolve property placeholders with uri: " + uri, exchange, e);
  182. }
  183. // append HTTP_PATH to HTTP_URI if it is provided in the header
  184. String path = exchange.getIn().getHeader(Exchange.HTTP_PATH, String.class);
  185. // NOW the HTTP_PATH is just related path, we don't need to trim it
  186. if (path != null) {
  187. if (path.startsWith("/")) {
  188. path = path.substring(1);
  189. }
  190. if (path.length() > 0) {
  191. // inject the dynamic path before the query params, if there are any
  192. int idx = uri.indexOf("?");
  193. // if there are no query params
  194. if (idx == -1) {
  195. // make sure that there is exactly one "/" between HTTP_URI and HTTP_PATH
  196. uri = uri.endsWith("/") ? uri : uri + "/";
  197. uri = uri.concat(path);
  198. } else {
  199. // there are query params, so inject the relative path in the right place
  200. String base = uri.substring(0, idx);
  201. base = base.endsWith("/") ? base : base + "/";
  202. base = base.concat(path);
  203. uri = base.concat(uri.substring(idx));
  204. }
  205. }
  206. }
  207. // ensure uri is encoded to be valid
  208. uri = UnsafeUriCharactersEncoder.encodeHttpURI(uri);
  209. return uri;
  210. }
  211. /**
  212. * Creates the URI to invoke.
  213. *
  214. * @param exchange the exchange
  215. * @param url the url to invoke
  216. * @param endpoint the endpoint
  217. * @return the URI to invoke
  218. */
  219. public static URI createURI(Exchange exchange, String url, NettyHttpEndpoint endpoint) throws URISyntaxException {
  220. URI uri = new URI(url);
  221. // rest producer may provide an override query string to be used which we should discard if using (hence the remove)
  222. String queryString = (String) exchange.getIn().removeHeader(Exchange.REST_HTTP_QUERY);
  223. // is a query string provided in the endpoint URI or in a header
  224. // (header overrules endpoint, raw query header overrules query header)
  225. if (queryString == null) {
  226. queryString = exchange.getIn().getHeader(Exchange.HTTP_RAW_QUERY, String.class);
  227. }
  228. if (queryString == null) {
  229. queryString = exchange.getIn().getHeader(Exchange.HTTP_QUERY, String.class);
  230. }
  231. if (queryString == null) {
  232. // use raw as we encode just below
  233. queryString = uri.getRawQuery();
  234. }
  235. if (queryString != null) {
  236. // need to encode query string
  237. queryString = UnsafeUriCharactersEncoder.encodeHttpURI(queryString);
  238. uri = URISupport.createURIWithQuery(uri, queryString);
  239. }
  240. return uri;
  241. }
  242. /**
  243. * Checks whether the given http status code is within the ok range
  244. *
  245. * @param statusCode the status code
  246. * @param okStatusCodeRange the ok range (inclusive)
  247. * @return <tt>true</tt> if ok, <tt>false</tt> otherwise
  248. */
  249. public static boolean isStatusCodeOk(int statusCode, String okStatusCodeRange) {
  250. String[] ranges = okStatusCodeRange.split(",");
  251. for (String range : ranges) {
  252. boolean ok;
  253. if (range.contains("-")) {
  254. int from = Integer.valueOf(StringHelper.before(range, "-"));
  255. int to = Integer.valueOf(StringHelper.after(range, "-"));
  256. ok = statusCode >= from && statusCode <= to;
  257. } else {
  258. int exact = Integer.valueOf(range);
  259. ok = exact == statusCode;
  260. }
  261. if (ok) {
  262. return true;
  263. }
  264. }
  265. return false;
  266. }
  267. }