1 /** 2 * Copyright (c) 2003,2004, Stefan Haustein, Oberhausen, Rhld., Germany 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a copy 5 * of this software and associated documentation files (the "Software"), to deal 6 * in the Software without restriction, including without limitation the rights 7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or 8 * sell copies of the Software, and to permit persons to whom the Software is 9 * furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice shall be included in 12 * all copies or substantial portions of the Software. 13 * 14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 * IN THE SOFTWARE. 21 * 22 * Contributor(s): John D. Beatty, Dave Dash, F. Hunter, Alexander Krebs, 23 * Lars Mehrmann, Sean McDaniel, Thomas Strang, Renaud Tognelli 24 * */ 25 26 package org.ksoap2.transport; 27 28 import java.util.List; 29 import java.util.zip.GZIPInputStream; 30 import java.io.*; 31 import java.net.MalformedURLException; 32 import java.net.Proxy; 33 import java.net.URL; 34 35 import org.ksoap2.*; 36 import org.ksoap2.serialization.SoapSerializationEnvelope; 37 import org.xmlpull.v1.*; 38 39 /** 40 * A J2SE based HttpTransport layer. 41 */ 42 public class HttpTransportSE extends Transport { 43 44 private ServiceConnection serviceConnection; 45 46 /** 47 * Creates instance of HttpTransportSE with set url 48 * 49 * @param url 50 * the destination to POST SOAP data 51 */ 52 public HttpTransportSE(String url) { 53 super(null, url); 54 } 55 56 /** 57 * Creates instance of HttpTransportSE with set url and defines a 58 * proxy server to use to access it 59 * 60 * @param proxy 61 * Proxy information or <code>null</code> for direct access 62 * @param url 63 * The destination to POST SOAP data 64 */ 65 public HttpTransportSE(Proxy proxy, String url) { 66 super(proxy, url); 67 } 68 69 /** 70 * Creates instance of HttpTransportSE with set url 71 * 72 * @param url 73 * the destination to POST SOAP data 74 * @param timeout 75 * timeout for connection and Read Timeouts (milliseconds) 76 */ 77 public HttpTransportSE(String url, int timeout) { 78 super(url, timeout); 79 } 80 81 public HttpTransportSE(Proxy proxy, String url, int timeout) { 82 super(proxy, url, timeout); 83 } 84 85 /** 86 * Creates instance of HttpTransportSE with set url 87 * 88 * @param url 89 * the destination to POST SOAP data 90 * @param timeout 91 * timeout for connection and Read Timeouts (milliseconds) 92 * @param contentLength 93 * Content Lenght in bytes if known in advance 94 */ 95 public HttpTransportSE(String url, int timeout, int contentLength) { 96 super(url, timeout); 97 } 98 99 public HttpTransportSE(Proxy proxy, String url, int timeout, int contentLength) { 100 super(proxy, url, timeout); 101 } 102 103 /** 104 * set the desired soapAction header field 105 * 106 * @param soapAction 107 * the desired soapAction 108 * @param envelope 109 * the envelope containing the information for the soap call. 110 * @throws IOException 111 * @throws XmlPullParserException 112 */ 113 public void call(String soapAction, SoapEnvelope envelope) throws IOException, 114 XmlPullParserException { 115 116 call(soapAction, envelope, null); 117 } 118 119 /** 120 * 121 * set the desired soapAction header field 122 * 123 * @param soapAction 124 * the desired soapAction 125 * @param envelope 126 * the envelope containing the information for the soap call. 127 * @param headers 128 * a list of HeaderProperties to be http header properties when establishing the connection 129 * 130 * @return <code>CookieJar</code> with any cookies sent by the server 131 * @throws IOException 132 * @throws XmlPullParserException 133 */ 134 public List call(String soapAction, SoapEnvelope envelope, List headers) 135 throws IOException, XmlPullParserException { 136 137 if (soapAction == null) { 138 soapAction = "\"\""; 139 } 140 141 System.out.println("call action:" + soapAction); 142 byte[] requestData = createRequestData(envelope, "UTF-8"); 143 144 if (requestData != null) { 145 requestDump = debug ? new String(requestData) : null; 146 } 147 else { 148 requestDump = null; 149 } 150 responseDump = null; 151 152 System.out.println("requestDump:" + requestDump); 153 ServiceConnection connection = getServiceConnection(); 154 System.out.println("connection:" + connection); 155 156 connection.setRequestProperty("User-Agent", USER_AGENT); 157 // SOAPAction is not a valid header for VER12 so do not add 158 // it 159 // @see "http://code.google.com/p/ksoap2-android/issues/detail?id=67 160 System.out.println("envelope:" + envelope); 161 if (envelope != null) { 162 if (envelope.version != SoapSerializationEnvelope.VER12) { 163 connection.setRequestProperty("SOAPAction", soapAction); 164 } 165 166 if (envelope.version == SoapSerializationEnvelope.VER12) { 167 connection.setRequestProperty("Content-Type", CONTENT_TYPE_SOAP_XML_CHARSET_UTF_8); 168 } else { 169 connection.setRequestProperty("Content-Type", CONTENT_TYPE_XML_CHARSET_UTF_8); 170 } 171 172 connection.setRequestProperty("Connection", "close"); 173 connection.setRequestProperty("Accept-Encoding", "gzip"); 174 connection.setRequestProperty("Content-Length", "" + requestData.length); 175 176 //M: Retry for HTTP Authentication 177 //connection.setFixedLengthStreamingMode(requestData.length); 178 179 // Pass the headers provided by the user along with the call 180 if (headers != null) { 181 for (int i = 0; i < headers.size(); i++) { 182 HeaderProperty hp = (HeaderProperty) headers.get(i); 183 connection.setRequestProperty(hp.getKey(), hp.getValue()); 184 } 185 } 186 187 connection.setRequestMethod("POST"); 188 189 } 190 else { 191 connection.setRequestProperty("Connection", "close"); 192 connection.setRequestProperty("Accept-Encoding", "gzip"); 193 connection.setRequestMethod("GET"); 194 } 195 196 if (requestData != null) { 197 OutputStream os = connection.openOutputStream(); 198 199 os.write(requestData, 0, requestData.length); 200 os.flush(); 201 os.close(); 202 requestData = null; 203 } 204 InputStream is; 205 List retHeaders = null; 206 boolean gZippedContent = false; 207 boolean bcaCert = false; 208 209 try { 210 retHeaders = connection.getResponseProperties(); 211 System.out.println("[HttpTransportSE] retHeaders = " + retHeaders); 212 for (int i = 0; i < retHeaders.size(); i++) { 213 HeaderProperty hp = (HeaderProperty) retHeaders.get(i); 214 // HTTP response code has null key 215 if (null == hp.getKey()) { 216 continue; 217 } 218 // ignoring case since users found that all smaller case is used on some server 219 // and even if it is wrong according to spec, we rather have it work.. 220 if (hp.getKey().equalsIgnoreCase("Content-Encoding") 221 && hp.getValue().equalsIgnoreCase("gzip")) { 222 gZippedContent = true; 223 } 224 } 225 if (gZippedContent) { 226 is = getUnZippedInputStream(connection.openInputStream()); 227 } else { 228 is = connection.openInputStream(); 229 } 230 } catch (IOException e) { 231 if (gZippedContent) { 232 is = getUnZippedInputStream(connection.getErrorStream()); 233 } else { 234 is = connection.getErrorStream(); 235 } 236 237 if (is == null) { 238 connection.disconnect(); 239 throw (e); 240 } 241 } 242 243 if (debug) { 244 ByteArrayOutputStream bos = new ByteArrayOutputStream(); 245 byte[] buf = new byte[8192]; 246 247 while (true) { 248 int rd = is.read(buf, 0, 8192); 249 if (rd == -1) { 250 break; 251 } 252 bos.write(buf, 0, rd); 253 } 254 255 bos.flush(); 256 buf = bos.toByteArray(); 257 258 responseDump = new String(buf); 259 260 System.out.println("responseDump:" + responseDump); 261 is.close(); 262 is = new ByteArrayInputStream(buf); 263 } 264 265 if (envelope != null) { 266 parseResponse(envelope, is); 267 } 268 269 return retHeaders; 270 } 271 272 private InputStream getUnZippedInputStream(InputStream inputStream) throws IOException { 273 /* workaround for Android 2.3 274 (see http://stackoverflow.com/questions/5131016/) 275 */ 276 try { 277 return (GZIPInputStream) inputStream; 278 } catch (ClassCastException e) { 279 return new GZIPInputStream(inputStream); 280 } 281 } 282 283 public ServiceConnection getServiceConnection() throws IOException { 284 if (serviceConnection == null) { 285 System.out.println("new ServiceConnectionSE:" + proxy + " " + url + " " + timeout); 286 serviceConnection = new ServiceConnectionSE(proxy, url, timeout); 287 } 288 return serviceConnection; 289 } 290 291 public String getHost() { 292 293 String retVal = null; 294 295 try { 296 retVal = new URL(url).getHost(); 297 } catch (MalformedURLException e) { 298 e.printStackTrace(); 299 } 300 301 return retVal; 302 } 303 304 public int getPort() { 305 306 int retVal = -1; 307 308 try { 309 retVal = new URL(url).getPort(); 310 } catch (MalformedURLException e) { 311 e.printStackTrace(); 312 } 313 314 return retVal; 315 } 316 317 public String getPath() { 318 319 String retVal = null; 320 321 try { 322 retVal = new URL(url).getPath(); 323 } catch (MalformedURLException e) { 324 e.printStackTrace(); 325 } 326 327 return retVal; 328 } 329 330 public String getQuery() { 331 332 String retVal = null; 333 334 try { 335 retVal = new URL(url).getQuery(); 336 } catch (MalformedURLException e) { 337 e.printStackTrace(); 338 } 339 340 return retVal; 341 } 342 343 /** 344 * @hide 345 */ 346 public byte[] getRequestData(SoapEnvelope envelope, String encoding) { 347 try { 348 return createRequestData(envelope, encoding); 349 } catch (Exception e) { 350 e.printStackTrace(); 351 } 352 353 return null; 354 } 355 } 356