001 /**
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.camel.component.http.helper;
018
019 import java.io.IOException;
020 import java.io.InputStream;
021 import java.io.ObjectInputStream;
022 import java.io.ObjectOutputStream;
023 import java.io.OutputStream;
024 import java.net.URI;
025 import java.net.URISyntaxException;
026 import java.util.ArrayList;
027 import java.util.List;
028 import java.util.Map;
029 import javax.servlet.ServletResponse;
030 import javax.servlet.http.HttpServletRequest;
031
032 import org.apache.camel.Exchange;
033 import org.apache.camel.RuntimeExchangeException;
034 import org.apache.camel.component.http.HttpConstants;
035 import org.apache.camel.component.http.HttpConverter;
036 import org.apache.camel.component.http.HttpEndpoint;
037 import org.apache.camel.component.http.HttpMethods;
038 import org.apache.camel.converter.IOConverter;
039 import org.apache.camel.converter.stream.CachedOutputStream;
040 import org.apache.camel.util.IOHelper;
041 import org.apache.camel.util.ObjectHelper;
042
043 public final class HttpHelper {
044
045 private HttpHelper() {
046 // Helper class
047 }
048
049 public static void setCharsetFromContentType(String contentType, Exchange exchange) {
050 if (contentType != null) {
051 // find the charset and set it to the Exchange
052 int index = contentType.indexOf("charset=");
053 if (index > 0) {
054 String charset = contentType.substring(index + 8);
055 exchange.setProperty(Exchange.CHARSET_NAME, IOConverter.normalizeCharset(charset));
056 }
057 }
058 }
059
060 /**
061 * Writes the given object as response body to the servlet response
062 * <p/>
063 * The content type will be set to {@link HttpConstants#CONTENT_TYPE_JAVA_SERIALIZED_OBJECT}
064 *
065 * @param response servlet response
066 * @param target object to write
067 * @throws IOException is thrown if error writing
068 */
069 public static void writeObjectToServletResponse(ServletResponse response, Object target) throws IOException {
070 response.setContentType(HttpConstants.CONTENT_TYPE_JAVA_SERIALIZED_OBJECT);
071 writeObjectToStream(response.getOutputStream(), target);
072 }
073
074 /**
075 * Writes the given object as response body to the output stream
076 *
077 * @param stream output stream
078 * @param target object to write
079 * @throws IOException is thrown if error writing
080 */
081 public static void writeObjectToStream(OutputStream stream, Object target) throws IOException {
082 ObjectOutputStream oos = new ObjectOutputStream(stream);
083 oos.writeObject(target);
084 oos.flush();
085 IOHelper.close(oos);
086 }
087
088 /**
089 * Deserializes the input stream to a Java object
090 *
091 * @param is input stream for the Java object
092 * @return the java object, or <tt>null</tt> if input stream was <tt>null</tt>
093 * @throws ClassNotFoundException is thrown if class not found
094 * @throws IOException can be thrown
095 */
096 public static Object deserializeJavaObjectFromStream(InputStream is) throws ClassNotFoundException, IOException {
097 if (is == null) {
098 return null;
099 }
100
101 Object answer = null;
102 ObjectInputStream ois = new ObjectInputStream(is);
103 try {
104 answer = ois.readObject();
105 } finally {
106 IOHelper.close(ois);
107 }
108
109 return answer;
110 }
111
112 /**
113 * Reads the response body from the given http servlet request.
114 *
115 * @param request http servlet request
116 * @param exchange the exchange
117 * @return the response body, can be <tt>null</tt> if no body
118 * @throws IOException is thrown if error reading response body
119 */
120 public static Object readResponseBodyFromServletRequest(HttpServletRequest request, Exchange exchange) throws IOException {
121 InputStream is = HttpConverter.toInputStream(request, exchange);
122 return readResponseBodyFromInputStream(is, exchange);
123 }
124
125 /**
126 * Reads the response body from the given input stream.
127 *
128 * @param is the input stream
129 * @param exchange the exchange
130 * @return the response body, can be <tt>null</tt> if no body
131 * @throws IOException is thrown if error reading response body
132 */
133 public static Object readResponseBodyFromInputStream(InputStream is, Exchange exchange) throws IOException {
134 if (is == null) {
135 return null;
136 }
137
138 // convert the input stream to StreamCache if the stream cache is not disabled
139 if (exchange.getProperty(Exchange.DISABLE_HTTP_STREAM_CACHE, Boolean.FALSE, Boolean.class)) {
140 return is;
141 } else {
142 CachedOutputStream cos = new CachedOutputStream(exchange);
143 IOHelper.copyAndCloseInput(is, cos);
144 return cos.getStreamCache();
145 }
146 }
147
148 /**
149 * Creates the URL to invoke.
150 *
151 * @param exchange the exchange
152 * @param endpoint the endpoint
153 * @return the URL to invoke
154 */
155 public static String createURL(Exchange exchange, HttpEndpoint endpoint) {
156 String uri = null;
157 if (!(endpoint.isBridgeEndpoint())) {
158 uri = exchange.getIn().getHeader(Exchange.HTTP_URI, String.class);
159 }
160 if (uri == null) {
161 uri = endpoint.getHttpUri().toASCIIString();
162 }
163
164 // resolve placeholders in uri
165 try {
166 uri = exchange.getContext().resolvePropertyPlaceholders(uri);
167 } catch (Exception e) {
168 throw new RuntimeExchangeException("Cannot resolve property placeholders with uri: " + uri, exchange, e);
169 }
170
171 // append HTTP_PATH to HTTP_URI if it is provided in the header
172 String path = exchange.getIn().getHeader(Exchange.HTTP_PATH, String.class);
173 if (path != null) {
174 if (path.startsWith("/")) {
175 URI baseURI;
176 String baseURIString = exchange.getIn().getHeader(Exchange.HTTP_BASE_URI, String.class);
177 try {
178 if (baseURIString == null) {
179 if (exchange.getFromEndpoint() != null) {
180 baseURIString = exchange.getFromEndpoint().getEndpointUri();
181 } else {
182 // will set a default one for it
183 baseURIString = "/";
184 }
185 }
186 baseURI = new URI(baseURIString);
187 String basePath = baseURI.getRawPath();
188 if (path.startsWith(basePath)) {
189 path = path.substring(basePath.length());
190 if (path.startsWith("/")) {
191 path = path.substring(1);
192 }
193 } else {
194 throw new RuntimeExchangeException("Cannot analyze the Exchange.HTTP_PATH header, due to: cannot find the right HTTP_BASE_URI", exchange);
195 }
196 } catch (Throwable t) {
197 throw new RuntimeExchangeException("Cannot analyze the Exchange.HTTP_PATH header, due to: " + t.getMessage(), exchange, t);
198 }
199 }
200 if (path.length() > 0) {
201 // make sure that there is exactly one "/" between HTTP_URI and
202 // HTTP_PATH
203 if (!uri.endsWith("/")) {
204 uri = uri + "/";
205 }
206 uri = uri.concat(path);
207 }
208 }
209 return uri;
210 }
211
212 /**
213 * Creates the HttpMethod to use to call the remote server, often either its GET or POST.
214 *
215 * @param exchange the exchange
216 * @return the created method
217 * @throws URISyntaxException
218 */
219 public static HttpMethods createMethod(Exchange exchange, HttpEndpoint endpoint, boolean hasPayload) throws URISyntaxException {
220 // is a query string provided in the endpoint URI or in a header (header
221 // overrules endpoint)
222 String queryString = exchange.getIn().getHeader(Exchange.HTTP_QUERY, String.class);
223 // We need also check the HTTP_URI header query part
224 String uriString = exchange.getIn().getHeader(Exchange.HTTP_URI, String.class);
225 // resolve placeholders in uriString
226 try {
227 uriString = exchange.getContext().resolvePropertyPlaceholders(uriString);
228 } catch (Exception e) {
229 throw new RuntimeExchangeException("Cannot resolve property placeholders with uri: " + uriString, exchange, e);
230 }
231 if (uriString != null) {
232 URI uri = new URI(uriString);
233 queryString = uri.getQuery();
234 }
235 if (queryString == null) {
236 queryString = endpoint.getHttpUri().getQuery();
237 }
238
239
240 // compute what method to use either GET or POST
241 HttpMethods answer;
242 HttpMethods m = exchange.getIn().getHeader(Exchange.HTTP_METHOD, HttpMethods.class);
243 if (m != null) {
244 // always use what end-user provides in a header
245 answer = m;
246 } else if (queryString != null) {
247 // if a query string is provided then use GET
248 answer = HttpMethods.GET;
249 } else {
250 // fallback to POST if we have payload, otherwise GET
251 answer = hasPayload ? HttpMethods.POST : HttpMethods.GET;
252 }
253
254 return answer;
255 }
256
257 /**
258 * Appends the key/value to the headers.
259 * <p/>
260 * This implementation supports keys with multiple values. In such situations the value
261 * will be a {@link java.util.List} that contains the multiple values.
262 *
263 * @param headers headers
264 * @param key the key
265 * @param value the value
266 */
267 @SuppressWarnings("unchecked")
268 public static void appendHeader(Map headers, String key, Object value) {
269 if (headers.containsKey(key)) {
270 Object existing = headers.get(key);
271 List list;
272 if (existing instanceof List) {
273 list = (List) existing;
274 } else {
275 list = new ArrayList();
276 list.add(existing);
277 }
278 list.add(value);
279 value = list;
280 }
281
282 headers.put(key, value);
283 }
284
285 /**
286 * Extracts the parameter value.
287 * <p/>
288 * This implementation supports HTTP multi value parameters which
289 * is based on the syntax of <tt>[value1, value2, value3]</tt> by returning
290 * a {@link List} containing the values.
291 * <p/>
292 * If the value is not a HTTP mulit value the value is returned as is.
293 *
294 * @param value the parameter value
295 * @return the extracted parameter value, see more details in javadoc.
296 */
297 @SuppressWarnings("unchecked")
298 public static Object extractHttpParameterValue(String value) {
299 if (value == null || ObjectHelper.isEmpty(value)) {
300 return value;
301 }
302
303 // trim value before checking for multiple parameters
304 String trimmed = value.trim();
305
306 if (trimmed.startsWith("[") && trimmed.endsWith("]")) {
307 // remove the [ ] markers
308 trimmed = trimmed.substring(1, trimmed.length() - 1);
309 List list = new ArrayList<String>();
310 String[] values = trimmed.split(",");
311 for (String s : values) {
312 list.add(s.trim());
313 }
314 return list;
315 }
316
317 return value;
318 }
319
320 }