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.FileOutputStream; 021 import java.io.IOException; 022 import java.io.InputStream; 023 import java.io.OutputStream; 024 import java.io.PrintWriter; 025 import java.util.zip.GZIPOutputStream; 026 027 import javax.servlet.ServletOutputStream; 028 import javax.servlet.http.HttpServletRequest; 029 import javax.servlet.http.HttpServletResponse; 030 031 import org.apache.camel.Message; 032 import org.apache.camel.component.http.helper.GZIPHelper; 033 import org.apache.camel.spi.HeaderFilterStrategy; 034 035 /** 036 * Binding between {@link HttpMessage} and {@link HttpServletResponse}. 037 * 038 * @version $Revision: 743652 $ 039 */ 040 public class DefaultHttpBinding implements HttpBinding { 041 042 private boolean useReaderForPayload; 043 private HeaderFilterStrategy headerFilterStrategy = new HttpHeaderFilterStrategy(); 044 045 public DefaultHttpBinding() { 046 } 047 048 public DefaultHttpBinding(HeaderFilterStrategy headerFilterStrategy) { 049 this.headerFilterStrategy = headerFilterStrategy; 050 } 051 052 public void readRequest(HttpServletRequest request, HttpMessage message) { 053 // lets force a parse of the body and headers 054 message.getBody(); 055 message.getHeaders(); 056 } 057 058 public void writeResponse(HttpExchange exchange, HttpServletResponse response) throws IOException { 059 if (exchange.isFailed()) { 060 Message fault = exchange.getFault(false); 061 if (fault != null) { 062 doWriteFaultResponse(fault, response); 063 } else { 064 doWriteExceptionResponse(exchange.getException(), response); 065 } 066 } else { 067 // just copy the protocol relates header 068 copyProtocolHeaders(exchange.getIn(), exchange.getOut()); 069 Message out = exchange.getOut(); 070 if (out != null) { 071 doWriteResponse(out, response); 072 } 073 } 074 } 075 076 private void copyProtocolHeaders(Message request, Message response) { 077 if (request.getHeader(GZIPHelper.CONTENT_ENCODING) != null) { 078 String contentEncoding = request.getHeader(GZIPHelper.CONTENT_ENCODING, String.class); 079 response.setHeader(GZIPHelper.CONTENT_ENCODING, contentEncoding); 080 } 081 } 082 083 public void doWriteExceptionResponse(Throwable exception, HttpServletResponse response) throws IOException { 084 response.setStatus(500); // 500 for internal server error 085 response.setContentType("text/plain"); 086 087 // append the stacktrace as response 088 PrintWriter pw = response.getWriter(); 089 exception.printStackTrace(pw); 090 091 pw.flush(); 092 } 093 094 public void doWriteFaultResponse(Message message, HttpServletResponse response) throws IOException { 095 doWriteResponse(message, response); 096 } 097 098 public void doWriteResponse(Message message, HttpServletResponse response) throws IOException { 099 // set the status code in the response. Default is 200. 100 if (message.getHeader(HttpProducer.HTTP_RESPONSE_CODE) != null) { 101 int code = message.getHeader(HttpProducer.HTTP_RESPONSE_CODE, Integer.class); 102 response.setStatus(code); 103 } 104 // set the content type in the response. 105 if (message.getHeader("Content-Type") != null) { 106 String contentType = message.getHeader("Content-Type", String.class); 107 response.setContentType(contentType); 108 } 109 110 // append headers 111 for (String key : message.getHeaders().keySet()) { 112 String value = message.getHeader(key, String.class); 113 if (headerFilterStrategy != null 114 && !headerFilterStrategy.applyFilterToCamelHeaders(key, value)) { 115 response.setHeader(key, value); 116 } 117 } 118 119 // write the body. 120 if (message.getBody() != null) { 121 // try to stream the body since that would be the most efficient 122 InputStream is = message.getBody(InputStream.class); 123 if (is != null) { 124 ServletOutputStream os = response.getOutputStream(); 125 try { 126 ByteArrayOutputStream initialArray = new ByteArrayOutputStream(); 127 int c; 128 while ((c = is.read()) >= 0) { 129 initialArray.write(c); 130 } 131 byte[] processedArray = processReponseContent(message, initialArray.toByteArray(), response); 132 os.write(processedArray); 133 // set content length before we flush 134 // Here the processedArray length is used instead of the 135 // length of the characters in written to the initialArray 136 // because if the method processReponseContent compresses 137 // the data, the processedArray may contain a different length 138 response.setContentLength(processedArray.length); 139 os.flush(); 140 } finally { 141 os.close(); 142 is.close(); 143 } 144 } else { 145 String data = message.getBody(String.class); 146 if (data != null) { 147 // set content length before we write data 148 response.setContentLength(data.length()); 149 response.getWriter().print(data); 150 response.getWriter().flush(); 151 } 152 } 153 154 } 155 } 156 157 protected byte[] processReponseContent(Message message, byte[] array, HttpServletResponse response) throws IOException { 158 String gzipEncoding = message.getHeader(GZIPHelper.CONTENT_ENCODING, String.class); 159 return GZIPHelper.compressArrayIfGZIPRequested(gzipEncoding, array, response); 160 } 161 162 public Object parseBody(HttpMessage httpMessage) throws IOException { 163 // lets assume the body is a reader 164 HttpServletRequest request = httpMessage.getRequest(); 165 // Need to handle the GET Method which has no inputStream 166 if ("GET".equals(request.getMethod())) { 167 return null; 168 } 169 if (isUseReaderForPayload()) { 170 return request.getReader(); 171 } else { 172 return GZIPHelper.getInputStream(request); 173 } 174 } 175 176 public boolean isUseReaderForPayload() { 177 return useReaderForPayload; 178 } 179 180 public void setUseReaderForPayload(boolean useReaderForPayload) { 181 this.useReaderForPayload = useReaderForPayload; 182 } 183 184 public HeaderFilterStrategy getHeaderFilterStrategy() { 185 return headerFilterStrategy; 186 } 187 188 public void setHeaderFilterStrategy(HeaderFilterStrategy headerFilterStrategy) { 189 this.headerFilterStrategy = headerFilterStrategy; 190 } 191 }