src/share/jaxws_classes/com/sun/xml/internal/ws/transport/http/client/HttpTransportPipe.java

changeset 368
0989ad8c0860
parent 286
f50545b5e2f1
child 408
b0610cd08440
equal deleted inserted replaced
366:8c0b6bccfe47 368:0989ad8c0860
1 /* 1 /*
2 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. 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. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 * 4 *
5 * This code is free software; you can redistribute it and/or modify it 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 6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this 7 * published by the Free Software Foundation. Oracle designates this
30 import com.sun.xml.internal.ws.api.WSBinding; 30 import com.sun.xml.internal.ws.api.WSBinding;
31 import com.sun.xml.internal.ws.api.ha.StickyFeature; 31 import com.sun.xml.internal.ws.api.ha.StickyFeature;
32 import com.sun.xml.internal.ws.api.message.Packet; 32 import com.sun.xml.internal.ws.api.message.Packet;
33 import com.sun.xml.internal.ws.api.pipe.*; 33 import com.sun.xml.internal.ws.api.pipe.*;
34 import com.sun.xml.internal.ws.api.pipe.helper.AbstractTubeImpl; 34 import com.sun.xml.internal.ws.api.pipe.helper.AbstractTubeImpl;
35 import com.sun.xml.internal.ws.client.ClientTransportException;
35 import com.sun.xml.internal.ws.developer.HttpConfigFeature; 36 import com.sun.xml.internal.ws.developer.HttpConfigFeature;
37 import com.sun.xml.internal.ws.resources.ClientMessages;
36 import com.sun.xml.internal.ws.transport.Headers; 38 import com.sun.xml.internal.ws.transport.Headers;
37 import com.sun.xml.internal.ws.util.ByteArrayBuffer; 39 import com.sun.xml.internal.ws.util.ByteArrayBuffer;
38 import com.sun.xml.internal.ws.client.ClientTransportException;
39 import com.sun.xml.internal.ws.resources.ClientMessages;
40 import com.sun.xml.internal.ws.util.RuntimeVersion; 40 import com.sun.xml.internal.ws.util.RuntimeVersion;
41 import com.sun.xml.internal.ws.util.StreamUtils; 41 import com.sun.xml.internal.ws.util.StreamUtils;
42 42
43 import javax.xml.bind.DatatypeConverter; 43 import javax.xml.bind.DatatypeConverter;
44 import javax.xml.bind.JAXBContext;
45 import javax.xml.bind.JAXBException;
46 import javax.xml.ws.BindingProvider; 44 import javax.xml.ws.BindingProvider;
47 import javax.xml.ws.WebServiceException; 45 import javax.xml.ws.WebServiceException;
48 import javax.xml.ws.WebServiceFeature; 46 import javax.xml.ws.WebServiceFeature;
47 import javax.xml.ws.handler.MessageContext;
49 import javax.xml.ws.soap.SOAPBinding; 48 import javax.xml.ws.soap.SOAPBinding;
50 import javax.xml.ws.handler.MessageContext; 49 import java.io.*;
51
52 import java.io.ByteArrayOutputStream;
53 import java.io.IOException;
54 import java.io.InputStream;
55 import java.io.OutputStream;
56 import java.io.PrintWriter;
57 import java.net.CookieHandler; 50 import java.net.CookieHandler;
58 import java.util.Collections; 51 import java.net.HttpURLConnection;
59 import java.util.List; 52 import java.util.*;
53 import java.util.Map.Entry;
54 import java.util.logging.Level;
60 import java.util.logging.Logger; 55 import java.util.logging.Logger;
61 import java.util.logging.Level;
62 import java.util.Map;
63 import java.util.Map.Entry;
64 import java.net.HttpURLConnection;
65 56
66 /** 57 /**
67 * {@link Tube} that sends a request to a remote HTTP server. 58 * {@link Tube} that sends a request to a remote HTTP server.
68 * 59 *
69 * TODO: need to create separate HTTP transport pipes for binding. SOAP1.1, SOAP1.2, 60 * TODO: need to create separate HTTP transport pipes for binding. SOAP1.1, SOAP1.2,
70 * TODO: XML/HTTP differ in handling status codes. 61 * TODO: XML/HTTP differ in handling status codes.
71 * 62 *
72 * @author Jitendra Kotamraju 63 * @author Jitendra Kotamraju
73 */ 64 */
74 public class HttpTransportPipe extends AbstractTubeImpl { 65 public class HttpTransportPipe extends AbstractTubeImpl {
75 private static final Logger LOGGER = Logger.getLogger(HttpTransportPipe.class.getName()); 66
67 private static final List<String> USER_AGENT = Collections.singletonList(RuntimeVersion.VERSION.toString());
68 private static final Logger LOGGER = Logger.getLogger(HttpTransportPipe.class.getName());
69
70 /**
71 * Dumps what goes across HTTP transport.
72 */
73 public static boolean dump;
76 74
77 private final Codec codec; 75 private final Codec codec;
78 private final WSBinding binding; 76 private final WSBinding binding;
79 private static final List<String> USER_AGENT = Collections.singletonList(RuntimeVersion.VERSION.toString());
80 private final CookieHandler cookieJar; // shared object among the tubes 77 private final CookieHandler cookieJar; // shared object among the tubes
81 private final boolean sticky; 78 private final boolean sticky;
82 79
83 // Need to use JAXB first to register DatatypeConverter
84 static { 80 static {
81 boolean b;
85 try { 82 try {
86 JAXBContext.newInstance().createUnmarshaller(); 83 b = Boolean.getBoolean(HttpTransportPipe.class.getName()+".dump");
87 } catch(JAXBException je) { 84 } catch( Throwable t ) {
88 // Nothing much can be done. Intentionally left empty 85 b = false;
89 } 86 }
87 dump = b;
90 } 88 }
91 89
92 public HttpTransportPipe(Codec codec, WSBinding binding) { 90 public HttpTransportPipe(Codec codec, WSBinding binding) {
93 this.codec = codec; 91 this.codec = codec;
94 this.binding = binding; 92 this.binding = binding;
118 private HttpTransportPipe(HttpTransportPipe that, TubeCloner cloner) { 116 private HttpTransportPipe(HttpTransportPipe that, TubeCloner cloner) {
119 this(that.codec.copy(), that.binding); 117 this(that.codec.copy(), that.binding);
120 cloner.add(that,this); 118 cloner.add(that,this);
121 } 119 }
122 120
121 @Override
123 public NextAction processException(@NotNull Throwable t) { 122 public NextAction processException(@NotNull Throwable t) {
124 return doThrow(t); 123 return doThrow(t);
125 } 124 }
126 125
126 @Override
127 public NextAction processRequest(@NotNull Packet request) { 127 public NextAction processRequest(@NotNull Packet request) {
128 return doReturnWith(process(request)); 128 return doReturnWith(process(request));
129 } 129 }
130 130
131 @Override
131 public NextAction processResponse(@NotNull Packet response) { 132 public NextAction processResponse(@NotNull Packet response) {
132 return doReturnWith(response); 133 return doReturnWith(response);
133 } 134 }
134 135
135 protected HttpClientTransport getTransport(Packet request, Map<String, List<String>> reqHeaders) { 136 protected HttpClientTransport getTransport(Packet request, Map<String, List<String>> reqHeaders) {
176 } 177 }
177 if (binding instanceof SOAPBinding) { 178 if (binding instanceof SOAPBinding) {
178 writeSOAPAction(reqHeaders, ct.getSOAPActionHeader()); 179 writeSOAPAction(reqHeaders, ct.getSOAPActionHeader());
179 } 180 }
180 181
181 if(dump || LOGGER.isLoggable(Level.FINER)) 182 if (dump || LOGGER.isLoggable(Level.FINER)) {
182 dump(buf, "HTTP request", reqHeaders); 183 dump(buf, "HTTP request", reqHeaders);
184 }
183 185
184 buf.writeTo(con.getOutput()); 186 buf.writeTo(con.getOutput());
185 } else { 187 } else {
186 // Set static Content-Type 188 // Set static Content-Type
187 reqHeaders.put("Content-Type", Collections.singletonList(ct.getContentType())); 189 reqHeaders.put("Content-Type", Collections.singletonList(ct.getContentType()));
313 return code == 500 || code == 400; 315 return code == 500 || code == 400;
314 } 316 }
315 317
316 private void addCookies(Packet context, Map<String, List<String>> reqHeaders) throws IOException { 318 private void addCookies(Packet context, Map<String, List<String>> reqHeaders) throws IOException {
317 Boolean shouldMaintainSessionProperty = 319 Boolean shouldMaintainSessionProperty =
318 (Boolean) context.invocationProperties.get(BindingProvider.SESSION_MAINTAIN_PROPERTY); 320 (Boolean) context.invocationProperties.get(BindingProvider.SESSION_MAINTAIN_PROPERTY);
319 if (shouldMaintainSessionProperty != null && !shouldMaintainSessionProperty) { 321 if (shouldMaintainSessionProperty != null && !shouldMaintainSessionProperty) {
320 return; // explicitly turned off 322 return; // explicitly turned off
321 } 323 }
322 if (sticky || (shouldMaintainSessionProperty != null && shouldMaintainSessionProperty)) { 324 if (sticky || (shouldMaintainSessionProperty != null && shouldMaintainSessionProperty)) {
323 Map<String, List<String>> cookies = cookieJar.get(context.endpointAddress.getURI(),reqHeaders); 325 Map<String, List<String>> rememberedCookies = cookieJar.get(context.endpointAddress.getURI(), reqHeaders);
324 List<String> cookieList = cookies.get("Cookie"); 326 processCookieHeaders(reqHeaders, rememberedCookies, "Cookie");
325 if (cookieList != null && !cookieList.isEmpty()) { 327 processCookieHeaders(reqHeaders, rememberedCookies, "Cookie2");
326 reqHeaders.put("Cookie", cookieList); 328 }
327 } 329 }
328 cookieList = cookies.get("Cookie2"); 330
329 if (cookieList != null && !cookieList.isEmpty()) { 331 private void processCookieHeaders(Map<String, List<String>> requestHeaders, Map<String, List<String>> rememberedCookies, String cookieHeader) {
330 reqHeaders.put("Cookie2", cookieList); 332 List<String> jarCookies = rememberedCookies.get(cookieHeader);
331 } 333 if (jarCookies != null && !jarCookies.isEmpty()) {
334 List<String> resultCookies = mergeUserCookies(jarCookies, requestHeaders.get(cookieHeader));
335 requestHeaders.put(cookieHeader, resultCookies);
336 }
337 }
338
339 private List<String> mergeUserCookies(List<String> rememberedCookies, List<String> userCookies) {
340
341 // nothing to merge
342 if (userCookies == null || userCookies.isEmpty()) {
343 return rememberedCookies;
344 }
345
346 Map<String, String> map = new HashMap<String, String>();
347 cookieListToMap(rememberedCookies, map);
348 cookieListToMap(userCookies, map);
349
350 return new ArrayList<String>(map.values());
351 }
352
353 private void cookieListToMap(List<String> cookieList, Map<String, String> targetMap) {
354 for(String cookie : cookieList) {
355 int index = cookie.indexOf("=");
356 String cookieName = cookie.substring(0, index);
357 targetMap.put(cookieName, cookie);
332 } 358 }
333 } 359 }
334 360
335 private void recordCookies(Packet context, HttpClientTransport con) throws IOException { 361 private void recordCookies(Packet context, HttpClientTransport con) throws IOException {
336 Boolean shouldMaintainSessionProperty = 362 Boolean shouldMaintainSessionProperty =
337 (Boolean) context.invocationProperties.get(BindingProvider.SESSION_MAINTAIN_PROPERTY); 363 (Boolean) context.invocationProperties.get(BindingProvider.SESSION_MAINTAIN_PROPERTY);
338 if (shouldMaintainSessionProperty != null && !shouldMaintainSessionProperty) { 364 if (shouldMaintainSessionProperty != null && !shouldMaintainSessionProperty) {
339 return; // explicitly turned off 365 return; // explicitly turned off
340 } 366 }
341 if (sticky || (shouldMaintainSessionProperty != null && shouldMaintainSessionProperty)) { 367 if (sticky || (shouldMaintainSessionProperty != null && shouldMaintainSessionProperty)) {
342 cookieJar.put(context.endpointAddress.getURI(), con.getHeaders()); 368 cookieJar.put(context.endpointAddress.getURI(), con.getHeaders());
346 private void addBasicAuth(Packet context, Map<String, List<String>> reqHeaders) { 372 private void addBasicAuth(Packet context, Map<String, List<String>> reqHeaders) {
347 String user = (String) context.invocationProperties.get(BindingProvider.USERNAME_PROPERTY); 373 String user = (String) context.invocationProperties.get(BindingProvider.USERNAME_PROPERTY);
348 if (user != null) { 374 if (user != null) {
349 String pw = (String) context.invocationProperties.get(BindingProvider.PASSWORD_PROPERTY); 375 String pw = (String) context.invocationProperties.get(BindingProvider.PASSWORD_PROPERTY);
350 if (pw != null) { 376 if (pw != null) {
351 StringBuffer buf = new StringBuffer(user); 377 StringBuilder buf = new StringBuilder(user);
352 buf.append(":"); 378 buf.append(":");
353 buf.append(pw); 379 buf.append(pw);
354 String creds = DatatypeConverter.printBase64Binary(buf.toString().getBytes()); 380 String creds = DatatypeConverter.printBase64Binary(buf.toString().getBytes());
355 reqHeaders.put("Authorization", Collections.singletonList("Basic "+creds)); 381 reqHeaders.put("Authorization", Collections.singletonList("Basic "+creds));
356 } 382 }
361 * write SOAPAction header if the soapAction parameter is non-null or BindingProvider properties set. 387 * write SOAPAction header if the soapAction parameter is non-null or BindingProvider properties set.
362 * BindingProvider properties take precedence. 388 * BindingProvider properties take precedence.
363 */ 389 */
364 private void writeSOAPAction(Map<String, List<String>> reqHeaders, String soapAction) { 390 private void writeSOAPAction(Map<String, List<String>> reqHeaders, String soapAction) {
365 //dont write SOAPAction HTTP header for SOAP 1.2 messages. 391 //dont write SOAPAction HTTP header for SOAP 1.2 messages.
366 if(SOAPVersion.SOAP_12.equals(binding.getSOAPVersion())) 392 if(SOAPVersion.SOAP_12.equals(binding.getSOAPVersion())) {
367 return; 393 return;
368 if (soapAction != null) 394 }
395 if (soapAction != null) {
369 reqHeaders.put("SOAPAction", Collections.singletonList(soapAction)); 396 reqHeaders.put("SOAPAction", Collections.singletonList(soapAction));
370 else 397 } else {
371 reqHeaders.put("SOAPAction", Collections.singletonList("\"\"")); 398 reqHeaders.put("SOAPAction", Collections.singletonList("\"\""));
372 } 399 }
373 400 }
401
402 @Override
374 public void preDestroy() { 403 public void preDestroy() {
375 // nothing to do. Intentionally left empty. 404 // nothing to do. Intentionally left empty.
376 } 405 }
377 406
407 @Override
378 public HttpTransportPipe copy(TubeCloner cloner) { 408 public HttpTransportPipe copy(TubeCloner cloner) {
379 return new HttpTransportPipe(this,cloner); 409 return new HttpTransportPipe(this,cloner);
380 } 410 }
381 411
382 412
399 buf.writeTo(baos); 429 buf.writeTo(baos);
400 pw.println("--------------------"); 430 pw.println("--------------------");
401 431
402 String msg = baos.toString(); 432 String msg = baos.toString();
403 if (dump) { 433 if (dump) {
404 System.out.println(msg); 434 System.out.println(msg);
405 } 435 }
406 if (LOGGER.isLoggable(Level.FINER)) { 436 if (LOGGER.isLoggable(Level.FINER)) {
407 LOGGER.log(Level.FINER, msg); 437 LOGGER.log(Level.FINER, msg);
408 } 438 }
409 } 439 }
410 440
411 /**
412 * Dumps what goes across HTTP transport.
413 */
414 public static boolean dump;
415
416 static {
417 boolean b;
418 try {
419 b = Boolean.getBoolean(HttpTransportPipe.class.getName()+".dump");
420 } catch( Throwable t ) {
421 b = false;
422 }
423 dump = b;
424 }
425 } 441 }

mercurial