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