Getting ​Transfer-Encoding=chunked instead of content length in soap ws call - java

I am trying to call two soap ws and from java. When I'm calling these ws from two different java thread it's successfully called but when tried to call in same thread, first call get successful and second call get stuck. I can see both the request in my logs.
I checked tcp dump at server and can see for first request, all the header parameter is set correctly but in second call instead of content-length getting transfer-encoding = chunked.
first ws call header - 2/15/2018 9:59:40 AM [8]
Content-Length=639 Content-Type=text/xml; charset=UTF-8 Accept=/ Host=test102.com User-Agent=Apache CXF
2.7.11 SOAPAction="Trackem.Web.Services/ReserveServiceTime" Proxy-Connection=Keep-Alive
Second ws call header - 2/15/2018 10:01:11 AM [9]
Transfer-Encoding=chunked Content-Type=text/xml; charset​​=UTF-8 Accept=/ Host=test102.com
User-Agent=Apache CXF 2.7.11
SOAPAction="Trackem.Web.Services/CreateOrUpdateTask"
Proxy-Connection=Keep-Alive5:05 PM
Please help me do understand why second call is not working properly?
Here is my java ws method -
public P getPort(final Class<P> serviceEndpointInterface, final String ascNode) throws MalformedURLException{
final Bus currThreadBus = BusFactory.getThreadDefaultBus();
ClassLoader originalThreadClassLoader = Thread.currentThread().getContextClassLoader();
ClassLoader busFactoryClassLoader = BusFactory.class.getClassLoader();
try {
Thread.currentThread().setContextClassLoader(busFactoryClassLoader);
BusFactory.setThreadDefaultBus(BusFactory.newInstance().createBus());
QName qname = new QName(nameSpace, strQName);
Service service = Service.create(qname);
P port = null;
if (CommonUtil.isEmpty(portName)) {
port = service.getPort(serviceEndpointInterface);
} else {
QName portQname = new QName(nameSpace, portName);
port = service.getPort(portQname, serviceEndpointInterface);
}
BindingProvider bp = (BindingProvider) port;
// Timeout in millis
bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, serviceURL);
bp.getRequestContext().put(Message.CONNECTION_TIMEOUT, Integer.parseInt(connectTimeout));
bp.getRequestContext().put(Message.RECEIVE_TIMEOUT, Integer.parseInt(requestTimeout));
final Client client = ClientProxy.getClient(port);
client.getOutInterceptors().add(new LoggingOutInterceptor());
client.getInInterceptors().add(new LoggingInInterceptor());
//Add proxy server details if configured in ASC
if(!CommonMethods.isEmpty(proxyHost) && !CommonMethods.isEmpty(proxyPort))
{
HTTPConduit http = (HTTPConduit) ClientProxy.getClient(port).getConduit();
http.getClient().setProxyServer(proxyHost);
http.getClient().setProxyServerPort(Integer.parseInt(proxyPort));
if(!CommonMethods.isEmpty(proxyUsername) && !CommonMethods.isEmpty(proxyPassword))
{
http.getProxyAuthorization().setUserName(proxyUsername);
http.getProxyAuthorization().setPassword(proxyPassword);
}
}
return port;
}finally {
BusFactory.setThreadDefaultBus(currThreadBus);
Thread.currentThread().setContextClassLoader(originalThreadClassLoader);
}}

I solved this issue by disabling chunk transfer in HTTP client.
http.getClient().setAllowChunking(false);
I guess, the problem was in my proxy serve see this link

Related

Equivalent of ClientCredentials in WCF connection from a C# WinForm?

What's the equivalent of ClientCredentials in WCF connection from a C# WinForm application to an HTTP request in Android Java or Swift?
ServicePointManager.ServerCertificateValidationCallback += delegate { return true; };
SvcClient objSvcClient = new SvcClient();
objSvcClient.ClientCredentials.UserName.UserName = txtUserName.Text;
objSvcClient.ClientCredentials.UserName.Password = txtPassword.Text;
int intout = objSvcClient.GetData(999);
objSvcClient.Close();
MessageBox.Show(intout.ToString());
Just add the authorization header to the http request,for more information about it, you can refer to this link:
how to pass client credentials in postman?

Android HttpURLConnection receives HTTP 301 response code

I'm trying to do a HTTP GET using the HttpURLConnection object in Android.
UPDATE
I tried connection to a different server. This is also hosted within Cloud 9 (c9.io) and also returns a json response. This time I'm not getting a 301 redirect, but I am getting the actual response the server is supposed to send.
Since this means the problem is localised within the server, I've reorganized the following sections in order to focus reading onto the server-related information. Android related information has been moved to the end of the question.
Where I am connecting:
Development server on Cloud9
Using the Laravel Framework 5.2 (we cannot upgrade to 5.3 at this time, due to unsupported project dependencies)
The server should return a JSON answer
If I connect to the same URL through the browser I get the correct response (JSON string. Required HTTP Headers and a '200' HTTP Response Code)
Where I am connecting FROM
Android phone (Oneplus 3, on Android 6.0)
Compile SDK version: 23
Using Build Tools: "23.0.3"
Using Min SDK verion: 19
Using Target SDK version: 22
I'm connectiong using a HttpURLConnection object, using HTTP Method 'GET'
HTTP Response on Android
When I run my code I get the folling result from the server:
The HTTP response code is 301 but the message is null.
The new URL is exactly the same, but using HTTPS. It seems server is somehow forcing SSL/TSL encryption. Which does not happen when accessing HTTP from the browser.
HTTP Header (on Android):
date => Tue, 04 Oct 2016 05:56:26 GMT
location => https://domain.com/route/ (I modified this bit)
content-length => 382
content-type => text/html; charset=iso-8859-1
X-BACKEND => apps-proxy
X-Android-Selected-Protocol => http/1.1
X-Android-Sent-Millis => 1475560583894
X-Android-Received-Millis => 1475560585637
X-Android-Response-Source => NETWORK 301
null => HTTP/1.1 301
Other data
Since it seems the server wants Android to use HTTPS, I tried modifying the code to use HTTPS (HttpsURLConnection). This may or may not solve this problem, but I am unable to check it since I get an annoying SSL handshake failed error. Plus I have no need for encryption on this application, and therefore I'm reluctant to solve the problems coming with it.
This is all running within an AsyncTask object (since Android get moody when you try to use a network connection on the main thread).
Setting up a new server (outside of Cloud 9 and without any SSL/TSL) could be an option, but I'm reluctant to do this since it would be quite time consuming.
I tried connecting to another Cloud 9 server (which also returns a json response), using the exact same code, and everything works correctly. This suggests that the problem arises from the HTPP 301 error.
I will try to share with you any other information you may require to answer my question!
Native Android stuff (moved on UPDATE, see above)
The response content seems to be an incomplete JSON:
{ 'status':'ERROR'
Note I did NOT forget the closing } character, that's what the response actually containts. This is injected somewhere unknown (to me) during the workflow. When I capture the HTTP response (using Charles on my PC, which is set as a Proxy for my phone's Wi-Fi connection) it's content is (as expected) a simple HTML telling you to redirect (HTPP code 301) to a new route.
The invalid JSON code (above) isn't there, but a valid HTML is.
This would suggest that the invalid JSON appears somewhere internally to my code (not on the server, or transport). But there is no code on my app that generates a JSON string, let alone inject it into the response I'm processing.
Code for the HttpURLConnection
this.setURL(ruta); //gets correct url
HttpURLConnection cxn = (HttpURLConnection) this.getURL().openConnection(); //init
cxn.setRequestMethod("GET"); //use HTTP GET verb
cxn.setUseCaches(false); //no cache
cxn.setRequestProperty("Cache-Control", "no-cache"); //even less cache
cxn.setDoOutput(false); //only true in POST/PUT requests
cxn.setRequestProperty("Connection","keep-alive");
cxn.setRequestProperty("DNT", "1"); //TEMP
cxn.setInstanceFollowRedirects(true); //should follow redirects
cxn.setRequestProperty( "charset", "utf-8");
Code for the reading the result
int status_code = cxn.getResponseCode();
InputStream responseStream = new BufferedInputStream(cxn.getInputStream());
BufferedReader responseStreamReader = new BufferedReader(new InputStreamReader(responseStream));
String line = "";
StringBuilder stringBuilder = new StringBuilder();
while ((line = responseStreamReader.readLine()) != null) {
stringBuilder.append(line).append("\n");
}
responseStreamReader.close();
String response = stringBuilder.toString();
cxn.disconnect();
Remove the code you've used to create the HttpURLConnection and try with this one:
URL url;
HttpURLConnection urlConnection = null;
try {
url = new URL("http://www.domain.com/index.aspx?parameter1=X&parameter2=X"); //Use your url and add the GET parameters
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setInstanceFollowRedirects(false); /* added line */
InputStream in = urlConnection.getInputStream();
InputStreamReader isw = new InputStreamReader(in);
int data = isw.read();
while (data != -1) {
char current = (char) data;
data = isw.read();
System.out.print(current);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (urlConnection != null) {
urlConnection.disconnect();
}
}
This should be all you need to set for your GET request.
EDIT:
I've tested the webservice using Volley, here's the code I've used in order to retrieve the webservice response:
public class MainActivity extends AppCompatActivity {
public String response;
TextView textView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView = (TextView) findViewById(R.id.rTextView);
RequestQueue queue = Volley.newRequestQueue(this);
String url = "yourWebserviceUrl";
// Request a string response from the provided URL.
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener < String > () {
#Override
public void onResponse(String response) {
textView.setText("Response is: " + response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
textView.setText("That didn't work!");
}
});
// Add the request to the RequestQueue.
queue.add(stringRequest);
}
}
And this is the response I got:
{"status":"ok","found":false,"extra":"App\\Scanners"}
Changing the protocol to https worked for me.
I faced the same problem, and I fixed it after reading this source.
All we need to do is handling 3** errors like shown below
if(responseCode > 300 && responseCode < 400) {
String redirectHeader = conn.getHeaderField("Location");
if(TextUtils.isEmpty(redirectHeader)) {
return new JsonResponse(responseCode, "Failed to redirect");
}
JsonRequest newRequest = request;
newRequest.url = redirectHeader;
return getJsonFromUrl(newRequest);
}
Each 3** response should have a header with name Location which contains a redirect link which we should use.
Change the line :
HttpURLConnection cxn = (HttpURLConnection) this.getURL().openConnection();
with :
HttpsURLConnection cxn = (HttpsURLConnection) this.getURL().openConnection();
So you will able to handle https

Jersey ClientResponse getCookies failing to parse correctly

I have some Java code which is calling a restful service, and needs to first authenticate and store cookies for a future call. I am using Jersey 1.8. The problem is that after making the call to authenticate, I try to retrieve the cookies using ClientResponse.getCookies() and iterate through the list of NewCookie objects. However, when calling NewCookie.getName(), the path of the cookie is returned.
The cookies returned in the response header look like this:
Set-Cookie: xsIdEEDB0766347B60DAEAA0AF57226EDD2C=385DF57B79FE0A4D84E04ED43000A81B; path=/; HttpOnly
My code looks something like this. I am just dumping the info to System.out for now because I wanted to look at the values in the debugger.
My question is why ClientResponse.getCookies() does not seem to work. Parsing the headers manually will work, but that just does not seem right. Is there a way to configure the Client or the ClientResponse to correctly get the cookies?
ClientConfig clientConfig = new DefaultClientConfig();
Client client = Client.create(clientConfig);
Builder builder = client.resource(MY_PATH).accept("text/plain");
builder = builder.header(AUTHORIZATION, auth);
ClientResponse response = builder.head();
if (response.getClientResponseStatus() == Status.OK) {
// Look at cookies in the response
List<NewCookie> cs = response.getCookies();
for (NewCookie c : cs) {
System.out.println(c.getName());
System.out.println(c.getValue());
}
// Look at the cookies in the header
List<String> cookies = headers.get("Set-Cookie");
for (String cookie : cookies) {
// example: xsIdEEDB0766347B60DAEAA0AF57226EDD2C=385DF57B79FE0A4D84E04ED43000A81B; path=/; HttpOnly
int x = cookie.indexOf(';');
String cookieNameValue = cookie.substring(0, x);
String[] nameValue = cookieNameValue.split("=");
NewCookie nc = new NewCookie(nameValue[0], nameValue[1]);
}
}

Java Jersey ClientResponse returns wrong Status from getClientResponseStatus

I feel like I am missing something here. I have a filter which prints out my server's returned information and I report that I am returning the correct response (403). I wrote a JUnit test to verify this logic and many times I am reporting 200 instead of 403. The weird part is that my server logs still show that I sent a 403. Is there some known bug in Jersey 1.17 that I am not aware of and I need to upgrade to resolve? I am not really in a position to upgrade at this point in time so I am hoping there is some bug in my logic. Here is my test case.
#Test
public void testIdsOwnedBySomeoneElse()
{
final Login user1Cred = Logins.getInstance().getLogin(Logins.LoginType.User1);
final Login user2Cred = Logins.getInstance().getLogin(Logins.LoginType.User2);
final ServiceEndpointAuthenticated authUser1 = LoginHelper.Login(user1Cred);
final ServiceEndpointAuthenticated authUser2 = LoginHelper.Login(user2Cred);
// Create generic entry owned by user 1
BigInteger user1Id = null;
{
final Object payload = endpoint.CreateEntity(authUser1.getUserId());
final ClientResponse response = endpoint.Post(authUser1, payload);
assertTrue(Status.OK == response.getClientResponseStatus());
final byte[] data = Utilities.getBytes(response.getEntityInputStream());
user1Id = endpoint.getEntityId(data);
}
// Using User2, try to use that id from user1!
{
// test 1
final MyEndpointWrapper endpoint = new MyEndpointWrapper(user1Id, validId);
final Object payload = endpoint.CreateEntity(authUser2.getUserId());
final ClientResponse response = endpoint.Post(authUser2, payload);
final Status status = response.getClientResponseStatus();
System.out.println("Returned status = " + status);
if (status != Status.FORBIDDEN)
{
byte[] data = Utilities.getBytes(response.getEntityInputStream());
String toString = null;
try
{
toString = new String(data, "UTF-8");
}
catch (UnsupportedEncodingException e)
{
}
System.out.println("data: " + toString);
}
assertEquals("Status " + status + " is not forbidden!", Status.FORBIDDEN, status);
}
{
// test 2
final MyEndpointWrapper endpoint = new MyEndpointWrapper(validId, user1Id);
final Object payload = endpoint.CreateEntity(authUser2.getUserId());
final ClientResponse response = endpoint.Post(authUser2, payload);
final Status status = response.getClientResponseStatus();
System.out.println("Returned status = " + status);
if (status != Status.FORBIDDEN)
{
int i = 9;
}
assertEquals("Status " + status + " is not forbidden!", Status.FORBIDDEN, status);
}
// Go ahead and delete this data for cleanup
assertTrue(Status.OK == endpoint.Delete(authUser1, user1Id).getClientResponseStatus());
}
My generic code first logs into our server for the creds. These creds are "attached" to the WebResource and it attaches the proper headers automatically when I build my request. I first create an entity, post it, and store the returned id to be used by another user. I create another endpointwrapper which references that violation id and I attempt to post with that id. The server logs:
INFO: RESPONSE: 403 http://myendpoint MediaType:(application/json) Payload: 232 MyErrorMessage
I can even print this message out (as shown above)! The part I dont understand is that getClientResponseStatus returned to me OK. Why?
My Post code looks like:
#Override
public ClientResponse Post(ServiceEndpointAuthenticated endpoint, Object entity)
{
MyUploadData uploadData = (MyUploadData)entity;
return endpoint.getResourceBuilder("/myendpoint")
.accept(MediaTypeExt.APPLICATION_JSON)
.type(MediaTypeExt.APPLICATION_JSON)
.post(ClientResponse.class, gson.toJson(uploadData));
}
[UPDATE]
I ran wire capture and actually do see 200 being sent back! This does appear to be something inside of Jersey Server. Here is what I see:
When working:
Request: 1099 17.021219000 127.0.0.1 127.0.0.1 HTTP 2214 POST /myEndpoint HTTP/1.1 (application/json)
Response: 1153 17.042535000 127.0.0.1 127.0.0.1 HTTP 628 HTTP/1.1 400 Bad Request (application/json)
When not working:
Request: 1161 17.044313000 127.0.0.1 127.0.0.1 HTTP 250 POST /myEndpoint HTTP/1.1 (application/json)
Response: 1217 17.066059000 127.0.0.1 127.0.0.1 HTTP 412 HTTP/1.1 200 OK
When it works I see my normal headers in the response (eg: Access-Control-*, Pragma no cache, etc). When it doesn't work I dont see any of my headers but I do see "Transfer-Encoding: chunked" and my response is my error message but my response code is 200. I added an explicit Trace statement in the server right before I sent my response to ensure I am sending the right Status and I am.
I am okay with allowing chunked transfer but I am not really okay with losing my desired http response.
Incase anyone else encounters something similar. After digging around I finally found the problem. We have a heartbeat on some of our endpoints. Some endpoints can take longer than expected time. To ensure the client doesn't disconnect prematurely we have a component which attaches to the ServletOutputStream. This sends a space to the client to keep the connection alive.
When an error is thrown (caught by our new exception remapper), this keep-alive component was not being shutdown properly. This caused Jersey to switch into chunked mode. Ensuring the keep-alive component was shutdown properly resolved the problem.

How to use HttpsURLConnection through proxy by setProperty?

Network environment:
Https Client<=============>Proxy Server<==============>Https Server
192.168.17.11<-----extranet------>192.168.17.22
10.100.21.10<----intranet----->10.100.21.11
ps: Http Client without default gateway, but it can ping to 10.100.21.11
Description:
OS: Ubuntu 12.04 on 3 hosts
Https Client: Implement with java(openjdk-6).Have one network-interface.
Proxy Server: Apache2.2.Have two network-interfaces.
Https Server: Tomcat6.Have one network-interface.
I use two method to implement httpsurlconnection through proxy:
(For facilitate I do not write down about ssl handle function for checking serverTrusted and hostnameVerifier issue.If need I will update.)
1.Proxy class
InetSocketAddress proxyInet = new InetSocketAddress("10.100.21.11",80);
Proxy proxy = new Proxy(Proxy.Type.HTTP, proxyInet);
URL httpsUrl = new URL("https://192.168.17.22:8443/test");
HttpsURLConnection httpsCon = (HttpsURLConnection) httpsUrl.openConnection(proxy);
httpsCon.setDoOutput(true);
httpsCon.setDoInput(true);
httpsCon.setRequestMethod("POST");
OutputStream out = httpsCon.getOutputStream();
OutputStreamWriter owriter = new OutputStreamWriter(out);
owriter.write("<request>test</request>");
owriter.flush();
owriter.close();
...
This method workable and I observed packets flow also met my expectation.
HttpClient ---> ProxyServer ---> HttpServer
But when I use set Property method:
2.setProperty
System.setProperty("http.proxySet", "true");
System.setProperty("http.proxyHost",10.100.21.11);
System.setProperty("http.proxyPort","80");
URL httpsUrl = new URL("https://192.168.17.22:8443/test");
HttpsURLConnection httpsCon = (HttpsURLConnection)httpsUrl.openConnection();
httpsCon.setDoOutput(true);
httpsCon.setDoInput(true);
httpsCon.setRequestMethod("POST");
OutputStream out = httpsCon.getOutputStream();
OutputStreamWriter owriter = new OutputStreamWriter(out);
owriter.write("<request>test</request>");
owriter.flush();
owriter.close();
...
I got a NoRouteToHostException: Network is unreachable.
It make me confused.I did not see any packets between HttpClient and ProxyServer.
But HttpClient can ping to ProxyServer(10.100.12.10 ping 10.100.21.11)
So I remove proxy setting(as without using proxy):
Also got NoRouteToHostException: Network is unreachable.
I thought this is reasonable.Because there is no route to extranet.
I guess it seems like to setProperty method that the inner function of httpsUrlConnection will to check this url can be reachable or not.
But it is weird. 1st method can be success.
Have any idea? Or what are different between 1st and 2nd method?
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Update
System.setProperty("https.proxyHost",10.100.21.11);
System.setProperty("https.proxyPort","80");
It can work and packets flow are correct what I expect for.
But set https.proxyPort=443 is not workable for me
System.setProperty("https.proxyPort","443");
It will thorow a exception as bellow:
java.net.SocketException: Unexpected end of file from server
at sun.net.www.http.HttpClient.parseHTTPHeader(HttpClient.java:770)
....
So I thought Apache Proxy have also to be modified to the right configuration.
Your URL connection is https whereas you are only setting the http proxy.
Try setting the https proxy.
//System.setProperty("https.proxySet", "true");
System.setProperty("https.proxyHost",10.100.21.11);
System.setProperty("https.proxyPort","443");
EDIT
#EJP is correct. There is no https.proxySet .. I copied your original question and included in the answer.
You will need to create a Proxy object for it. Create one as below:
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyServer, Integer.parseInt(proxyPort)));
Now use this proxy to create the HttpURLConnection object.
HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection(proxy);
If you have to set the credentials for the proxy, set the Proxy-Authorization request property:
String uname_pwd = proxyUsername + ":" + proxyPassword
String authString = "Basic " + new sun.misc.BASE64Encoder().encode(uname_pwd.getBytes())
connection.setRequestProperty("Proxy-Authorization", authString);
And finally, you connect:
connection.connect();
thank you #divinedragon!
Same code on kotlin:
fun testProxy(login: String, pass: String, proxyData: ProxyData): String {
val url = URL("http://api.ipify.org")
val proxy = Proxy(Proxy.Type.HTTP, InetSocketAddress(proxyData.ip, proxyData.port))
val connection = url.openConnection(proxy) as HttpURLConnection
val loginPass = "$login:$pass"
val encodedLoginPass = Base64.getEncoder().encodeToString(loginPass.toByteArray())
val authString = "Basic $encodedLoginPass"
connection.setRequestProperty("Proxy-Authorization", authString);
with(connection) {
requestMethod = "GET" // optional default is GET
connectTimeout = 2000
readTimeout = 2000
return inputStream.bufferedReader().readText()
}
}

Categories

Resources