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