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.InvalidTypeException; 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.ExchangeHelper; 034 import org.apache.camel.util.IOHelper; 035 import org.apache.camel.util.ObjectHelper; 036 037 /** 038 * Binding between {@link HttpMessage} and {@link HttpServletResponse}. 039 * 040 * @version $Revision: 955530 $ 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 contentType = (String) value; 072 } 073 if (headerFilterStrategy != null 074 && !headerFilterStrategy.applyFilterToExternalHeaders(name, value)) { 075 headers.put(name, value); 076 } 077 } 078 079 //we populate the http request parameters without checking the request method 080 081 names = request.getParameterNames(); 082 while (names.hasMoreElements()) { 083 String name = (String)names.nextElement(); 084 Object value = request.getParameter(name); 085 if (headerFilterStrategy != null 086 && !headerFilterStrategy.applyFilterToExternalHeaders(name, value)) { 087 headers.put(name, value); 088 } 089 } 090 091 // store the method and query and other info in headers 092 headers.put(HttpMethods.HTTP_METHOD, request.getMethod()); 093 headers.put(HttpProducer.QUERY, request.getQueryString()); 094 } 095 096 public void writeResponse(HttpExchange exchange, HttpServletResponse response) throws IOException { 097 if (exchange.isFailed()) { 098 Message fault = exchange.getFault(false); 099 if (fault != null) { 100 doWriteFaultResponse(fault, response); 101 } else { 102 doWriteExceptionResponse(exchange.getException(), response); 103 } 104 } else { 105 // just copy the protocol relates header 106 copyProtocolHeaders(exchange.getIn(), exchange.getOut()); 107 Message out = exchange.getOut(); 108 if (out != null) { 109 doWriteResponse(out, response); 110 } 111 } 112 } 113 114 private void copyProtocolHeaders(Message request, Message response) { 115 if (request.getHeader(GZIPHelper.CONTENT_ENCODING) != null) { 116 String contentEncoding = request.getHeader(GZIPHelper.CONTENT_ENCODING, String.class); 117 response.setHeader(GZIPHelper.CONTENT_ENCODING, contentEncoding); 118 } 119 if (checkChunked(response)) { 120 response.setHeader(Exchange.TRANSFER_ENCODING, "chunked"); 121 } 122 } 123 124 protected boolean checkChunked(Message message) { 125 // set the default value to be true 126 boolean answer = true; 127 if (message.getHeader(Exchange.HTTP_CHUNKED) != null) { 128 129 answer = message.getHeader(Exchange.HTTP_CHUNKED, boolean.class); 130 } 131 return answer; 132 } 133 134 public void doWriteExceptionResponse(Throwable exception, HttpServletResponse response) throws IOException { 135 response.setStatus(500); // 500 for internal server error 136 response.setContentType("text/plain"); 137 138 // append the stacktrace as response 139 PrintWriter pw = response.getWriter(); 140 exception.printStackTrace(pw); 141 142 pw.flush(); 143 } 144 145 public void doWriteFaultResponse(Message message, HttpServletResponse response) throws IOException { 146 doWriteResponse(message, response); 147 } 148 149 public void doWriteResponse(Message message, HttpServletResponse response) throws IOException { 150 // set the status code in the response. Default is 200. 151 if (message.getHeader(HttpProducer.HTTP_RESPONSE_CODE) != null) { 152 int code = message.getHeader(HttpProducer.HTTP_RESPONSE_CODE, Integer.class); 153 response.setStatus(code); 154 } 155 // set the content type in the response. 156 if (message.getHeader("Content-Type") != null) { 157 String contentType = message.getHeader("Content-Type", String.class); 158 response.setContentType(contentType); 159 } 160 161 // append headers 162 for (String key : message.getHeaders().keySet()) { 163 String value = message.getHeader(key, String.class); 164 if (headerFilterStrategy != null 165 && !headerFilterStrategy.applyFilterToCamelHeaders(key, value)) { 166 response.setHeader(key, value); 167 } 168 } 169 170 if (message.getBody() != null) { 171 if (GZIPHelper.isGzip(message)) { 172 doWriteGZIPResponse(message, response); 173 } else { 174 doWriteDirectResponse(message, response); 175 } 176 } 177 } 178 179 protected void doWriteDirectResponse(Message message, HttpServletResponse response) throws IOException { 180 InputStream is = null; 181 if (checkChunked(message)) { 182 is = message.getBody(InputStream.class); 183 } 184 if (is != null) { 185 ServletOutputStream os = response.getOutputStream(); 186 try { 187 // copy directly from input stream to output stream 188 IOHelper.copy(is, os); 189 } finally { 190 os.close(); 191 is.close(); 192 } 193 } else { 194 // not convertable as a stream so try as a String 195 String data = message.getBody(String.class); 196 if (data != null) { 197 // set content length before we write data 198 response.setContentLength(data.length()); 199 response.getWriter().print(data); 200 response.getWriter().flush(); 201 } 202 } 203 } 204 205 protected void doWriteGZIPResponse(Message message, HttpServletResponse response) throws IOException { 206 byte[] bytes; 207 try { 208 bytes = ExchangeHelper.convertToMandatoryType(message.getExchange(), byte[].class, message.getBody()); 209 } catch (InvalidTypeException e) { 210 throw ObjectHelper.wrapRuntimeCamelException(e); 211 } 212 213 byte[] data = GZIPHelper.compressGZIP(bytes); 214 ServletOutputStream os = response.getOutputStream(); 215 try { 216 response.setContentLength(data.length); 217 os.write(data); 218 os.flush(); 219 } finally { 220 os.close(); 221 } 222 } 223 224 public Object parseBody(HttpMessage httpMessage) throws IOException { 225 // lets assume the body is a reader 226 HttpServletRequest request = httpMessage.getRequest(); 227 // Need to handle the GET Method which has no inputStream 228 if ("GET".equals(request.getMethod())) { 229 return null; 230 } 231 if (isUseReaderForPayload()) { 232 return request.getReader(); 233 } else { 234 // otherwise use input stream 235 return HttpConverter.toInputStream(request); 236 } 237 } 238 239 public boolean isUseReaderForPayload() { 240 return useReaderForPayload; 241 } 242 243 public void setUseReaderForPayload(boolean useReaderForPayload) { 244 this.useReaderForPayload = useReaderForPayload; 245 } 246 247 public HeaderFilterStrategy getHeaderFilterStrategy() { 248 return headerFilterStrategy; 249 } 250 251 public void setHeaderFilterStrategy(HeaderFilterStrategy headerFilterStrategy) { 252 this.headerFilterStrategy = headerFilterStrategy; 253 } 254 }