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 javax.servlet.ServletResponse;
026    import javax.servlet.http.HttpServletRequest;
027    
028    import org.apache.camel.Exchange;
029    import org.apache.camel.RuntimeExchangeException;
030    import org.apache.camel.component.http.HttpConstants;
031    import org.apache.camel.component.http.HttpConverter;
032    import org.apache.camel.component.http.HttpEndpoint;
033    import org.apache.camel.component.http.HttpMethods;
034    import org.apache.camel.converter.IOConverter;
035    import org.apache.camel.converter.stream.CachedOutputStream;
036    import org.apache.camel.util.IOHelper;
037    
038    public final class HttpHelper {
039    
040        private HttpHelper() {
041            // Helper class
042        }
043    
044        public static void setCharsetFromContentType(String contentType, Exchange exchange) {
045            if (contentType != null) {
046                // find the charset and set it to the Exchange
047                int index = contentType.indexOf("charset=");
048                if (index > 0) {
049                    String charset = contentType.substring(index + 8);
050                    exchange.setProperty(Exchange.CHARSET_NAME, IOConverter.normalizeCharset(charset));
051                }
052            }
053        }
054        
055        /**
056         * Writes the given object as response body to the servlet response
057         * <p/>
058         * The content type will be set to {@link HttpConstants#CONTENT_TYPE_JAVA_SERIALIZED_OBJECT}
059         *
060         * @param response servlet response
061         * @param target   object to write
062         * @throws IOException is thrown if error writing
063         */
064        public static void writeObjectToServletResponse(ServletResponse response, Object target) throws IOException {
065            response.setContentType(HttpConstants.CONTENT_TYPE_JAVA_SERIALIZED_OBJECT);
066            writeObjectToStream(response.getOutputStream(), target);
067        }
068    
069        /**
070         * Writes the given object as response body to the output stream
071         *
072         * @param stream output stream
073         * @param target   object to write
074         * @throws IOException is thrown if error writing
075         */
076        public static void writeObjectToStream(OutputStream stream, Object target) throws IOException {
077            ObjectOutputStream oos = new ObjectOutputStream(stream);
078            oos.writeObject(target);
079            oos.flush();
080            IOHelper.close(oos);
081        }
082    
083        /**
084         * Deserializes the input stream to a Java object
085         *
086         * @param is input stream for the Java object
087         * @return the java object, or <tt>null</tt> if input stream was <tt>null</tt>
088         * @throws ClassNotFoundException is thrown if class not found
089         * @throws IOException can be thrown
090         */
091        public static Object deserializeJavaObjectFromStream(InputStream is) throws ClassNotFoundException, IOException {
092            if (is == null) {
093                return null;
094            }
095    
096            Object answer = null;
097            ObjectInputStream ois = new ObjectInputStream(is);
098            try {
099                answer = ois.readObject();
100            } finally {
101                IOHelper.close(ois);
102            }
103    
104            return answer;
105        }
106    
107        /**
108         * Reads the response body from the given http servlet request.
109         *
110         * @param request  http servlet request
111         * @param exchange the exchange
112         * @return the response body, can be <tt>null</tt> if no body
113         * @throws IOException is thrown if error reading response body
114         */
115        public static Object readResponseBodyFromServletRequest(HttpServletRequest request, Exchange exchange) throws IOException {
116            InputStream is = HttpConverter.toInputStream(request, exchange);
117            return readResponseBodyFromInputStream(is, exchange);
118        }
119    
120        /**
121         * Reads the response body from the given input stream.
122         *
123         * @param is       the input stream
124         * @param exchange the exchange
125         * @return the response body, can be <tt>null</tt> if no body
126         * @throws IOException is thrown if error reading response body
127         */
128        public static Object readResponseBodyFromInputStream(InputStream is, Exchange exchange) throws IOException {
129            if (is == null) {
130                return null;
131            }
132    
133            // convert the input stream to StreamCache if the stream cache is not disabled
134            if (exchange.getProperty(Exchange.DISABLE_HTTP_STREAM_CACHE, Boolean.FALSE, Boolean.class)) {
135                return is;
136            } else {
137                CachedOutputStream cos = new CachedOutputStream(exchange);
138                IOHelper.copyAndCloseInput(is, cos);
139                return cos.getStreamCache();
140            }
141        }
142    
143        /**
144         * Creates the URL to invoke.
145         *
146         * @param exchange the exchange
147         * @param endpoint the endpoint
148         * @return the URL to invoke
149         */
150        public static String createURL(Exchange exchange, HttpEndpoint endpoint) {
151            String uri = null;
152            if (!(endpoint.isBridgeEndpoint())) {
153                uri = exchange.getIn().getHeader(Exchange.HTTP_URI, String.class);
154            }
155            if (uri == null) {
156                uri = endpoint.getHttpUri().toASCIIString();
157            }
158    
159            // resolve placeholders in uri
160            try {
161                uri = exchange.getContext().resolvePropertyPlaceholders(uri);
162            } catch (Exception e) {
163                throw new RuntimeExchangeException("Cannot resolve property placeholders with uri: " + uri, exchange, e);
164            }
165    
166            // append HTTP_PATH to HTTP_URI if it is provided in the header
167            String path = exchange.getIn().getHeader(Exchange.HTTP_PATH, String.class);
168            if (path != null) {
169                if (path.startsWith("/")) {
170                    URI baseURI;
171                    String baseURIString = exchange.getIn().getHeader(Exchange.HTTP_BASE_URI, String.class);
172                    try {
173                        if (baseURIString == null) {
174                            if (exchange.getFromEndpoint() != null) {
175                                baseURIString = exchange.getFromEndpoint().getEndpointUri();
176                            } else {
177                                // will set a default one for it
178                                baseURIString = "/";
179                            }
180                        }
181                        baseURI = new URI(baseURIString);
182                        String basePath = baseURI.getRawPath();
183                        if (path.startsWith(basePath)) {
184                            path = path.substring(basePath.length());
185                            if (path.startsWith("/")) {
186                                path = path.substring(1);
187                            }
188                        } else {
189                            throw new RuntimeExchangeException("Cannot analyze the Exchange.HTTP_PATH header, due to: cannot find the right HTTP_BASE_URI", exchange);
190                        }
191                    } catch (Throwable t) {
192                        throw new RuntimeExchangeException("Cannot analyze the Exchange.HTTP_PATH header, due to: " + t.getMessage(), exchange, t);
193                    }
194    
195                }
196                if (path.length() > 0) {
197                    // make sure that there is exactly one "/" between HTTP_URI and
198                    // HTTP_PATH
199                    if (!uri.endsWith("/")) {
200                        uri = uri + "/";
201                    }
202                    uri = uri.concat(path);
203                }
204            }
205            return uri;
206        }
207    
208        /**
209         * Creates the HttpMethod to use to call the remote server, often either its GET or POST.
210         *
211         * @param exchange  the exchange
212         * @return the created method
213         */
214        public static HttpMethods createMethod(Exchange exchange, HttpEndpoint endpoint, boolean hasPayload) {
215            // is a query string provided in the endpoint URI or in a header (header
216            // overrules endpoint)
217            String queryString = exchange.getIn().getHeader(Exchange.HTTP_QUERY, String.class);
218            if (queryString == null) {
219                queryString = endpoint.getHttpUri().getQuery();
220            }
221    
222            // compute what method to use either GET or POST
223            HttpMethods answer;
224            HttpMethods m = exchange.getIn().getHeader(Exchange.HTTP_METHOD, HttpMethods.class);
225            if (m != null) {
226                // always use what end-user provides in a header
227                answer = m;
228            } else if (queryString != null) {
229                // if a query string is provided then use GET
230                answer = HttpMethods.GET;
231            } else {
232                // fallback to POST if we have payload, otherwise GET
233                answer = hasPayload ? HttpMethods.POST : HttpMethods.GET;
234            }
235    
236            return answer;
237        }
238    }