Thu, 31 Aug 2017 15:18:52 +0800
merge
1 /*
2 * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
26 package com.sun.xml.internal.messaging.saaj.client.p2p;
28 import java.io.*;
29 import java.lang.reflect.Method;
30 import java.net.*;
31 import java.security.*;
32 import java.util.Iterator;
33 import java.util.StringTokenizer;
34 import java.util.logging.Level;
35 import java.util.logging.Logger;
37 import javax.xml.soap.*;
39 import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl;
40 import com.sun.xml.internal.messaging.saaj.util.*;
42 /**
43 * This represents a "connection" to the simple HTTP-based provider.
44 *
45 * @author Anil Vijendran (akv@eng.sun.com)
46 * @author Rajiv Mordani (rajiv.mordani@sun.com)
47 * @author Manveen Kaur (manveen.kaur@sun.com)
48 *
49 */
50 class HttpSOAPConnection extends SOAPConnection {
52 public static final String vmVendor = SAAJUtil.getSystemProperty("java.vendor.url");
53 private static final String sunVmVendor = "http://java.sun.com/";
54 private static final String ibmVmVendor = "http://www.ibm.com/";
55 private static final boolean isSunVM = sunVmVendor.equals(vmVendor) ? true: false;
56 private static final boolean isIBMVM = ibmVmVendor.equals(vmVendor) ? true : false;
57 private static final String JAXM_URLENDPOINT="javax.xml.messaging.URLEndpoint";
59 protected static final Logger log =
60 Logger.getLogger(LogDomainConstants.HTTP_CONN_DOMAIN,
61 "com.sun.xml.internal.messaging.saaj.client.p2p.LocalStrings");
64 MessageFactory messageFactory = null;
66 boolean closed = false;
68 public HttpSOAPConnection() throws SOAPException {
70 try {
71 messageFactory = MessageFactory.newInstance(SOAPConstants.DYNAMIC_SOAP_PROTOCOL);
72 } catch (NoSuchMethodError ex) {
73 //fallback to default SOAP 1.1 in this case for backward compatibility
74 messageFactory = MessageFactory.newInstance();
75 } catch (Exception ex) {
76 log.log(Level.SEVERE, "SAAJ0001.p2p.cannot.create.msg.factory", ex);
77 throw new SOAPExceptionImpl("Unable to create message factory", ex);
78 }
79 }
81 public void close() throws SOAPException {
82 if (closed) {
83 log.severe("SAAJ0002.p2p.close.already.closed.conn");
84 throw new SOAPExceptionImpl("Connection already closed");
85 }
87 messageFactory = null;
88 closed = true;
89 }
91 public SOAPMessage call(SOAPMessage message, Object endPoint)
92 throws SOAPException {
93 if (closed) {
94 log.severe("SAAJ0003.p2p.call.already.closed.conn");
95 throw new SOAPExceptionImpl("Connection is closed");
96 }
98 Class urlEndpointClass = null;
99 ClassLoader loader = Thread.currentThread().getContextClassLoader();
100 try {
101 if (loader != null) {
102 urlEndpointClass = loader.loadClass(JAXM_URLENDPOINT);
103 } else {
104 urlEndpointClass = Class.forName(JAXM_URLENDPOINT);
105 }
106 } catch (ClassNotFoundException ex) {
107 //Do nothing. URLEndpoint is available only when JAXM is there.
108 if (log.isLoggable(Level.FINEST))
109 log.finest("SAAJ0090.p2p.endpoint.available.only.for.JAXM");
110 }
112 if (urlEndpointClass != null) {
113 if (urlEndpointClass.isInstance(endPoint)) {
114 String url = null;
116 try {
117 Method m = urlEndpointClass.getMethod("getURL", (Class[])null);
118 url = (String) m.invoke(endPoint, (Object[])null);
119 } catch (Exception ex) {
120 // TBD -- exception chaining
121 log.log(Level.SEVERE,"SAAJ0004.p2p.internal.err",ex);
122 throw new SOAPExceptionImpl(
123 "Internal error: " + ex.getMessage());
124 }
125 try {
126 endPoint = new URL(url);
127 } catch (MalformedURLException mex) {
128 log.log(Level.SEVERE,"SAAJ0005.p2p.", mex);
129 throw new SOAPExceptionImpl("Bad URL: " + mex.getMessage());
130 }
131 }
132 }
134 if (endPoint instanceof java.lang.String) {
135 try {
136 endPoint = new URL((String) endPoint);
137 } catch (MalformedURLException mex) {
138 log.log(Level.SEVERE, "SAAJ0006.p2p.bad.URL", mex);
139 throw new SOAPExceptionImpl("Bad URL: " + mex.getMessage());
140 }
141 }
143 if (endPoint instanceof URL)
144 try {
145 SOAPMessage response = post(message, (URL)endPoint);
146 return response;
147 } catch (Exception ex) {
148 // TBD -- chaining?
149 throw new SOAPExceptionImpl(ex);
150 } else {
151 log.severe("SAAJ0007.p2p.bad.endPoint.type");
152 throw new SOAPExceptionImpl("Bad endPoint type " + endPoint);
153 }
154 }
156 SOAPMessage post(SOAPMessage message, URL endPoint) throws SOAPException, IOException {
157 boolean isFailure = false;
159 URL url = null;
160 HttpURLConnection httpConnection = null;
162 int responseCode = 0;
163 try {
164 if (endPoint.getProtocol().equals("https"))
165 //if(!setHttps)
166 initHttps();
167 // Process the URL
168 URI uri = new URI(endPoint.toString());
169 String userInfo = uri.getRawUserInfo();
171 url = endPoint;
173 if (dL > 0)
174 d("uri: " + userInfo + " " + url + " " + uri);
176 // TBD
177 // Will deal with https later.
178 if (!url.getProtocol().equalsIgnoreCase("http")
179 && !url.getProtocol().equalsIgnoreCase("https")) {
180 log.severe("SAAJ0052.p2p.protocol.mustbe.http.or.https");
181 throw new IllegalArgumentException(
182 "Protocol "
183 + url.getProtocol()
184 + " not supported in URL "
185 + url);
186 }
187 httpConnection = (HttpURLConnection) createConnection(url);
189 httpConnection.setRequestMethod("POST");
191 httpConnection.setDoOutput(true);
192 httpConnection.setDoInput(true);
193 httpConnection.setUseCaches(false);
194 httpConnection.setInstanceFollowRedirects(true);
196 if (message.saveRequired())
197 message.saveChanges();
199 MimeHeaders headers = message.getMimeHeaders();
201 Iterator it = headers.getAllHeaders();
202 boolean hasAuth = false; // true if we find explicit Auth header
203 while (it.hasNext()) {
204 MimeHeader header = (MimeHeader) it.next();
206 String[] values = headers.getHeader(header.getName());
207 if (values.length == 1)
208 httpConnection.setRequestProperty(
209 header.getName(),
210 header.getValue());
211 else {
212 StringBuffer concat = new StringBuffer();
213 int i = 0;
214 while (i < values.length) {
215 if (i != 0)
216 concat.append(',');
217 concat.append(values[i]);
218 i++;
219 }
221 httpConnection.setRequestProperty(
222 header.getName(),
223 concat.toString());
224 }
226 if ("Authorization".equals(header.getName())) {
227 hasAuth = true;
228 if (log.isLoggable(Level.FINE))
229 log.fine("SAAJ0091.p2p.https.auth.in.POST.true");
230 }
231 }
233 if (!hasAuth && userInfo != null) {
234 initAuthUserInfo(httpConnection, userInfo);
235 }
237 OutputStream out = httpConnection.getOutputStream();
238 try {
239 message.writeTo(out);
240 out.flush();
241 } finally {
242 out.close();
243 }
245 httpConnection.connect();
247 try {
249 responseCode = httpConnection.getResponseCode();
251 // let HTTP_INTERNAL_ERROR (500) through because it is used for SOAP faults
252 if (responseCode == HttpURLConnection.HTTP_INTERNAL_ERROR) {
253 isFailure = true;
254 }
255 //else if (responseCode != HttpURLConnection.HTTP_OK)
256 //else if (!(responseCode >= HttpURLConnection.HTTP_OK && responseCode < 207))
257 else if ((responseCode / 100) != 2) {
258 log.log(Level.SEVERE,
259 "SAAJ0008.p2p.bad.response",
260 new String[] {httpConnection.getResponseMessage()});
261 throw new SOAPExceptionImpl(
262 "Bad response: ("
263 + responseCode
264 + httpConnection.getResponseMessage());
266 }
267 } catch (IOException e) {
268 // on JDK1.3.1_01, we end up here, but then getResponseCode() succeeds!
269 responseCode = httpConnection.getResponseCode();
270 if (responseCode == HttpURLConnection.HTTP_INTERNAL_ERROR) {
271 isFailure = true;
272 } else {
273 throw e;
274 }
276 }
278 } catch (SOAPException ex) {
279 throw ex;
280 } catch (Exception ex) {
281 log.severe("SAAJ0009.p2p.msg.send.failed");
282 throw new SOAPExceptionImpl("Message send failed", ex);
283 }
285 SOAPMessage response = null;
286 InputStream httpIn = null;
287 if (responseCode == HttpURLConnection.HTTP_OK || isFailure) {
288 try {
289 MimeHeaders headers = new MimeHeaders();
291 String key, value;
293 // Header field 0 is the status line so we skip it.
295 int i = 1;
297 while (true) {
298 key = httpConnection.getHeaderFieldKey(i);
299 value = httpConnection.getHeaderField(i);
301 if (key == null && value == null)
302 break;
304 if (key != null) {
305 StringTokenizer values =
306 new StringTokenizer(value, ",");
307 while (values.hasMoreTokens())
308 headers.addHeader(key, values.nextToken().trim());
309 }
310 i++;
311 }
313 httpIn =
314 (isFailure
315 ? httpConnection.getErrorStream()
316 : httpConnection.getInputStream());
318 byte[] bytes = readFully(httpIn);
320 int length =
321 httpConnection.getContentLength() == -1
322 ? bytes.length
323 : httpConnection.getContentLength();
325 // If no reply message is returned,
326 // content-Length header field value is expected to be zero.
327 if (length == 0) {
328 response = null;
329 log.warning("SAAJ0014.p2p.content.zero");
330 } else {
331 ByteInputStream in = new ByteInputStream(bytes, length);
332 response = messageFactory.createMessage(headers, in);
333 }
335 } catch (SOAPException ex) {
336 throw ex;
337 } catch (Exception ex) {
338 log.log(Level.SEVERE,"SAAJ0010.p2p.cannot.read.resp", ex);
339 throw new SOAPExceptionImpl(
340 "Unable to read response: " + ex.getMessage());
341 } finally {
342 if (httpIn != null)
343 httpIn.close();
344 httpConnection.disconnect();
345 }
346 }
347 return response;
348 }
350 // Object identifies where the request should be sent.
351 // It is required to support objects of type String and java.net.URL.
353 public SOAPMessage get(Object endPoint) throws SOAPException {
354 if (closed) {
355 log.severe("SAAJ0011.p2p.get.already.closed.conn");
356 throw new SOAPExceptionImpl("Connection is closed");
357 }
358 Class urlEndpointClass = null;
360 try {
361 urlEndpointClass = Class.forName("javax.xml.messaging.URLEndpoint");
362 } catch (Exception ex) {
363 //Do nothing. URLEndpoint is available only when JAXM is there.
364 }
366 if (urlEndpointClass != null) {
367 if (urlEndpointClass.isInstance(endPoint)) {
368 String url = null;
370 try {
371 Method m = urlEndpointClass.getMethod("getURL", (Class[])null);
372 url = (String) m.invoke(endPoint, (Object[])null);
373 } catch (Exception ex) {
374 log.severe("SAAJ0004.p2p.internal.err");
375 throw new SOAPExceptionImpl(
376 "Internal error: " + ex.getMessage());
377 }
378 try {
379 endPoint = new URL(url);
380 } catch (MalformedURLException mex) {
381 log.severe("SAAJ0005.p2p.");
382 throw new SOAPExceptionImpl("Bad URL: " + mex.getMessage());
383 }
384 }
385 }
387 if (endPoint instanceof java.lang.String) {
388 try {
389 endPoint = new URL((String) endPoint);
390 } catch (MalformedURLException mex) {
391 log.severe("SAAJ0006.p2p.bad.URL");
392 throw new SOAPExceptionImpl("Bad URL: " + mex.getMessage());
393 }
394 }
396 if (endPoint instanceof URL)
397 try {
398 SOAPMessage response = doGet((URL)endPoint);
399 return response;
400 } catch (Exception ex) {
401 throw new SOAPExceptionImpl(ex);
402 } else
403 throw new SOAPExceptionImpl("Bad endPoint type " + endPoint);
404 }
406 SOAPMessage doGet(URL endPoint) throws SOAPException, IOException {
407 boolean isFailure = false;
409 URL url = null;
410 HttpURLConnection httpConnection = null;
412 int responseCode = 0;
413 try {
414 /// Is https GET allowed??
415 if (endPoint.getProtocol().equals("https"))
416 initHttps();
417 // Process the URL
418 URI uri = new URI(endPoint.toString());
419 String userInfo = uri.getRawUserInfo();
421 url = endPoint;
423 if (dL > 0)
424 d("uri: " + userInfo + " " + url + " " + uri);
426 // TBD
427 // Will deal with https later.
428 if (!url.getProtocol().equalsIgnoreCase("http")
429 && !url.getProtocol().equalsIgnoreCase("https")) {
430 log.severe("SAAJ0052.p2p.protocol.mustbe.http.or.https");
431 throw new IllegalArgumentException(
432 "Protocol "
433 + url.getProtocol()
434 + " not supported in URL "
435 + url);
436 }
437 httpConnection = (HttpURLConnection) createConnection(url);
439 httpConnection.setRequestMethod("GET");
441 httpConnection.setDoOutput(true);
442 httpConnection.setDoInput(true);
443 httpConnection.setUseCaches(false);
444 httpConnection.setFollowRedirects(true);
446 httpConnection.connect();
448 try {
450 responseCode = httpConnection.getResponseCode();
452 // let HTTP_INTERNAL_ERROR (500) through because it is used for SOAP faults
453 if (responseCode == HttpURLConnection.HTTP_INTERNAL_ERROR) {
454 isFailure = true;
455 } else if ((responseCode / 100) != 2) {
456 log.log(Level.SEVERE,
457 "SAAJ0008.p2p.bad.response",
458 new String[] { httpConnection.getResponseMessage()});
459 throw new SOAPExceptionImpl(
460 "Bad response: ("
461 + responseCode
462 + httpConnection.getResponseMessage());
464 }
465 } catch (IOException e) {
466 // on JDK1.3.1_01, we end up here, but then getResponseCode() succeeds!
467 responseCode = httpConnection.getResponseCode();
468 if (responseCode == HttpURLConnection.HTTP_INTERNAL_ERROR) {
469 isFailure = true;
470 } else {
471 throw e;
472 }
474 }
476 } catch (SOAPException ex) {
477 throw ex;
478 } catch (Exception ex) {
479 log.severe("SAAJ0012.p2p.get.failed");
480 throw new SOAPExceptionImpl("Get failed", ex);
481 }
483 SOAPMessage response = null;
484 InputStream httpIn = null;
485 if (responseCode == HttpURLConnection.HTTP_OK || isFailure) {
486 try {
487 MimeHeaders headers = new MimeHeaders();
489 String key, value;
491 // Header field 0 is the status line so we skip it.
493 int i = 1;
495 while (true) {
496 key = httpConnection.getHeaderFieldKey(i);
497 value = httpConnection.getHeaderField(i);
499 if (key == null && value == null)
500 break;
502 if (key != null) {
503 StringTokenizer values =
504 new StringTokenizer(value, ",");
505 while (values.hasMoreTokens())
506 headers.addHeader(key, values.nextToken().trim());
507 }
508 i++;
509 }
511 httpIn =
512 (isFailure
513 ? httpConnection.getErrorStream()
514 : httpConnection.getInputStream());
515 // If no reply message is returned,
516 // content-Length header field value is expected to be zero.
517 // java SE 6 documentation says :
518 // available() : an estimate of the number of bytes that can be read
519 //(or skipped over) from this input stream without blocking
520 //or 0 when it reaches the end of the input stream.
521 if ((httpIn == null )
522 || (httpConnection.getContentLength() == 0)
523 || (httpIn.available() == 0)) {
524 response = null;
525 log.warning("SAAJ0014.p2p.content.zero");
526 } else {
527 response = messageFactory.createMessage(headers, httpIn);
528 }
530 } catch (SOAPException ex) {
531 throw ex;
532 } catch (Exception ex) {
533 log.log(Level.SEVERE,
534 "SAAJ0010.p2p.cannot.read.resp",
535 ex);
536 throw new SOAPExceptionImpl(
537 "Unable to read response: " + ex.getMessage());
538 } finally {
539 if (httpIn != null)
540 httpIn.close();
541 httpConnection.disconnect();
542 }
543 }
544 return response;
545 }
547 private byte[] readFully(InputStream istream) throws IOException {
548 ByteArrayOutputStream bout = new ByteArrayOutputStream();
549 byte[] buf = new byte[1024];
550 int num = 0;
552 while ((num = istream.read(buf)) != -1) {
553 bout.write(buf, 0, num);
554 }
556 byte[] ret = bout.toByteArray();
558 return ret;
559 }
561 //private static String SSL_PKG = "com.sun.net.ssl.internal.www.protocol";
562 //private static String SSL_PROVIDER =
563 // "com.sun.net.ssl.internal.ssl.Provider";
564 private static final String SSL_PKG;
565 private static final String SSL_PROVIDER;
567 static {
568 if (isIBMVM) {
569 SSL_PKG ="com.ibm.net.ssl.internal.www.protocol";
570 SSL_PROVIDER ="com.ibm.net.ssl.internal.ssl.Provider";
571 } else {
572 //if not IBM VM default to Sun.
573 SSL_PKG = "com.sun.net.ssl.internal.www.protocol";
574 SSL_PROVIDER ="com.sun.net.ssl.internal.ssl.Provider";
575 }
576 }
578 private void initHttps() {
579 //if(!setHttps) {
580 String pkgs = SAAJUtil.getSystemProperty("java.protocol.handler.pkgs");
581 if (log.isLoggable(Level.FINE))
582 log.log(Level.FINE, "SAAJ0053.p2p.providers", new String[] { pkgs });
584 if (pkgs == null || pkgs.indexOf(SSL_PKG) < 0) {
585 if (pkgs == null)
586 pkgs = SSL_PKG;
587 else
588 pkgs = pkgs + "|" + SSL_PKG;
589 System.setProperty("java.protocol.handler.pkgs", pkgs);
590 if (log.isLoggable(Level.FINE))
591 log.log(Level.FINE, "SAAJ0054.p2p.set.providers",
592 new String[] { pkgs });
593 try {
594 Class c = Class.forName(SSL_PROVIDER);
595 Provider p = (Provider) c.newInstance();
596 Security.addProvider(p);
597 if (log.isLoggable(Level.FINE))
598 log.log(Level.FINE, "SAAJ0055.p2p.added.ssl.provider",
599 new String[] { SSL_PROVIDER });
600 //System.out.println("Added SSL_PROVIDER " + SSL_PROVIDER);
601 //setHttps = true;
602 } catch (Exception ex) {
603 }
604 }
605 //}
606 }
608 private void initAuthUserInfo(HttpURLConnection conn, String userInfo) {
609 String user;
610 String password;
611 if (userInfo != null) { // get the user and password
612 //System.out.println("UserInfo= " + userInfo );
613 int delimiter = userInfo.indexOf(':');
614 if (delimiter == -1) {
615 user = ParseUtil.decode(userInfo);
616 password = null;
617 } else {
618 user = ParseUtil.decode(userInfo.substring(0, delimiter++));
619 password = ParseUtil.decode(userInfo.substring(delimiter));
620 }
622 String plain = user + ":";
623 byte[] nameBytes = plain.getBytes();
624 byte[] passwdBytes = password.getBytes();
626 // concatenate user name and password bytes and encode them
627 byte[] concat = new byte[nameBytes.length + passwdBytes.length];
629 System.arraycopy(nameBytes, 0, concat, 0, nameBytes.length);
630 System.arraycopy(
631 passwdBytes,
632 0,
633 concat,
634 nameBytes.length,
635 passwdBytes.length);
636 String auth = "Basic " + new String(Base64.encode(concat));
637 conn.setRequestProperty("Authorization", auth);
638 if (dL > 0)
639 d("Adding auth " + auth);
640 }
641 }
643 private static final int dL = 0;
644 private void d(String s) {
645 log.log(Level.SEVERE,
646 "SAAJ0013.p2p.HttpSOAPConnection",
647 new String[] { s });
648 System.err.println("HttpSOAPConnection: " + s);
649 }
651 private java.net.HttpURLConnection createConnection(URL endpoint)
652 throws IOException {
653 return (HttpURLConnection) endpoint.openConnection();
654 }
656 }