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.gae.http;
018
019 import java.io.ByteArrayInputStream;
020 import java.io.InputStream;
021 import java.net.URL;
022 import java.util.zip.GZIPInputStream;
023
024 import javax.servlet.http.HttpServletRequest;
025 import javax.servlet.http.HttpServletResponse;
026
027 import com.google.appengine.api.urlfetch.HTTPHeader;
028 import com.google.appengine.api.urlfetch.HTTPMethod;
029 import com.google.appengine.api.urlfetch.HTTPRequest;
030 import com.google.appengine.api.urlfetch.HTTPResponse;
031
032 import org.apache.camel.Exchange;
033 import org.apache.camel.Message;
034 import org.apache.camel.component.gae.bind.InboundBinding;
035 import org.apache.camel.component.gae.bind.OutboundBinding;
036 import org.apache.camel.spi.HeaderFilterStrategy;
037 import org.apache.camel.util.UnsafeUriCharactersEncoder;
038
039 import static org.apache.camel.component.gae.http.GHttpEndpoint.getEndpointUrl;
040 import static org.apache.camel.component.http.helper.GZIPHelper.isGzip;
041
042 /**
043 * Binds the {@link HTTPRequest}/{@link HTTPResponse} pair of the URL fetch
044 * service to a Camel {@link Exchange}.
045 */
046 public class GHttpBinding implements
047 OutboundBinding <GHttpEndpoint, HTTPRequest, HTTPResponse>,
048 InboundBinding <GHttpEndpoint, HttpServletRequest, HttpServletResponse> {
049
050 // ----------------------------------------------------------------
051 // Outbound binding
052 // ----------------------------------------------------------------
053
054 /**
055 * Reads data from <code>response</code> and writes it to the out-message of
056 * the <code>exchange</code>.
057 *
058 * @param endpoint
059 * @param exchange
060 * @param response
061 * @return the original <code>exchange</code> instance populated with
062 * response data.
063 * @throws GHttpException
064 * if the response code is >= 400 and
065 * {@link GHttpEndpoint#isThrowExceptionOnFailure()} returns
066 * <code>true</code>.
067 */
068 public Exchange readResponse(GHttpEndpoint endpoint, Exchange exchange, HTTPResponse response) throws Exception {
069 int responseCode = response.getResponseCode();
070 readResponseHeaders(endpoint, exchange, response);
071 readResponseBody(endpoint, exchange, response);
072 if (responseCode >= 400 && endpoint.isThrowExceptionOnFailure()) {
073 throw new GHttpException(responseCode,
074 exchange.getOut().getBody(InputStream.class),
075 exchange.getOut().getHeaders());
076 }
077 return exchange;
078 }
079
080 /**
081 * Reads data from <code>exchange</code> and writes it to a newly created
082 * {@link HTTPRequest} instance. The <code>request</code> parameter is
083 * ignored.
084 *
085 * @param endpoint
086 * @param exchange
087 * @param request
088 * ignored.
089 * @return a newly created {@link HTTPRequest} instance containing data from
090 * <code>exchange</code>.
091 */
092 public HTTPRequest writeRequest(GHttpEndpoint endpoint, Exchange exchange, HTTPRequest request) throws Exception {
093 HTTPRequest answer = new HTTPRequest(
094 getRequestUrl(endpoint, exchange),
095 getRequestMethod(endpoint, exchange));
096 writeRequestHeaders(endpoint, exchange, answer);
097 writeRequestBody(endpoint, exchange, answer);
098 return answer;
099 }
100
101 // ----------------------------------------------------------------
102 // Inbound binding
103 // ----------------------------------------------------------------
104
105 public Exchange readRequest(GHttpEndpoint endpoint, Exchange exchange, HttpServletRequest request) {
106 readRequestHeaders(endpoint, exchange, request);
107 return exchange;
108 }
109
110 public HttpServletResponse writeResponse(GHttpEndpoint endpoint, Exchange exchange, HttpServletResponse response) {
111 return response;
112 }
113
114 // ----------------------------------------------------------------
115 // Customization points
116 // ----------------------------------------------------------------
117
118 protected void readResponseHeaders(GHttpEndpoint endpoint, Exchange exchange, HTTPResponse response) {
119 HeaderFilterStrategy strategy = endpoint.getHeaderFilterStrategy();
120
121 Message in = exchange.getIn();
122 Message out = exchange.getOut();
123
124 out.setHeaders(in.getHeaders());
125 out.setHeader(Exchange.HTTP_RESPONSE_CODE, response.getResponseCode());
126
127 String contentType = getResponseHeader("Content-Type", response);
128 if (contentType != null) {
129 out.setHeader(Exchange.CONTENT_TYPE, contentType);
130 }
131
132 for (HTTPHeader header : response.getHeaders()) {
133 String name = header.getName();
134 String value = header.getValue();
135 if (strategy != null && !strategy.applyFilterToExternalHeaders(name, value, exchange)) {
136 out.setHeader(name, value);
137 }
138 }
139 }
140
141 protected void readRequestHeaders(GHttpEndpoint endpoint, Exchange exchange, HttpServletRequest request) {
142 // EXPERIMENTAL // TODO: resolve gzip encoding issues
143 exchange.getIn().removeHeader("Accept-Encoding");
144 exchange.getIn().removeHeader("Content-Encoding");
145 }
146
147 protected void writeRequestHeaders(GHttpEndpoint endpoint, Exchange exchange, HTTPRequest request) {
148 HeaderFilterStrategy strategy = endpoint.getHeaderFilterStrategy();
149 for (String headerName : exchange.getIn().getHeaders().keySet()) {
150 String headerValue = exchange.getIn().getHeader(headerName, String.class);
151 if (strategy != null && !strategy.applyFilterToCamelHeaders(headerName, headerValue, exchange)) {
152 request.addHeader(new HTTPHeader(headerName, headerValue));
153 }
154 }
155 }
156
157 protected void readResponseBody(GHttpEndpoint endpoint, Exchange exchange, HTTPResponse response) throws Exception {
158 byte[] content = response.getContent();
159 if (content != null) {
160 InputStream stream = new ByteArrayInputStream(content);
161 if (isGzip(getResponseHeader("Content-Encoding", response))) {
162 stream = new GZIPInputStream(stream);
163 }
164 exchange.getOut().setBody(stream);
165 }
166 }
167
168 protected void writeRequestBody(GHttpEndpoint endpoint, Exchange exchange, HTTPRequest request) {
169 request.setPayload(exchange.getIn().getBody(byte[].class));
170 }
171
172 protected URL getRequestUrl(GHttpEndpoint endpoint, Exchange exchange) throws Exception {
173 String uri = exchange.getIn().getHeader(Exchange.HTTP_URI, String.class);
174 String query = exchange.getIn().getHeader(Exchange.HTTP_QUERY, String.class);
175 if (uri != null && !endpoint.isBridgeEndpoint()) {
176 return getEndpointUrl(UnsafeUriCharactersEncoder.encode(uri), query);
177 }
178 return getEndpointUrl(endpoint.getEndpointUri(), query);
179 }
180
181 protected HTTPMethod getRequestMethod(GHttpEndpoint endpoint, Exchange exchange) {
182 String method = (String)exchange.getIn().getHeader(Exchange.HTTP_METHOD);
183 if (method != null) {
184 return HTTPMethod.valueOf(method);
185 } else if (exchange.getIn().getBody() != null) {
186 return HTTPMethod.POST;
187 } else {
188 return HTTPMethod.GET;
189 }
190 }
191
192 protected String getResponseHeader(String name, HTTPResponse response) {
193 for (HTTPHeader header : response.getHeaders()) {
194 if (header.getName().equalsIgnoreCase(name)) {
195 return header.getValue();
196 }
197 }
198 return null;
199 }
200
201 }