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