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; 018 019 import java.io.IOException; 020 import java.io.InputStream; 021 import java.io.PrintWriter; 022 import java.util.Enumeration; 023 import java.util.Map; 024 import javax.servlet.ServletOutputStream; 025 import javax.servlet.http.HttpServletRequest; 026 import javax.servlet.http.HttpServletResponse; 027 028 import org.apache.camel.Exchange; 029 import org.apache.camel.InvalidPayloadException; 030 import org.apache.camel.Message; 031 import org.apache.camel.component.http.helper.GZIPHelper; 032 import org.apache.camel.spi.HeaderFilterStrategy; 033 import org.apache.camel.util.IOHelper; 034 import org.apache.camel.util.MessageHelper; 035 import org.apache.camel.util.ObjectHelper; 036 037 /** 038 * Binding between {@link HttpMessage} and {@link HttpServletResponse}. 039 * 040 * @version $Revision: 827033 $ 041 */ 042 public class DefaultHttpBinding implements HttpBinding { 043 044 private boolean useReaderForPayload; 045 private HeaderFilterStrategy headerFilterStrategy = new HttpHeaderFilterStrategy(); 046 047 public DefaultHttpBinding() { 048 } 049 050 public DefaultHttpBinding(HeaderFilterStrategy headerFilterStrategy) { 051 this.headerFilterStrategy = headerFilterStrategy; 052 } 053 054 public void readRequest(HttpServletRequest request, HttpMessage message) { 055 // lets parser the parameterMap first to avoid consuming the POST parameters as InputStream 056 Map parameterMap = request.getParameterMap(); 057 058 // lets force a parse of the body and headers 059 message.getBody(); 060 // populate the headers from the request 061 Map<String, Object> headers = message.getHeaders(); 062 063 String contentType = ""; 064 //apply the headerFilterStrategy 065 Enumeration names = request.getHeaderNames(); 066 while (names.hasMoreElements()) { 067 String name = (String)names.nextElement(); 068 Object value = request.getHeader(name); 069 // mapping the content-type 070 if (name.toLowerCase().equals("content-type")) { 071 name = Exchange.CONTENT_TYPE; 072 contentType = (String) value; 073 } 074 if (headerFilterStrategy != null 075 && !headerFilterStrategy.applyFilterToExternalHeaders(name, value, message.getExchange())) { 076 headers.put(name, value); 077 } 078 } 079 080 //we populate the http request parameters for GET and POST 081 String method = request.getMethod(); 082 if (method.equalsIgnoreCase("GET") || (method.equalsIgnoreCase("POST") && contentType.equalsIgnoreCase("application/x-www-form-urlencoded"))) { 083 names = request.getParameterNames(); 084 while (names.hasMoreElements()) { 085 String name = (String)names.nextElement(); 086 Object value = request.getParameter(name); 087 if (headerFilterStrategy != null 088 && !headerFilterStrategy.applyFilterToExternalHeaders(name, value, message.getExchange())) { 089 headers.put(name, value); 090 } 091 } 092 } 093 094 // store the method and query and other info in headers 095 headers.put(Exchange.HTTP_METHOD, request.getMethod()); 096 headers.put(Exchange.HTTP_QUERY, request.getQueryString()); 097 headers.put(Exchange.HTTP_URL, request.getRequestURL()); 098 headers.put(Exchange.HTTP_URI, request.getRequestURI()); 099 headers.put(Exchange.HTTP_PATH, request.getPathInfo()); 100 headers.put(Exchange.CONTENT_TYPE, request.getContentType()); 101 headers.put(Exchange.HTTP_CHARACTER_ENCODING, request.getCharacterEncoding()); 102 } 103 104 public void writeResponse(Exchange exchange, HttpServletResponse response) throws IOException { 105 if (exchange.isFailed()) { 106 if (exchange.getException() != null) { 107 doWriteExceptionResponse(exchange.getException(), response); 108 } else { 109 // it must be a fault, no need to check for the fault flag on the message 110 doWriteFaultResponse(exchange.getOut(), response, exchange); 111 } 112 } else { 113 // just copy the protocol relates header 114 copyProtocolHeaders(exchange.getIn(), exchange.getOut()); 115 Message out = exchange.getOut(); 116 if (out != null) { 117 doWriteResponse(out, response, exchange); 118 } 119 } 120 } 121 122 private void copyProtocolHeaders(Message request, Message response) { 123 if (request.getHeader(Exchange.CONTENT_ENCODING) != null) { 124 String contentEncoding = request.getHeader(Exchange.CONTENT_ENCODING, String.class); 125 response.setHeader(Exchange.CONTENT_ENCODING, contentEncoding); 126 } 127 } 128 129 public void doWriteExceptionResponse(Throwable exception, HttpServletResponse response) throws IOException { 130 response.setStatus(500); // 500 for internal server error 131 response.setContentType("text/plain"); 132 133 // append the stacktrace as response 134 PrintWriter pw = response.getWriter(); 135 exception.printStackTrace(pw); 136 137 pw.flush(); 138 } 139 140 public void doWriteFaultResponse(Message message, HttpServletResponse response, Exchange exchange) throws IOException { 141 doWriteResponse(message, response, exchange); 142 } 143 144 public void doWriteResponse(Message message, HttpServletResponse response, Exchange exchange) throws IOException { 145 // set the status code in the response. Default is 200. 146 if (message.getHeader(Exchange.HTTP_RESPONSE_CODE) != null) { 147 int code = message.getHeader(Exchange.HTTP_RESPONSE_CODE, Integer.class); 148 response.setStatus(code); 149 } 150 // set the content type in the response. 151 String contentType = MessageHelper.getContentType(message); 152 if (MessageHelper.getContentType(message) != null) { 153 response.setContentType(contentType); 154 } 155 156 // append headers 157 for (String key : message.getHeaders().keySet()) { 158 String value = message.getHeader(key, String.class); 159 if (headerFilterStrategy != null 160 && !headerFilterStrategy.applyFilterToCamelHeaders(key, value, exchange)) { 161 response.setHeader(key, value); 162 } 163 } 164 165 // write the body. 166 if (message.getBody() != null) { 167 if (GZIPHelper.isGzip(message)) { 168 doWriteGZIPResponse(message, response, exchange); 169 } else { 170 doWriteDirectResponse(message, response, exchange); 171 } 172 } 173 } 174 175 protected void doWriteDirectResponse(Message message, HttpServletResponse response, Exchange exchange) throws IOException { 176 InputStream is = message.getBody(InputStream.class); 177 if (is != null) { 178 ServletOutputStream os = response.getOutputStream(); 179 try { 180 // copy directly from input stream to output stream 181 IOHelper.copy(is, os); 182 } finally { 183 try { 184 os.close(); 185 } catch (Exception e) { 186 // ignore, maybe client have disconnected or timed out 187 } 188 try { 189 is.close(); 190 } catch (Exception e) { 191 // ignore, maybe client have disconnected or timed out 192 } 193 } 194 } else { 195 // not convertable as a stream so try as a String 196 String data = message.getBody(String.class); 197 if (data != null) { 198 // set content length before we write data 199 response.setContentLength(data.length()); 200 response.getWriter().print(data); 201 response.getWriter().flush(); 202 } 203 } 204 } 205 206 protected void doWriteGZIPResponse(Message message, HttpServletResponse response, Exchange exchange) throws IOException { 207 byte[] bytes; 208 try { 209 bytes = message.getMandatoryBody(byte[].class); 210 } catch (InvalidPayloadException e) { 211 throw ObjectHelper.wrapRuntimeCamelException(e); 212 } 213 214 byte[] data = GZIPHelper.compressGZIP(bytes); 215 ServletOutputStream os = response.getOutputStream(); 216 try { 217 response.setContentLength(data.length); 218 os.write(data); 219 os.flush(); 220 } finally { 221 os.close(); 222 } 223 } 224 225 public Object parseBody(HttpMessage httpMessage) throws IOException { 226 // lets assume the body is a reader 227 HttpServletRequest request = httpMessage.getRequest(); 228 // Need to handle the GET Method which has no inputStream 229 if ("GET".equals(request.getMethod())) { 230 return null; 231 } 232 if (isUseReaderForPayload()) { 233 return request.getReader(); 234 } else { 235 // otherwise use input stream 236 return HttpConverter.toInputStream(request); 237 } 238 } 239 240 public boolean isUseReaderForPayload() { 241 return useReaderForPayload; 242 } 243 244 public void setUseReaderForPayload(boolean useReaderForPayload) { 245 this.useReaderForPayload = useReaderForPayload; 246 } 247 248 public HeaderFilterStrategy getHeaderFilterStrategy() { 249 return headerFilterStrategy; 250 } 251 252 public void setHeaderFilterStrategy(HeaderFilterStrategy headerFilterStrategy) { 253 this.headerFilterStrategy = headerFilterStrategy; 254 } 255 256 }