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