Fri, 07 Aug 2009 11:27:00 -0700
6813167: 6u14 JAX-WS audit mutable static bugs
6803688: Integrate latest JAX-WS (2.1.6) in to JDK 6u14
Reviewed-by: darcy, ramap
1 /*
2 * Copyright 2005-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
27 package com.sun.xml.internal.messaging.saaj.client.p2p;
29 import java.io.*;
30 import java.lang.reflect.Method;
31 import java.net.*;
32 import java.security.*;
33 import java.util.Iterator;
34 import java.util.StringTokenizer;
35 import java.util.logging.Level;
36 import java.util.logging.Logger;
38 import javax.xml.soap.*;
40 import com.sun.xml.internal.messaging.saaj.SOAPExceptionImpl;
41 import com.sun.xml.internal.messaging.saaj.util.*;
43 /**
44 * This represents a "connection" to the simple HTTP-based provider.
45 *
46 * @author Anil Vijendran (akv@eng.sun.com)
47 * @author Rajiv Mordani (rajiv.mordani@sun.com)
48 * @author Manveen Kaur (manveen.kaur@sun.com)
49 *
50 */
51 public class HttpSOAPConnection extends SOAPConnection {
53 public static final String vmVendor = System.getProperty("java.vendor.url");
54 private static final String sunVmVendor = "http://java.sun.com/";
55 private static final String ibmVmVendor = "http://www.ibm.com/";
56 private static final boolean isSunVM = sunVmVendor.equals(vmVendor) ? true: false;
57 private static final boolean isIBMVM = ibmVmVendor.equals(vmVendor) ? true : false;
58 private static final String JAXM_URLENDPOINT="javax.xml.messaging.URLEndpoint";
60 protected static final Logger log =
61 Logger.getLogger(LogDomainConstants.HTTP_CONN_DOMAIN,
62 "com.sun.xml.internal.messaging.saaj.client.p2p.LocalStrings");
64 private static final String defaultProxyHost = null;
65 private static final int defaultProxyPort = -1;
67 MessageFactory messageFactory = null;
69 boolean closed = false;
71 public HttpSOAPConnection() throws SOAPException {
72 proxyHost = defaultProxyHost;
73 proxyPort = defaultProxyPort;
75 try {
76 messageFactory = MessageFactory.newInstance(SOAPConstants.DYNAMIC_SOAP_PROTOCOL);
77 } catch (NoSuchMethodError ex) {
78 //fallback to default SOAP 1.1 in this case for backward compatibility
79 messageFactory = MessageFactory.newInstance();
80 } catch (Exception ex) {
81 log.log(Level.SEVERE, "SAAJ0001.p2p.cannot.create.msg.factory", ex);
82 throw new SOAPExceptionImpl("Unable to create message factory", ex);
83 }
84 }
86 public void close() throws SOAPException {
87 if (closed) {
88 log.severe("SAAJ0002.p2p.close.already.closed.conn");
89 throw new SOAPExceptionImpl("Connection already closed");
90 }
92 messageFactory = null;
93 closed = true;
94 }
96 public SOAPMessage call(SOAPMessage message, Object endPoint)
97 throws SOAPException {
98 if (closed) {
99 log.severe("SAAJ0003.p2p.call.already.closed.conn");
100 throw new SOAPExceptionImpl("Connection is closed");
101 }
103 Class urlEndpointClass = null;
104 ClassLoader loader = Thread.currentThread().getContextClassLoader();
105 try {
106 if (loader != null) {
107 urlEndpointClass = loader.loadClass(JAXM_URLENDPOINT);
108 } else {
109 urlEndpointClass = Class.forName(JAXM_URLENDPOINT);
110 }
111 } catch (ClassNotFoundException ex) {
112 //Do nothing. URLEndpoint is available only when JAXM is there.
113 log.finest("SAAJ0090.p2p.endpoint.available.only.for.JAXM");
114 }
116 if (urlEndpointClass != null) {
117 if (urlEndpointClass.isInstance(endPoint)) {
118 String url = null;
120 try {
121 Method m = urlEndpointClass.getMethod("getURL", (Class[])null);
122 url = (String) m.invoke(endPoint, (Object[])null);
123 } catch (Exception ex) {
124 // TBD -- exception chaining
125 log.log(Level.SEVERE,"SAAJ0004.p2p.internal.err",ex);
126 throw new SOAPExceptionImpl(
127 "Internal error: " + ex.getMessage());
128 }
129 try {
130 endPoint = new URL(url);
131 } catch (MalformedURLException mex) {
132 log.log(Level.SEVERE,"SAAJ0005.p2p.", mex);
133 throw new SOAPExceptionImpl("Bad URL: " + mex.getMessage());
134 }
135 }
136 }
138 if (endPoint instanceof java.lang.String) {
139 try {
140 endPoint = new URL((String) endPoint);
141 } catch (MalformedURLException mex) {
142 log.log(Level.SEVERE, "SAAJ0006.p2p.bad.URL", mex);
143 throw new SOAPExceptionImpl("Bad URL: " + mex.getMessage());
144 }
145 }
147 if (endPoint instanceof URL)
148 try {
149 PriviledgedPost pp =
150 new PriviledgedPost(this, message, (URL) endPoint);
151 SOAPMessage response =
152 (SOAPMessage) AccessController.doPrivileged(pp);
154 return response;
155 } catch (Exception ex) {
156 // TBD -- chaining?
157 throw new SOAPExceptionImpl(ex);
158 } else {
159 log.severe("SAAJ0007.p2p.bad.endPoint.type");
160 throw new SOAPExceptionImpl("Bad endPoint type " + endPoint);
161 }
162 }
164 static class PriviledgedPost implements PrivilegedExceptionAction {
166 HttpSOAPConnection c;
167 SOAPMessage message;
168 URL endPoint;
170 PriviledgedPost(
171 HttpSOAPConnection c,
172 SOAPMessage message,
173 URL endPoint) {
174 this.c = c;
175 this.message = message;
176 this.endPoint = endPoint;
177 }
179 public Object run() throws Exception {
180 return c.post(message, endPoint);
181 }
182 }
184 // TBD
185 // Fix this to do things better.
187 private String proxyHost = null;
189 static class PriviledgedSetProxyAction implements PrivilegedExceptionAction {
191 String proxyHost = null;
192 int proxyPort = 0;
194 PriviledgedSetProxyAction(String host, int port) {
195 this.proxyHost = host;
196 this.proxyPort = port;
197 }
199 public Object run() throws Exception {
200 System.setProperty("http.proxyHost", proxyHost);
201 System.setProperty("http.proxyPort", new Integer(proxyPort).toString());
202 log.log(Level.FINE, "SAAJ0050.p2p.proxy.host",
203 new String[] { proxyHost });
204 log.log(Level.FINE, "SAAJ0051.p2p.proxy.port",
205 new String[] { new Integer(proxyPort).toString() });
206 return proxyHost;
207 }
208 }
211 public void setProxy(String host, int port) {
212 try {
213 proxyPort = port;
214 PriviledgedSetProxyAction ps = new PriviledgedSetProxyAction(host, port);
215 proxyHost = (String) AccessController.doPrivileged(ps);
216 } catch (Exception e) {
217 throw new RuntimeException(e);
218 }
219 }
221 public String getProxyHost() {
222 return proxyHost;
223 }
225 private int proxyPort = -1;
227 public int getProxyPort() {
228 return proxyPort;
229 }
231 SOAPMessage post(SOAPMessage message, URL endPoint) throws SOAPException {
232 boolean isFailure = false;
234 URL url = null;
235 HttpURLConnection httpConnection = null;
237 int responseCode = 0;
238 try {
239 if (endPoint.getProtocol().equals("https"))
240 //if(!setHttps)
241 initHttps();
242 // Process the URL
243 JaxmURI uri = new JaxmURI(endPoint.toString());
244 String userInfo = uri.getUserinfo();
246 url = endPoint;
248 if (dL > 0)
249 d("uri: " + userInfo + " " + url + " " + uri);
251 // TBD
252 // Will deal with https later.
253 if (!url.getProtocol().equalsIgnoreCase("http")
254 && !url.getProtocol().equalsIgnoreCase("https")) {
255 log.severe("SAAJ0052.p2p.protocol.mustbe.http.or.https");
256 throw new IllegalArgumentException(
257 "Protocol "
258 + url.getProtocol()
259 + " not supported in URL "
260 + url);
261 }
262 httpConnection = (HttpURLConnection) createConnection(url);
264 httpConnection.setRequestMethod("POST");
266 httpConnection.setDoOutput(true);
267 httpConnection.setDoInput(true);
268 httpConnection.setUseCaches(false);
269 HttpURLConnection.setFollowRedirects(true);
271 if (message.saveRequired())
272 message.saveChanges();
274 MimeHeaders headers = message.getMimeHeaders();
276 Iterator it = headers.getAllHeaders();
277 boolean hasAuth = false; // true if we find explicit Auth header
278 while (it.hasNext()) {
279 MimeHeader header = (MimeHeader) it.next();
281 String[] values = headers.getHeader(header.getName());
283 if (values.length == 1)
284 httpConnection.setRequestProperty(
285 header.getName(),
286 header.getValue());
287 else {
288 StringBuffer concat = new StringBuffer();
289 int i = 0;
290 while (i < values.length) {
291 if (i != 0)
292 concat.append(',');
293 concat.append(values[i]);
294 i++;
295 }
297 httpConnection.setRequestProperty(
298 header.getName(),
299 concat.toString());
300 }
302 if ("Authorization".equals(header.getName())) {
303 hasAuth = true;
304 log.fine("SAAJ0091.p2p.https.auth.in.POST.true");
305 }
306 }
308 if (!hasAuth && userInfo != null) {
309 initAuthUserInfo(httpConnection, userInfo);
310 }
312 OutputStream out = httpConnection.getOutputStream();
313 message.writeTo(out);
315 out.flush();
316 out.close();
318 httpConnection.connect();
320 try {
322 responseCode = httpConnection.getResponseCode();
324 // let HTTP_INTERNAL_ERROR (500) through because it is used for SOAP faults
325 if (responseCode == HttpURLConnection.HTTP_INTERNAL_ERROR) {
326 isFailure = true;
327 }
328 //else if (responseCode != HttpURLConnection.HTTP_OK)
329 //else if (!(responseCode >= HttpURLConnection.HTTP_OK && responseCode < 207))
330 else if ((responseCode / 100) != 2) {
331 log.log(Level.SEVERE,
332 "SAAJ0008.p2p.bad.response",
333 new String[] {httpConnection.getResponseMessage()});
334 throw new SOAPExceptionImpl(
335 "Bad response: ("
336 + responseCode
337 + httpConnection.getResponseMessage());
339 }
340 } catch (IOException e) {
341 // on JDK1.3.1_01, we end up here, but then getResponseCode() succeeds!
342 responseCode = httpConnection.getResponseCode();
343 if (responseCode == HttpURLConnection.HTTP_INTERNAL_ERROR) {
344 isFailure = true;
345 } else {
346 throw e;
347 }
349 }
351 } catch (SOAPException ex) {
352 throw ex;
353 } catch (Exception ex) {
354 log.severe("SAAJ0009.p2p.msg.send.failed");
355 throw new SOAPExceptionImpl("Message send failed", ex);
356 }
358 SOAPMessage response = null;
359 if (responseCode == HttpURLConnection.HTTP_OK || isFailure) {
360 try {
361 MimeHeaders headers = new MimeHeaders();
363 String key, value;
365 // Header field 0 is the status line so we skip it.
367 int i = 1;
369 while (true) {
370 key = httpConnection.getHeaderFieldKey(i);
371 value = httpConnection.getHeaderField(i);
373 if (key == null && value == null)
374 break;
376 if (key != null) {
377 StringTokenizer values =
378 new StringTokenizer(value, ",");
379 while (values.hasMoreTokens())
380 headers.addHeader(key, values.nextToken().trim());
381 }
382 i++;
383 }
385 InputStream httpIn =
386 (isFailure
387 ? httpConnection.getErrorStream()
388 : httpConnection.getInputStream());
390 byte[] bytes = readFully(httpIn);
392 int length =
393 httpConnection.getContentLength() == -1
394 ? bytes.length
395 : httpConnection.getContentLength();
397 // If no reply message is returned,
398 // content-Length header field value is expected to be zero.
399 if (length == 0) {
400 response = null;
401 log.warning("SAAJ0014.p2p.content.zero");
402 } else {
403 ByteInputStream in = new ByteInputStream(bytes, length);
404 response = messageFactory.createMessage(headers, in);
405 }
407 httpIn.close();
408 httpConnection.disconnect();
410 } catch (SOAPException ex) {
411 throw ex;
412 } catch (Exception ex) {
413 log.log(Level.SEVERE,"SAAJ0010.p2p.cannot.read.resp", ex);
414 throw new SOAPExceptionImpl(
415 "Unable to read response: " + ex.getMessage());
416 }
417 }
418 return response;
419 }
421 // Object identifies where the request should be sent.
422 // It is required to support objects of type String and java.net.URL.
424 public SOAPMessage get(Object endPoint) throws SOAPException {
425 if (closed) {
426 log.severe("SAAJ0011.p2p.get.already.closed.conn");
427 throw new SOAPExceptionImpl("Connection is closed");
428 }
429 Class urlEndpointClass = null;
431 try {
432 urlEndpointClass = Class.forName("javax.xml.messaging.URLEndpoint");
433 } catch (Exception ex) {
434 //Do nothing. URLEndpoint is available only when JAXM is there.
435 }
437 if (urlEndpointClass != null) {
438 if (urlEndpointClass.isInstance(endPoint)) {
439 String url = null;
441 try {
442 Method m = urlEndpointClass.getMethod("getURL", (Class[])null);
443 url = (String) m.invoke(endPoint, (Object[])null);
444 } catch (Exception ex) {
445 log.severe("SAAJ0004.p2p.internal.err");
446 throw new SOAPExceptionImpl(
447 "Internal error: " + ex.getMessage());
448 }
449 try {
450 endPoint = new URL(url);
451 } catch (MalformedURLException mex) {
452 log.severe("SAAJ0005.p2p.");
453 throw new SOAPExceptionImpl("Bad URL: " + mex.getMessage());
454 }
455 }
456 }
458 if (endPoint instanceof java.lang.String) {
459 try {
460 endPoint = new URL((String) endPoint);
461 } catch (MalformedURLException mex) {
462 log.severe("SAAJ0006.p2p.bad.URL");
463 throw new SOAPExceptionImpl("Bad URL: " + mex.getMessage());
464 }
465 }
467 if (endPoint instanceof URL)
468 try {
469 PriviledgedGet pg = new PriviledgedGet(this, (URL) endPoint);
470 SOAPMessage response =
471 (SOAPMessage) AccessController.doPrivileged(pg);
473 return response;
474 } catch (Exception ex) {
475 throw new SOAPExceptionImpl(ex);
476 } else
477 throw new SOAPExceptionImpl("Bad endPoint type " + endPoint);
478 }
480 static class PriviledgedGet implements PrivilegedExceptionAction {
482 HttpSOAPConnection c;
483 URL endPoint;
485 PriviledgedGet(HttpSOAPConnection c, URL endPoint) {
486 this.c = c;
487 this.endPoint = endPoint;
488 }
490 public Object run() throws Exception {
491 return c.get(endPoint);
492 }
493 }
495 SOAPMessage get(URL endPoint) throws SOAPException {
496 boolean isFailure = false;
498 URL url = null;
499 HttpURLConnection httpConnection = null;
501 int responseCode = 0;
502 try {
503 /// Is https GET allowed??
504 if (endPoint.getProtocol().equals("https"))
505 initHttps();
506 // Process the URL
507 JaxmURI uri = new JaxmURI(endPoint.toString());
508 String userInfo = uri.getUserinfo();
510 url = endPoint;
512 if (dL > 0)
513 d("uri: " + userInfo + " " + url + " " + uri);
515 // TBD
516 // Will deal with https later.
517 if (!url.getProtocol().equalsIgnoreCase("http")
518 && !url.getProtocol().equalsIgnoreCase("https")) {
519 log.severe("SAAJ0052.p2p.protocol.mustbe.http.or.https");
520 throw new IllegalArgumentException(
521 "Protocol "
522 + url.getProtocol()
523 + " not supported in URL "
524 + url);
525 }
526 httpConnection = (HttpURLConnection) createConnection(url);
528 httpConnection.setRequestMethod("GET");
530 httpConnection.setDoOutput(true);
531 httpConnection.setDoInput(true);
532 httpConnection.setUseCaches(false);
533 HttpURLConnection.setFollowRedirects(true);
535 httpConnection.connect();
537 try {
539 responseCode = httpConnection.getResponseCode();
541 // let HTTP_INTERNAL_ERROR (500) through because it is used for SOAP faults
542 if (responseCode == HttpURLConnection.HTTP_INTERNAL_ERROR) {
543 isFailure = true;
544 } else if ((responseCode / 100) != 2) {
545 log.log(Level.SEVERE,
546 "SAAJ0008.p2p.bad.response",
547 new String[] { httpConnection.getResponseMessage()});
548 throw new SOAPExceptionImpl(
549 "Bad response: ("
550 + responseCode
551 + httpConnection.getResponseMessage());
553 }
554 } catch (IOException e) {
555 // on JDK1.3.1_01, we end up here, but then getResponseCode() succeeds!
556 responseCode = httpConnection.getResponseCode();
557 if (responseCode == HttpURLConnection.HTTP_INTERNAL_ERROR) {
558 isFailure = true;
559 } else {
560 throw e;
561 }
563 }
565 } catch (SOAPException ex) {
566 throw ex;
567 } catch (Exception ex) {
568 log.severe("SAAJ0012.p2p.get.failed");
569 throw new SOAPExceptionImpl("Get failed", ex);
570 }
572 SOAPMessage response = null;
573 if (responseCode == HttpURLConnection.HTTP_OK || isFailure) {
574 try {
575 MimeHeaders headers = new MimeHeaders();
577 String key, value;
579 // Header field 0 is the status line so we skip it.
581 int i = 1;
583 while (true) {
584 key = httpConnection.getHeaderFieldKey(i);
585 value = httpConnection.getHeaderField(i);
587 if (key == null && value == null)
588 break;
590 if (key != null) {
591 StringTokenizer values =
592 new StringTokenizer(value, ",");
593 while (values.hasMoreTokens())
594 headers.addHeader(key, values.nextToken().trim());
595 }
596 i++;
597 }
599 InputStream httpIn =
600 (isFailure
601 ? httpConnection.getErrorStream()
602 : httpConnection.getInputStream());
604 byte[] bytes = readFully(httpIn);
606 int length =
607 httpConnection.getContentLength() == -1
608 ? bytes.length
609 : httpConnection.getContentLength();
611 // If no reply message is returned,
612 // content-Length header field value is expected to be zero.
613 if (length == 0) {
614 response = null;
615 log.warning("SAAJ0014.p2p.content.zero");
616 } else {
618 ByteInputStream in = new ByteInputStream(bytes, length);
619 response = messageFactory.createMessage(headers, in);
620 }
622 httpIn.close();
623 httpConnection.disconnect();
625 } catch (SOAPException ex) {
626 throw ex;
627 } catch (Exception ex) {
628 log.log(Level.SEVERE,
629 "SAAJ0010.p2p.cannot.read.resp",
630 ex);
631 throw new SOAPExceptionImpl(
632 "Unable to read response: " + ex.getMessage());
633 }
634 }
635 return response;
636 }
638 private byte[] readFully(InputStream istream) throws IOException {
639 ByteArrayOutputStream bout = new ByteArrayOutputStream();
640 byte[] buf = new byte[1024];
641 int num = 0;
643 while ((num = istream.read(buf)) != -1) {
644 bout.write(buf, 0, num);
645 }
647 byte[] ret = bout.toByteArray();
649 return ret;
650 }
652 //private static String SSL_PKG = "com.sun.net.ssl.internal.www.protocol";
653 //private static String SSL_PROVIDER =
654 // "com.sun.net.ssl.internal.ssl.Provider";
655 private static final String SSL_PKG;
656 private static final String SSL_PROVIDER;
658 static {
659 if (isIBMVM) {
660 SSL_PKG ="com.ibm.net.ssl.internal.www.protocol";
661 SSL_PROVIDER ="com.ibm.net.ssl.internal.ssl.Provider";
662 } else {
663 //if not IBM VM default to Sun.
664 SSL_PKG = "com.sun.net.ssl.internal.www.protocol";
665 SSL_PROVIDER ="com.sun.net.ssl.internal.ssl.Provider";
666 }
667 }
669 private void initHttps() {
670 //if(!setHttps) {
671 String pkgs = System.getProperty("java.protocol.handler.pkgs");
672 log.log(Level.FINE,
673 "SAAJ0053.p2p.providers",
674 new String[] { pkgs });
676 if (pkgs == null || pkgs.indexOf(SSL_PKG) < 0) {
677 if (pkgs == null)
678 pkgs = SSL_PKG;
679 else
680 pkgs = pkgs + "|" + SSL_PKG;
681 System.setProperty("java.protocol.handler.pkgs", pkgs);
682 log.log(Level.FINE,
683 "SAAJ0054.p2p.set.providers",
684 new String[] { pkgs });
685 try {
686 Class c = Class.forName(SSL_PROVIDER);
687 Provider p = (Provider) c.newInstance();
688 Security.addProvider(p);
689 log.log(Level.FINE,
690 "SAAJ0055.p2p.added.ssl.provider",
691 new String[] { SSL_PROVIDER });
692 //System.out.println("Added SSL_PROVIDER " + SSL_PROVIDER);
693 //setHttps = true;
694 } catch (Exception ex) {
695 }
696 }
697 //}
698 }
700 private void initAuthUserInfo(HttpURLConnection conn, String userInfo) {
701 String user;
702 String password;
703 if (userInfo != null) { // get the user and password
704 //System.out.println("UserInfo= " + userInfo );
705 int delimiter = userInfo.indexOf(':');
706 if (delimiter == -1) {
707 user = ParseUtil.decode(userInfo);
708 password = null;
709 } else {
710 user = ParseUtil.decode(userInfo.substring(0, delimiter++));
711 password = ParseUtil.decode(userInfo.substring(delimiter));
712 }
714 String plain = user + ":";
715 byte[] nameBytes = plain.getBytes();
716 byte[] passwdBytes = password.getBytes();
718 // concatenate user name and password bytes and encode them
719 byte[] concat = new byte[nameBytes.length + passwdBytes.length];
721 System.arraycopy(nameBytes, 0, concat, 0, nameBytes.length);
722 System.arraycopy(
723 passwdBytes,
724 0,
725 concat,
726 nameBytes.length,
727 passwdBytes.length);
728 String auth = "Basic " + new String(Base64.encode(concat));
729 conn.setRequestProperty("Authorization", auth);
730 if (dL > 0)
731 d("Adding auth " + auth);
732 }
733 }
735 private static final int dL = 0;
736 private void d(String s) {
737 log.log(Level.SEVERE,
738 "SAAJ0013.p2p.HttpSOAPConnection",
739 new String[] { s });
740 System.err.println("HttpSOAPConnection: " + s);
741 }
743 private java.net.HttpURLConnection createConnection(URL endpoint)
744 throws IOException {
745 return (HttpURLConnection) endpoint.openConnection();
746 }
748 }