HTTPClient unable to establish route between https and http - httpclient

I am testing HttpClient 4.2 by hitting a mixture of http and https links.
HttpClient seems to stick with the protocol from the first call. If the first call is http, then all following https calls fail but http calls are fine. And vice versa.
Here is the test code I used.
#Test
public void testNoRedirectMixed() throws ClientProtocolException, IOException {
HttpClient httpclient = new DefaultHttpClient();
httpclient=WebClientDevWrapper.wrapClient(httpclient);
HttpClientParams.setRedirecting(httpclient.getParams(), false);
{
HttpGet httpget = new HttpGet("http://www.hotmail.com");
HttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
assertTrue(EntityUtils.toString(entity).indexOf("com")>0);
}
try {
HttpGet httpget = new HttpGet("https://www.hotmail.com");
HttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
}catch (Exception e) {
e.printStackTrace();
}
{
HttpGet httpget = new HttpGet("http://www.baidu.com");
HttpResponse response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
assertTrue(EntityUtils.toString(entity).indexOf("com")>0);
}
}
The second request (https) will fail, but the baidu request is fine.
Caused by: org.apache.http.HttpException: Unable to establish route: planned = {s}->https://www.hotmail.com; current = {s}->http://www.hotmail.com
at org.apache.http.impl.client.DefaultRequestDirector.establishRoute(DefaultRequestDirector.java:842)
I also have to disable redirection because hotmail redirects request: http://www.hotmail.com -> https://www.hotmail.com or https://www.hotmail.com -> https://www.live.com. A similar error is thrown in either cases.
The wrapper is shown below. It is used to accept all certificates.
public class WebClientDevWrapper {
public static HttpClient wrapClient(HttpClient base) {
try {
SSLContext ctx = SSLContext.getInstance("TLS");
X509TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] xcs,
String string) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] xcs,
String string) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[]{};
}
};
ctx.init(null, new TrustManager[] { tm }, null);
SSLSocketFactory ssf = new SSLSocketFactory(ctx);
ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
ClientConnectionManager ccm = base.getConnectionManager();
SchemeRegistry sr = ccm.getSchemeRegistry();
sr.register(new Scheme("https", ssf, 443));
DefaultHttpClient client= new DefaultHttpClient(ccm, base.getParams());
return client;
} catch (Exception ex) {
ex.printStackTrace();
return null;
}
}
}

HttpClient should be able to manage connections absolutely transparently to the user. This problem is likely to be caused by a regression introduced in the 4.2 release (see HTTPCLIENT-1193).
Use either PoolingConnectionManager or SingleConnectionManager instead of the default one until 4.2.1 version is released.

You are trying to use one connection to communicate to a number of different sites. AFAIR You have to create new connection (== new client) for every unique site.

Related

WireMock: Stubbing - How get object "testClient"?

I want to test http request/response. So I use WireMock.
I want to stub response for specific request:
Here code:
public class WireMockPersons {
#Rule
public WireMockRule wireMockRule = new WireMockRule(8089);
#Test
public void exactUrlOnly() {
stubFor(get(urlEqualTo("/some/thing"))
.willReturn(aResponse()
.withHeader("Content-Type", "text/plain")
.withBody("Hello world!")));
assertThat(testClient.get("/some/thing").statusCode(), is(200));
assertThat(testClient.get("/some/thing/else").statusCode(), is(404));
}
Code is not compile because no object testClient. How I can get testClient object?
testClient is your client library for the API you are mocking.
Looks like you have copied directly from the examples which are indicative only.
Replace testClient with the HTTP library of your choosing, for example HttpClient.
String url = "http://localhost:8089/some/thing";
try (CloseableHttpClient client = HttpClientBuilder.create().build()) {
HttpGet get = new HttpGet(url);
HttpEntity entity = client.execute(get).getEntity();
return EntityUtils.toString(entity, "UTF-8");
} catch (IOException e) {
throw new RuntimeException("Unable to call " + url, e);
}

Jetty Java websocket client doesn't connect to server

I am using Java Jetty client written [websocket-client 9.3.8.RC0]. Websocket server is little wierd in our case.
It accepting request in format.
wss://192.168.122.1:8443/status?-xsrf-=tokenValue
Token Value is received in first Login POST request in which i get Token Value & Cookie header. Cookie is added as a header whereas token is given as a param.
Now question is : -
When i run below code it just call awaitclose() function in starting. But there is not other function called i.e. Onconnected or even Onclose.
Any help would be appreciated to debug it further, to see any logs or environment issue to see why Socket is not connected.
Trying to figure out following points to debug.
1. To check if client certificates are causing issue.
Tried with my python code wspy.py it work seemlessly fine.
Code is
public final class websocketxxx {
WebSocketClient client=null;
public websocketxxx (){
}
public void run(String host,String cookieVal, String xsrfVal, String resource) throws IOException {
SslContextFactory sslContextFactory = new SslContextFactory();
sslContextFactory.setTrustAll(true);
WebSocketClient client = new WebSocketClient(sslContextFactory);
MyWebSocket socket = new MyWebSocket();
try {
client.start();
ClientUpgradeRequest request = new ClientUpgradeRequest();
// Add the authentication and protocol to the request header
// Crate wss URI from host and resource
resource = resource + xsrfVal;
URI destinationUri = new URI("wss://" + host + resource); // set URI
request.setHeader("cookie",cookieVal);
request.setHeader("Sec-WebSocket-Protocol", "ao-json");
//System.out.println("Request Headers print : " request.getHeaders())
System.out.println("Connecting to : " + destinationUri);
client.connect(socket, destinationUri, request);
socket.awaitClose(5000, TimeUnit.SECONDS);
} catch (Throwable t) {
t.printStackTrace();
} finally {
try {
client.stop();
} catch (Exception e) {
e.printStackTrace();
}
}
}
#WebSocket
public class MyWebSocket {
private final CountDownLatch closeLatch = new CountDownLatch(1);
#OnWebSocketConnect
public void onConnect(Session session) {
System.out.println("WebSocket Opened in client side");
try {
System.out.println("Sending message: Hi server");
session.getRemote().sendString("Hi Server");
} catch (IOException e) {
e.printStackTrace();
}
}
#OnWebSocketMessage
public void onMessage(String message) {
System.out.println("Message from Server: " + message);
}
#OnWebSocketClose
public void onClose(int statusCode, String reason) {
System.out.println("WebSocket Closed. Code:" + statusCode);
}
public boolean awaitClose(int duration, TimeUnit unit) throws InterruptedException {
return this.closeLatch.await(duration, unit);
}
}
public Client getBypassCertVerificationClient() {
Client client1 = null;
try {
// Create a HostnameVerifier that overrides the verify method to accept all hosts
HostnameVerifier hostnameVerifier = new HostnameVerifier() {
public boolean verify(String host, SSLSession sslSession) {
return true;
}
};
// Create a TrustManager
TrustManager[] trust_mgr = new TrustManager[]{
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
return null;
}
public void checkClientTrusted(X509Certificate[] certs, String t) {
}
public void checkServerTrusted(X509Certificate[] certs, String t) {
}
}
};
// Create the SSL Context
SSLContext sslContext = SSLContext.getInstance("SSL");
sslContext.init(null, trust_mgr, new SecureRandom());
// Create the client with the new hostname verifier and SSL context
client1 = ClientBuilder.newBuilder()
.sslContext(sslContext)
.hostnameVerifier(hostnameVerifier)
.build();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
return client1;
}
public String[] simple_Login_POST_request(String host, String user, String password, String resource, String data) {
String resp = null;
String[] headers = new String[2];
try {
// Create a Client instance that supports self-signed SSL certificates
Client client = getBypassCertVerificationClient();
// Create a WebTarget instance with host and resource
WebTarget target = client.target("https://" + host).path(resource);
// Build HTTP request invocation
Invocation.Builder invocationBuilder = target.request();
// Encode the user/password and add it to the request header
invocationBuilder.header(HttpHeaders.CONTENT_TYPE, "application/x-www-form-urlencoded");
Form form = new Form();
form.param("userid", user);
form.param("password", password);
// Invoke POST request and get response as String
//post(Entity.entity(form,MediaType.APPLICATION_FORM_URLENCODED_TYPE));
Response response = invocationBuilder.method("POST", Entity.entity(form,MediaType.APPLICATION_FORM_URLENCODED_TYPE));
resp = (String) response.readEntity(String.class);
// Print input URL, input data, response code and response
System.out.println("URL: [POST] " + target.getUri().toString());
System.out.println("HTTP Status: " + response.getStatus());
System.out.println("HTTP Status: " + response.getHeaders());
headers[0] = response.getHeaderString("Set-Cookie");
//response.getStringHeaders()
headers[1] = response.getHeaderString("X-XSRF-TOKEN");
System.out.println("Response: \n" + resp);
response.close();
} catch (Exception e) {
e.printStackTrace();
}
return headers;
}
public static void main(String[] args) throws IOException {
String host = "";
String user = "";
String password = "";
String resource = "";
host ="192.168.122.1:8443";
user = "ADMIN";
password ="ADMIN";
websocketXXX wsNotification = new websocketxxx();
/////////////////////////////////////////////////////////////////
// Simple POST LOGIN Request
resource = "/api/login";
String headers[]= wsNotification.simple_Login_POST_request(host, user, password, resource, null);
////////////////////////////////////////////////////////////////
headers[0] = headers[0].substring(headers[0].lastIndexOf(",") + 1);
System.out.println("headers[0]: " + headers[0] + "\n");
String cookie = headers[0];
String XSRFToken = headers[1];
resource = "/status?-xsrf-=";
//wsNotification.simple_websocket_example(host, cookie, XSRFToken, resource);
wsNotification.run(host, cookie, XSRFToken, resource);
}
}
The implementation is mostly correct.
Setting raw Cookie and Sec-WebSocket-* headers is forbidden, you have to use the API.
Cookie handling from:
ClientUpgradeRequest request = new ClientUpgradeRequest();
request.setHeader("cookie",cookieVal);
To ClientUpgradeRequest.setCookies() :
ClientUpgradeRequest request = new ClientUpgradeRequest();
List<HttpCookie> cookies = new ArrayList<>();
cookies.add(new HttpCookie(...));
request.setCookies(cookies);
Note: if you are using the java CookieStore, then you can pass the CookieStore instance to the client as well, using the setCookiesFrom(CookieStore) method.
Sub Protocol Selection from:
ClientUpgradeRequest request = new ClientUpgradeRequest();
request.setHeader("Sec-WebSocket-Protocol", "ao-json");
To ClientUpgradeRequest.setSubProtocols():
ClientUpgradeRequest request = new ClientUpgradeRequest();
request.setSubProtocols("ao-json");

Spring Cloud - Getting Retry Working In RestTemplate?

I have been migrating an existing application over to Spring Cloud's service discovery, Ribbon load balancing, and circuit breakers. The application already makes extensive use of the RestTemplate and I have been able to successfully use the load balanced version of the template. However, I have been testing the situation where there are two instances of a service and I drop one of those instances out of operation. I would like the RestTemplate to failover to the next server. From the research I have done, it appears that the fail-over logic exists in the Feign client and when using Zuul. It appears that the LoadBalancedRest template does not have logic for fail-over. In diving into the code, it looks like the RibbonClientHttpRequestFactory is using the netflix RestClient (which appears to have logic for doing retries).
So where do I go from here to get this working?
I would prefer to not use the Feign client because I would have to sweep A LOT of code.
I had found this link that suggested using the #Retryable annotation along with #HystrixCommand but this seems like something that should be a part of the load balanced rest template.
I did some digging into the code for RibbonClientHttpRequestFactory.RibbonHttpRequest:
protected ClientHttpResponse executeInternal(HttpHeaders headers) throws IOException {
try {
addHeaders(headers);
if (outputStream != null) {
outputStream.close();
builder.entity(outputStream.toByteArray());
}
HttpRequest request = builder.build();
HttpResponse response = client.execute(request, config);
return new RibbonHttpResponse(response);
}
catch (Exception e) {
throw new IOException(e);
}
}
It appears that if I override this method and change it to use "client.executeWithLoadBalancer()" that I might be able to leverage the retry logic that is built into the RestClient? I guess I could create my own version of the RibbonClientHttpRequestFactory to do this?
Just looking for guidance on the best approach.
Thanks
To answer my own question:
Before I get into the details, a cautionary tale:
Eureka's self preservation mode sent me down a rabbit hole while testing the fail-over on my local machine. I recommend turning self preservation mode off while doing your testing. Because I was dropping nodes at a regular rate and then restarting (with a different instance ID using a random value), I tripped Eureka's self preservation mode. I ended up with many instances in Eureka that pointed to the same machine, same port. The fail-over was actually working but the next node that was chosen happened to be another dead instance. Very confusing at first!
I was able to get fail-over working with a modified version of RibbonClientHttpRequestFactory. Because RibbonAutoConfiguration creates a load balanced RestTemplate with this factory, rather then injecting this rest template, I create a new one with my modified version of the request factory:
protected RestTemplate restTemplate;
#Autowired
public void customizeRestTemplate(SpringClientFactory springClientFactory, LoadBalancerClient loadBalancerClient) {
restTemplate = new RestTemplate();
// Use a modified version of the http request factory that leverages the load balacing in netflix's RestClient.
RibbonRetryHttpRequestFactory lFactory = new RibbonRetryHttpRequestFactory(springClientFactory, loadBalancerClient);
restTemplate.setRequestFactory(lFactory);
}
The modified Request Factory is just a copy of RibbonClientHttpRequestFactory with two minor changes:
1) In createRequest, I removed the code that was selecting a server from the load balancer because the RestClient will do that for us.
2) In the inner class, RibbonHttpRequest, I changed executeInternal to call "executeWithLoadBalancer".
The full class:
#SuppressWarnings("deprecation")
public class RibbonRetryHttpRequestFactory implements ClientHttpRequestFactory {
private final SpringClientFactory clientFactory;
private LoadBalancerClient loadBalancer;
public RibbonRetryHttpRequestFactory(SpringClientFactory clientFactory, LoadBalancerClient loadBalancer) {
this.clientFactory = clientFactory;
this.loadBalancer = loadBalancer;
}
#Override
public ClientHttpRequest createRequest(URI originalUri, HttpMethod httpMethod) throws IOException {
String serviceId = originalUri.getHost();
IClientConfig clientConfig = clientFactory.getClientConfig(serviceId);
RestClient client = clientFactory.getClient(serviceId, RestClient.class);
HttpRequest.Verb verb = HttpRequest.Verb.valueOf(httpMethod.name());
return new RibbonHttpRequest(originalUri, verb, client, clientConfig);
}
public class RibbonHttpRequest extends AbstractClientHttpRequest {
private HttpRequest.Builder builder;
private URI uri;
private HttpRequest.Verb verb;
private RestClient client;
private IClientConfig config;
private ByteArrayOutputStream outputStream = null;
public RibbonHttpRequest(URI uri, HttpRequest.Verb verb, RestClient client, IClientConfig config) {
this.uri = uri;
this.verb = verb;
this.client = client;
this.config = config;
this.builder = HttpRequest.newBuilder().uri(uri).verb(verb);
}
#Override
public HttpMethod getMethod() {
return HttpMethod.valueOf(verb.name());
}
#Override
public URI getURI() {
return uri;
}
#Override
protected OutputStream getBodyInternal(HttpHeaders headers) throws IOException {
if (outputStream == null) {
outputStream = new ByteArrayOutputStream();
}
return outputStream;
}
#Override
protected ClientHttpResponse executeInternal(HttpHeaders headers) throws IOException {
try {
addHeaders(headers);
if (outputStream != null) {
outputStream.close();
builder.entity(outputStream.toByteArray());
}
HttpRequest request = builder.build();
HttpResponse response = client.executeWithLoadBalancer(request, config);
return new RibbonHttpResponse(response);
}
catch (Exception e) {
throw new IOException(e);
}
//TODO: fix stats, now that execute is not called
// use execute here so stats are collected
/*
return loadBalancer.execute(this.config.getClientName(), new LoadBalancerRequest<ClientHttpResponse>() {
#Override
public ClientHttpResponse apply(ServiceInstance instance) throws Exception {}
});
*/
}
private void addHeaders(HttpHeaders headers) {
for (String name : headers.keySet()) {
// apache http RequestContent pukes if there is a body and
// the dynamic headers are already present
if (!isDynamic(name) || outputStream == null) {
List<String> values = headers.get(name);
for (String value : values) {
builder.header(name, value);
}
}
}
}
private boolean isDynamic(String name) {
return name.equals("Content-Length") || name.equals("Transfer-Encoding");
}
}
public class RibbonHttpResponse extends AbstractClientHttpResponse {
private HttpResponse response;
private HttpHeaders httpHeaders;
public RibbonHttpResponse(HttpResponse response) {
this.response = response;
this.httpHeaders = new HttpHeaders();
List<Map.Entry<String, String>> headers = response.getHttpHeaders().getAllHeaders();
for (Map.Entry<String, String> header : headers) {
this.httpHeaders.add(header.getKey(), header.getValue());
}
}
#Override
public InputStream getBody() throws IOException {
return response.getInputStream();
}
#Override
public HttpHeaders getHeaders() {
return this.httpHeaders;
}
#Override
public int getRawStatusCode() throws IOException {
return response.getStatus();
}
#Override
public String getStatusText() throws IOException {
return HttpStatus.valueOf(response.getStatus()).name();
}
#Override
public void close() {
response.close();
}
}
}
I had the same problem but then, out of the box, everything was working (using a #LoadBalanced RestTemplate). I am using Finchley version of Spring Cloud, and I think my problem was that I was not explicity adding spring-retry in my pom configuration. I'll leave here my spring-retry related yml configuration (remember this only works with #LoadBalanced RestTemplate, Zuul of Feign):
spring:
# Ribbon retries on
cloud:
loadbalancer:
retry:
enabled: true
# Ribbon service config
my-service:
ribbon:
MaxAutoRetries: 3
MaxAutoRetriesNextServer: 1
OkToRetryOnAllOperations: true
retryableStatusCodes: 500, 502

Why HandshakeRequest doesn't return HttpSession in my ServerEndpointConfig.Configurator?

There is a good example for sharing HttpSession between Websocket and Rest service. (Spring DispatchServlet cannot find resource within Jetty) But it doesn't work for me. I'm not sure is there any thing I'm missing?
I'm using Jetty as websocket server and also I created a WebApp as well which injected by SpringConfig.
private void init() throws Exception
{
Server server = new Server();
// Create SSL Connector
ServerConnector serverConnector = getSSLConnector(server);
// Bundle to server
server.setConnectors(new Connector[] { serverConnector });
// Create request handler collection
HandlerCollection handlers = new HandlerCollection();
// Add WebSocket handler
final ServletContextHandler servletContextHandler = getWebSocketContextHandler();
handlers.addHandler(servletContextHandler);
// Add Servlet handler
handlers.addHandler(getWebAppServletContextHandler());
server.setHandler(handlers);
// Initial WebSocket
WebSocketServerContainerInitializer.configureContext(servletContextHandler);
// Start Jetty
server.start();
server.join();
}
Both WebSocket and Rest are working under same port perfectly, of course, with different context paths.
Now, I created a Rest service:
#RequestMapping(value = "/login", method = RequestMethod.POST)
#Consumes({ MediaType.APPLICATION_JSON_VALUE })
#Produces({ MediaType.APPLICATION_JSON_VALUE })
public #ResponseBody Message login(#RequestBody Credential credential, #Context HttpServletRequest servlerRequest)
{
...
HttpSession session = servlerRequest.getSession(true);
session.setAttribute("userName", credential.getUserName());
...
Message message = new Message();
...
return message;
}
In this service I created a HttpSession and stored something in. As I said, it works, and so does the session.
Rest client:
public void login() throws KeyManagementException, NoSuchAlgorithmException
{
final String loginServiceUri = HTTP_SERVICE_BASE_URI + "/login";
ClientConfig clientConfig = new DefaultClientConfig();
...
Client client = Client.create(clientConfig);
WebResource webResource = client.resource(loginServiceUri);
ClientResponse response = webResource
.type("application/json")
.post(ClientResponse.class, new Credential("user","pass"));
if (response.getStatus() != 200) {
throw new RuntimeException("Failed : HTTP error code : " + response.getStatus());
}
List<NewCookie>cookies = response.getCookies();
ClientEndpointConfigurator.setCookies(cookies); <== Store cookies as well as session to ClientEndpointConfigrator class
Message message = response.getEntity(Message.class);
...
}
ClientEndpointConfigrator class has a static list for all cookies which like this:
public class ClientEndpointConfigurator extends ClientEndpointConfig.Configurator {
private static List<NewCookie> cookies = null;
public static void setCookies(List<NewCookie> cookies) {
ClientEndpointConfigurator.cookies = cookies;
}
...
#Override
public void beforeRequest(Map<String, List<String>> headers) {
...
if(null != cookies)
{
List<String> cookieList = new ArrayList<String>();
for(NewCookie cookie: cookies)
{
cookieList.add(cookie.toString());
}
headers.put("Cookie", cookieList);
}
...
}
}
beforeRequest() method will put all cookies to request header. If you inspect the cookieList, you will see:
[JSESSIONID=tvum36z6j2bc1p9uf2gumxguh;Version=1;Path=/rs;Secure]
Things looks prefect.
Finally, create a server end ServerEndpointConfigurator class, and override the modifyHandshake() method to retrieve the session and cookies
public class SpringServerEndpointConfigurator extends ServerEndpointConfig.Configurator {
#Override
public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
super.modifyHandshake(sec, request, response);
httpSession = (HttpSession)request.getHttpSession(); <== **It returns null here!**
...
}
}
}
I can't get my HttpSession back! and if you print headers out, you will see the cookie has been changed:
Cookie: JSESSIONID="tvum36z6j2bc1p9uf2gumxguh";$Path="/rs"
Any one knows what's the reason?
All right, I figured it out, it's because I put WebSocket and Rest to different context handler. Jetty keeps handlers isolate to each other. To share session information, you have to put them together.
But if someone does want to separate them, it is still possible done by sharing SessionManager or SessionHandler. There are many ways to achieve this, you can inject SessionHandler to each ServletContext or just define it as a static variable and put it on somewhere every one can reach, each way works.

SSL "Peer not Authenticated" error with HttpClient 4 - works in some case but not others

I have a wildcard cert for *.mydomain.com (the names have been changed to protect the innocent...that is NOT the real domain :) )
When using a correctly implemented Java HttpClient 4 (the issue is not seen in FF), Service calls made via HTTPS to api.mydomain.com are successful where as identical service calls made to non-production subdomains of mydomain.com (developer.mydomain.com, api-beta.mydomain.com, api-uat.mydomain.com) generate this Exception with the Test harness code below:
javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
at com.sun.net.ssl.internal.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:352)
at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:128)
at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:397)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:148)
at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:149)
at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:121)
at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:573)
at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:425)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:820)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:754)
at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:732)
at com.mydomain.httpclientexample.HttpClientTestv2.main(HttpClientTestv2.java:54)
While the SLL cert on developer.mydomain.com, api-beta.mydomain.com & api-uat.mydomain.com appears to be the same WC cert as api.mydomain.com, the exception is not seen on api.mydomain.com but it is on the other sub-domains. The code works on api-na.mydomain.com and should work on the non-production subdomains.
Any ideas?
Client code: As you can see, I can easily change the ADDRESS_VALIDATION_SERVICE_URI I want to call. The api.mydomain.com one works without the SSLPeerUnverifiedException; the other three URIs throw the exception...
package com.mydomain.httpclientexample;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
public class HttpClientTestv2 {
//public final static String ADDRESS_VALIDATION_SERVICE_URI = "https://developer.mydomain.com/v1.0/stores/MYSTORE/address/validate.xml";
public final static String ADDRESS_VALIDATION_SERVICE_URI = "https://api-beta.mydomain.com/v1.0/stores/MYSTORE/address/validate.xml";
//public final static String ADDRESS_VALIDATION_SERVICE_URI = "https://api-uat.mydomain.com/v1.0/stores/MYSTORE/address/validate.xml";
//public final static String ADDRESS_VALIDATION_SERVICE_URI = "https://api.mydomain.com/v1.0/stores/MYSTORE/address/validate.xml";
public final static String APIKEY_ATTRIBUTE_NAME = "apikey";
public final static String APIKEY_ATTRIBUTE_VALUE = "2c90bc83e821364ffa557486c3e2a44e";
/**
* #param args
*/
public static void main(String[] args) {
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpPost httpPost = new HttpPost(ADDRESS_VALIDATION_SERVICE_URI);
System.out.println("executing request" + httpPost.getRequestLine());
//set a request header
httpPost.setHeader(APIKEY_ATTRIBUTE_NAME , APIKEY_ATTRIBUTE_VALUE);
//add the xml body
StringEntity postBody = null;
try {
postBody = new StringEntity(getXMLDoc(),"UTF-8");
} catch (UnsupportedEncodingException uee) {
System.out.println("----------------------------------------");
System.out.println("Exception Caught in UnsupportedEncodingException catch block");
System.out.println("----------------------------------------");
uee.printStackTrace();
}
httpPost.setEntity(postBody);
HttpResponse response;
try {
response = httpclient.execute(httpPost);
HttpEntity entity = response.getEntity();
System.out.println("----------------------------------------");
System.out.println(response.getStatusLine());
if (entity != null) {
System.out.println("Response content length: " + entity.getContentLength());
System.out.println("Content:" + EntityUtils.toString(entity));
EntityUtils.consume(entity);
// entity.consumeContent();
}
} catch (ClientProtocolException e) {
System.out.println("----------------------------------------");
System.out.println("Exception Caught in ClientProtocolException catch block");
System.out.println("----------------------------------------");
e.printStackTrace();
} catch (IOException e) {
System.out.println("----------------------------------------");
System.out.println("Exception Caught in ClientProtocolException catch block");
System.out.println("----------------------------------------");
e.printStackTrace();
}
// When HttpClient instance is no longer needed,
// shut down the connection manager to ensure
// immediate deallocation of all system resources
httpclient.getConnectionManager().shutdown();
}
private static String getXMLDoc() {
StringBuffer XMLDoc = new StringBuffer("<?xml version=\"1.0\" encoding=\"UTF-8\"?><AddressValidationRequest xmlns=\"http://api.mydomain.com/schema/checkout/1.0\">")
.append("<Header><MaxAddressSuggestions>5</MaxAddressSuggestions></Header>")
.append("<Address><Line1>17243 S. Mill Ln</Line1><Line2/><City>Ocean View</City><MainDivision>DE</MainDivision><CountryCode>US</CountryCode><PostalCode>19970</PostalCode></Address>")
.append("</AddressValidationRequest>");
return XMLDoc.toString();
}
}