1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19
20
21 package org.apache.axis2.transport.http;
22
23 import org.apache.axiom.om.OMElement;
24 import org.apache.axiom.om.OMException;
25 import org.apache.axiom.om.OMNamespace;
26 import org.apache.axiom.soap.SOAP11Constants;
27 import org.apache.axiom.soap.SOAP12Constants;
28 import org.apache.axiom.soap.SOAPEnvelope;
29 import org.apache.axiom.soap.SOAPFactory;
30 import org.apache.axiom.soap.SOAPProcessingException;
31 import org.apache.axiom.soap.impl.llom.soap11.SOAP11Factory;
32 import org.apache.axiom.soap.impl.llom.soap12.SOAP12Factory;
33 import org.apache.axis2.AxisFault;
34 import org.apache.axis2.Constants;
35 import org.apache.axis2.addressing.EndpointReference;
36 import org.apache.axis2.builder.BuilderUtil;
37 import org.apache.axis2.context.ConfigurationContext;
38 import org.apache.axis2.context.MessageContext;
39 import org.apache.axis2.context.OperationContext;
40 import org.apache.axis2.description.AxisService;
41 import org.apache.axis2.description.Parameter;
42 import org.apache.axis2.engine.AxisEngine;
43 import org.apache.axis2.engine.Handler.InvocationResponse;
44 import org.apache.axis2.transport.TransportUtils;
45 import org.apache.axis2.util.JavaUtils;
46 import org.apache.axis2.util.Utils;
47
48 import javax.xml.parsers.FactoryConfigurationError;
49 import javax.xml.stream.XMLStreamException;
50 import java.io.IOException;
51 import java.io.InputStream;
52 import java.io.OutputStream;
53 import java.util.Iterator;
54 import java.util.Map;
55 import java.util.zip.GZIPInputStream;
56
57 public class HTTPTransportUtils {
58
59
60 /**
61 * @deprecated This was used only by the now deprecated processHTTPGetRequest() method.
62 */
63 public static SOAPEnvelope createEnvelopeFromGetRequest(String requestUrl,
64 Map map, ConfigurationContext configCtx)
65 throws AxisFault {
66 String[] values =
67 Utils.parseRequestURLForServiceAndOperation(requestUrl,
68 configCtx.getServiceContextPath());
69 if (values == null) {
70 return new SOAP11Factory().getDefaultEnvelope();
71 }
72
73 if ((values[1] != null) && (values[0] != null)) {
74 String srvice = values[0];
75 AxisService service = configCtx.getAxisConfiguration().getService(srvice);
76 if (service == null) {
77 throw new AxisFault("service not found: " + srvice);
78 }
79 String operation = values[1];
80 SOAPFactory soapFactory = new SOAP11Factory();
81 SOAPEnvelope envelope = soapFactory.getDefaultEnvelope();
82 OMNamespace omNs = soapFactory.createOMNamespace(service.getSchemaTargetNamespace(),
83 service.getSchemaTargetNamespacePrefix());
84 soapFactory.createOMNamespace(service.getSchemaTargetNamespace(),
85 service.getSchemaTargetNamespacePrefix());
86 OMElement opElement = soapFactory.createOMElement(operation, omNs);
87 Iterator it = map.keySet().iterator();
88
89 while (it.hasNext()) {
90 String name = (String) it.next();
91 String value = (String) map.get(name);
92 OMElement omEle = soapFactory.createOMElement(name, omNs);
93
94 omEle.setText(value);
95 opElement.addChild(omEle);
96 }
97
98 envelope.getBody().addChild(opElement);
99
100 return envelope;
101 } else {
102 return null;
103 }
104 }
105
106 /**
107 * <p>
108 * Checks whether MTOM needs to be enabled for the message represented by
109 * the msgContext. We check value assigned to the "enableMTOM" property
110 * either using the config files (axis2.xml, services.xml) or
111 * programatically. Programatic configuration is given priority. If the
112 * given value is "optional", MTOM will be enabled only if the incoming
113 * message was an MTOM message.
114 * </p>
115 *
116 * @param msgContext
117 * @return true if SwA needs to be enabled
118 */
119 public static boolean doWriteMTOM(MessageContext msgContext) {
120 boolean enableMTOM;
121 Object enableMTOMObject = null;
122 // First check the whether MTOM is enabled by the configuration
123 // (Eg:Axis2.xml, services.xml)
124 Parameter parameter = msgContext.getParameter(Constants.Configuration.ENABLE_MTOM);
125 if (parameter != null) {
126 enableMTOMObject = parameter.getValue();
127 }
128 // Check whether the configuration is overridden programatically..
129 // Priority given to programatically setting of the value
130 Object property = msgContext.getProperty(Constants.Configuration.ENABLE_MTOM);
131 if (property != null) {
132 enableMTOMObject = property;
133 }
134 enableMTOM = JavaUtils.isTrueExplicitly(enableMTOMObject);
135 // Handle the optional value for enableMTOM
136 // If the value for 'enableMTOM' is given as optional and if the request
137 // message was a MTOM message we sent out MTOM
138 if (!enableMTOM && msgContext.isDoingMTOM() && (enableMTOMObject instanceof String)) {
139 if (((String) enableMTOMObject).equalsIgnoreCase(Constants.VALUE_OPTIONAL)) {
140 enableMTOM = true;
141 }
142 }
143 return enableMTOM;
144 }
145
146 /**
147 * <p>
148 * Checks whether SOAP With Attachments (SwA) needs to be enabled for the
149 * message represented by the msgContext. We check value assigned to the
150 * "enableSwA" property either using the config files (axis2.xml,
151 * services.xml) or programatically. Programatic configuration is given
152 * priority. If the given value is "optional", SwA will be enabled only if
153 * the incoming message was SwA type.
154 * </p>
155 *
156 * @param msgContext
157 * @return true if SwA needs to be enabled
158 */
159 public static boolean doWriteSwA(MessageContext msgContext) {
160 boolean enableSwA;
161 Object enableSwAObject = null;
162 // First check the whether SwA is enabled by the configuration
163 // (Eg:Axis2.xml, services.xml)
164 Parameter parameter = msgContext.getParameter(Constants.Configuration.ENABLE_SWA);
165 if (parameter != null) {
166 enableSwAObject = parameter.getValue();
167 }
168 // Check whether the configuration is overridden programatically..
169 // Priority given to programatically setting of the value
170 Object property = msgContext.getProperty(Constants.Configuration.ENABLE_SWA);
171 if (property != null) {
172 enableSwAObject = property;
173 }
174 enableSwA = JavaUtils.isTrueExplicitly(enableSwAObject);
175 // Handle the optional value for enableSwA
176 // If the value for 'enableSwA' is given as optional and if the request
177 // message was a SwA message we sent out SwA
178 if (!enableSwA && msgContext.isDoingSwA() && (enableSwAObject instanceof String)) {
179 if (((String) enableSwAObject).equalsIgnoreCase(Constants.VALUE_OPTIONAL)) {
180 enableSwA = true;
181 }
182 }
183 return enableSwA;
184 }
185
186 /**
187 * Utility method to query CharSetEncoding. First look in the
188 * MessageContext. If it's not there look in the OpContext. Use the defualt,
189 * if it's not given in either contexts.
190 *
191 * @param msgContext
192 * @return CharSetEncoding
193 */
194 public static String getCharSetEncoding(MessageContext msgContext) {
195 String charSetEnc = (String) msgContext
196 .getProperty(Constants.Configuration.CHARACTER_SET_ENCODING);
197
198 if (charSetEnc == null) {
199 OperationContext opctx = msgContext.getOperationContext();
200 if (opctx != null) {
201 charSetEnc = (String) opctx
202 .getProperty(Constants.Configuration.CHARACTER_SET_ENCODING);
203 }
204 /**
205 * If the char set enc is still not found use the default
206 */
207 if (charSetEnc == null) {
208 charSetEnc = MessageContext.DEFAULT_CHAR_SET_ENCODING;
209 }
210 }
211 return charSetEnc;
212 }
213
214 /**
215 * @param msgContext - The MessageContext of the Request Message
216 * @param out - The output stream of the response
217 * @param soapAction - SoapAction of the request
218 * @param requestURI - The URL that the request came to
219 * @param configurationContext - The Axis Configuration Context
220 * @param requestParameters - The parameters of the request message
221 * @return - boolean indication whether the operation was succesfull
222 * @throws AxisFault - Thrown in case a fault occurs
223 * @deprecated use RESTUtil.processURLRequest(MessageContext msgContext, OutputStream out, String contentType) instead
224 */
225
226 public static boolean processHTTPGetRequest(MessageContext msgContext,
227 OutputStream out, String soapAction,
228 String requestURI,
229 ConfigurationContext configurationContext,
230 Map requestParameters)
231 throws AxisFault {
232 if ((soapAction != null) && soapAction.startsWith("\"") && soapAction.endsWith("\"")) {
233 soapAction = soapAction.substring(1, soapAction.length() - 1);
234 }
235
236 msgContext.setSoapAction(soapAction);
237 msgContext.setTo(new EndpointReference(requestURI));
238 msgContext.setProperty(MessageContext.TRANSPORT_OUT, out);
239 msgContext.setServerSide(true);
240 SOAPEnvelope envelope = HTTPTransportUtils.createEnvelopeFromGetRequest(requestURI,
241 requestParameters,
242 configurationContext);
243
244 if (envelope == null) {
245 return false;
246 } else {
247 msgContext.setDoingREST(true);
248 msgContext.setEnvelope(envelope);
249 AxisEngine.receive(msgContext);
250 return true;
251 }
252 }
253
254 private static final int VERSION_UNKNOWN = 0;
255 private static final int VERSION_SOAP11 = 1;
256 private static final int VERSION_SOAP12 = 2;
257
258 public static InvocationResponse processHTTPPostRequest(MessageContext msgContext,
259 InputStream in,
260 OutputStream out,
261 String contentType,
262 String soapActionHeader,
263 String requestURI)
264 throws AxisFault {
265 int soapVersion = VERSION_UNKNOWN;
266 try {
267 soapVersion = initializeMessageContext(msgContext, soapActionHeader, requestURI, contentType);
268 msgContext.setProperty(MessageContext.TRANSPORT_OUT, out);
269
270 msgContext.setEnvelope(
271 TransportUtils.createSOAPMessage(
272 msgContext,
273 handleGZip(msgContext, in),
274 contentType));
275 return AxisEngine.receive(msgContext);
276 } catch (SOAPProcessingException e) {
277 throw AxisFault.makeFault(e);
278 } catch (AxisFault e) {
279 throw e;
280 } catch (IOException e) {
281 throw AxisFault.makeFault(e);
282 } catch (OMException e) {
283 throw AxisFault.makeFault(e);
284 } catch (XMLStreamException e) {
285 throw AxisFault.makeFault(e);
286 } catch (FactoryConfigurationError e) {
287 throw AxisFault.makeFault(e);
288 } finally {
289 if ((msgContext.getEnvelope() == null) && soapVersion != VERSION_SOAP11) {
290 msgContext.setEnvelope(new SOAP12Factory().getDefaultEnvelope());
291 }
292 }
293 }
294
295 public static int initializeMessageContext(MessageContext msgContext,
296 String soapActionHeader,
297 String requestURI,
298 String contentType) {
299 int soapVersion = VERSION_UNKNOWN;
300 // remove the starting and trailing " from the SOAP Action
301 if ((soapActionHeader != null)
302 && soapActionHeader.length() > 0
303 && soapActionHeader.charAt(0) == '\"'
304 && soapActionHeader.endsWith("\"")) {
305 soapActionHeader = soapActionHeader.substring(1, soapActionHeader.length() - 1);
306 }
307
308 // fill up the Message Contexts
309 msgContext.setSoapAction(soapActionHeader);
310 msgContext.setTo(new EndpointReference(requestURI));
311 msgContext.setServerSide(true);
312
313 // get the type of char encoding
314 String charSetEnc = BuilderUtil.getCharSetEncoding(contentType);
315 if (charSetEnc == null) {
316 charSetEnc = MessageContext.DEFAULT_CHAR_SET_ENCODING;
317 }
318 msgContext.setProperty(Constants.Configuration.CHARACTER_SET_ENCODING, charSetEnc);
319
320 if (contentType != null) {
321 if (contentType.indexOf(SOAP12Constants.SOAP_12_CONTENT_TYPE) > -1) {
322 soapVersion = VERSION_SOAP12;
323 TransportUtils.processContentTypeForAction(contentType, msgContext);
324 } else if (contentType
325 .indexOf(SOAP11Constants.SOAP_11_CONTENT_TYPE) > -1) {
326 soapVersion = VERSION_SOAP11;
327 } else if (isRESTRequest(contentType)) {
328 // If REST, construct a SOAP11 envelope to hold the rest message and
329 // indicate that this is a REST message.
330 soapVersion = VERSION_SOAP11;
331 msgContext.setDoingREST(true);
332 }
333 if (soapVersion == VERSION_SOAP11) {
334 // TODO Keith : Do we need this anymore
335 // Deployment configuration parameter
336 Parameter enableREST = msgContext
337 .getParameter(Constants.Configuration.ENABLE_REST);
338 if ((soapActionHeader == null) && (enableREST != null)) {
339 if (Constants.VALUE_TRUE.equals(enableREST.getValue())) {
340 // If the content Type is text/xml (BTW which is the
341 // SOAP 1.1 Content type ) and the SOAP Action is
342 // absent it is rest !!
343 msgContext.setDoingREST(true);
344 }
345 }
346 }
347 }
348 return soapVersion;
349 }
350
351 public static InputStream handleGZip(MessageContext msgContext, InputStream in)
352 throws IOException {
353 Map headers = (Map) msgContext.getProperty(MessageContext.TRANSPORT_HEADERS);
354
355 if (headers != null) {
356 if (HTTPConstants.COMPRESSION_GZIP
357 .equals(headers.get(HTTPConstants.HEADER_CONTENT_ENCODING)) ||
358 HTTPConstants.COMPRESSION_GZIP.equals(headers.get(
359 HTTPConstants.HEADER_CONTENT_ENCODING_LOWERCASE))) {
360 in = new GZIPInputStream(in);
361 }
362 }
363 return in;
364 }
365
366 public static boolean isDoingREST(MessageContext msgContext) {
367 boolean enableREST = false;
368
369 // check whether isDoingRest is already true in the message context
370 if (msgContext.isDoingREST()) {
371 return true;
372 }
373
374 Object enableRESTProperty = msgContext.getProperty(Constants.Configuration.ENABLE_REST);
375 if (enableRESTProperty != null) {
376 enableREST = JavaUtils.isTrueExplicitly(enableRESTProperty);
377 }
378
379 msgContext.setDoingREST(enableREST);
380
381 return enableREST;
382 }
383
384 /**
385 * This will match for content types that will be regarded as REST in WSDL2.0.
386 * This contains,
387 * 1. application/xml
388 * 2. application/x-www-form-urlencoded
389 * 3. multipart/form-data
390 * <p/>
391 * If the request doesnot contain a content type; this will return true.
392 *
393 * @param contentType
394 * @return Boolean
395 */
396 public static boolean isRESTRequest(String contentType) {
397 if (contentType == null) {
398 return false;
399 }
400 return (contentType.indexOf(HTTPConstants.MEDIA_TYPE_APPLICATION_XML) > -1 ||
401 contentType.indexOf(HTTPConstants.MEDIA_TYPE_X_WWW_FORM) > -1 ||
402 contentType.indexOf(HTTPConstants.MEDIA_TYPE_MULTIPART_FORM_DATA) > -1);
403 }
404 }