Web service request working in old version of android (2.3.3) but not in later versions (4.0.3, 4.3) - https

While working on an application for android that uses web services I encounterd a bad request (response code 400) message when trying to retrieve some data in android versions 4.0.3 and 4.3. The perculiar thing however is that when sending the same request using the same code but on a device using android version 2.3.3 it works without any problems. I have also tried using httpGet instead of HttpsURLConnection, while this work for all versions it does not provide a solution as I need the added security.
My code is as follows:
private String executeRequest(String urlAddress)
{
String responce = null;
String msg = null;
int error = 0;
try {
URL url = new URL(urlAddress);
HttpsURLConnection connection = (HttpsURLConnection)url.openConnection();
SSLSocketFactory factory = SecureSocketFactory.getSSLSocketFactory();
connection.setSSLSocketFactory(factory);
connection.setHostnameVerifier(new Verifier());
connection.setDoOutput(true);
connection.setDoInput(true);
if (method == RequestMethod.POST)
{
connection.setRequestMethod("POST");
}
msg = connection.getResponseMessage();
error = connection.getResponseCode();
if ("OK".equals(msg))
{
InputStream content = (InputStream) connection.getContent();
responce = convertStreamToString(content);
}
else
{
responce = "Error " + error;
}
connection.disconnect();
} catch (Exception e) {
responce = e.toString();
}
return responce;
}
And the code of SecureSocketFactory.getSSLSocketFactory():
public static SSLSocketFactory getSSLSocketFactory()
throws IOException
{
if(ssf_ == null)
{
javax.net.ssl.KeyManager kms[] = null;
javax.net.ssl.TrustManager tms[] = null;
SSLContext context = null;
try
{
tms = CustomTrustManager.getTrustManagers();
context = SSLContext.getInstance("TLS");
context.init(kms, tms, null);
}
catch(GeneralSecurityException e)
{
IOException io = new IOException(e.getLocalizedMessage());
io.setStackTrace(e.getStackTrace());
throw io;
}
ssf_ = context.getSocketFactory();
}
return ssf_;
}
and the code of CustomTrustManager.getTrustManagers()
static TrustManager[] getTrustManagers(String trustStoreFile, String trustStorePW)
throws NoSuchAlgorithmException, KeyStoreException
{
String alg = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmFact = TrustManagerFactory.getInstance(alg);
tmFact.init((KeyStore)null);
TrustManager tms[] = tmFact.getTrustManagers();
for(int i = 0; i < tms.length; i++)
if(tms[i] instanceof X509TrustManager)
tms[i] = new CustomTrustManager((X509TrustManager)tms[i]);
return tms;
}
static TrustManager[] getTrustManagers()
throws NoSuchAlgorithmException, KeyStoreException
{
return getTrustManagers(null, null);
}
I have looked everywhere, but can't seem to find a solution please help.

I found my error, because do connection.setDoInput(true) it silencly sets my Requestmethod to post in version 4 which gives an error on the server causing it to return bad request.
apparently it does not set this in version 2, which explains why it does work there.
The following execute request method change fixed my code:
private String executeRequest(String urlAddress)
{
String responce = null;
String msg = null;
int error = 0;
try {
URL url = new URL(urlAddress);
HttpsURLConnection connection = (HttpsURLConnection)url.openConnection();
SSLSocketFactory factory = SecureSocketFactory.getSSLSocketFactory();
connection.setSSLSocketFactory(factory);
connection.setHostnameVerifier(new Verifier());
if (method == RequestMethod.POST)
{
connection.setDoOutput(true);
connection.setRequestMethod("POST");
}
else
{
connection.setDoInput(true);
connection.setRequestMethod("GET");
}
msg = connection.getResponseMessage();
error = connection.getResponseCode();
if ("OK".equals(msg))
{
InputStream content = (InputStream) connection.getContent();
responce = convertStreamToString(content);
}
else
{
responce = "Error " + error;
}
connection.disconnect();
} catch (Exception e) {
responce = e.toString();
}
return responce;
}

Related

Get response body 401 spring

I'm consuming a service using Spring's Rest Template. I'm getting error 401 in response: [no body]. But I'm doing the same query by postman, and I get the body. can anybody help me?
code:
private static List<AcervoMarcSecao> assinar(List<AcervoMarcSecao> acervosMarcSecao, byte[] imgAssinatura) throws ClientException, IOException {
restTemplate = new RestTemplate();
ResponseEntity<String> response = null;
HttpEntity<?> request = getHttpEntity(acervosMarcSecao, imgAssinatura);
try {
response = restTemplate
.exchange(parametros.get("SERVICE_HUB2_BASE_URL") + "/fw/v1/pdf/kms/lote/assinaturas",
HttpMethod.POST, request, String.class);
if(response.getBody() != null) {
LoteAssinaturaDTO loteAssinatura = new Gson().fromJson(response.getBody(), LoteAssinaturaDTO.class);
for(int i = 0; i < acervosMarcSecao.size(); i++) {
byte[] documentoAssinado = ImageRecover.recoverImageFromUrl(loteAssinatura.getDocumentos().get(i)
.getLinks().get(0).getHref());
if(documentoAssinado != null)
if(acervosMarcSecao.get(i).getVinculo() == null)
acervosMarcSecao.get(i).setVinculo(new Vinculos());
acervosMarcSecao.get(i).getVinculo().setArquivoAssinado(documentoAssinado);
acervosMarcSecao.get(i).getVinculo().setDataGravacao(new Date());
}
}
return acervosMarcSecao;
} catch (RestClientResponseException e) {
ErrorDTO error = new Gson().fromJson(e.getResponseBodyAsString(), ErrorDTO.class);
if(error.getChave().equals("excecao.hub.perfil")) {
throw new AlertaException(resourceBundle.getString("lblTipoAssinaturaDigitalInvalida"));
}
throw new AlertaException(error.getMessage());
} catch (Exception e) {
throw new AlertaException(resourceBundle.getString("txtErroCertificarArquivo"));
}
}
postman:

why does my return statement return a null result?

I am trying to connect to a distant machine and display some files from a specific directory.
The problem is when I test my function it returns a null result and what I want to do is to display file names.
Here is my code:
#Service
public class SftpClientImpl implements SftpClient {
private LsEntry entry;
#Override
public LsEntry connectToServer() {
String SFTPHOST = "xxxxx";
int SFTPPORT = 22;
String SFTPUSER = "xxx";
String SFTPPASS = "xxxxx";
String SFTPWORKINGDIR = "/dir/dir2/dir3";
Session session = null;
Channel channel = null;
ChannelSftp channelSftp = null;
try{
JSch jsch = new JSch();
session = jsch.getSession(SFTPUSER,SFTPHOST,SFTPPORT);
session.setPassword(SFTPPASS);
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
session.setConfig(config);
session.connect();
channel = session.openChannel("sftp");
channel.connect();
System.out.println("Starting the session ..");
channelSftp = (ChannelSftp)channel;
channelSftp.cd(SFTPWORKINGDIR);
Vector filelist = channelSftp.ls(SFTPWORKINGDIR);
for(int i=0; i<filelist.size();i++){
LsEntry entry = (LsEntry) filelist.get(i);
System.out.println(entry.getFilename());
}
while(session != null){
System.out.println("Killing the session");
session.disconnect();
System.exit(0);
}
}catch(Exception ex){
ex.printStackTrace();
}
return entry;
}
}
and:
#GetMapping(produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<LsEntry> getDirectories() {
LsEntry entry = sftpClient.connectToServer();
return new ResponseEntity<>(entry, HttpStatus.OK);
}
Any idea why this is not working?
entry is null as it's value is only contained within the for loop, and is actually declared twice (once with private class scope, once with local scope within the for loop).
What I suggest is to correct your variable declaration and test the connection and filename printing. If it still doesn't work, try it within a known working spring endpoint. If it prints your directory as expected than move to its own endpoint and try again. In doing this it'll help narrow down the scope of your issue.
I've used the below code to connect to and print file names for the past few years and is heavily based on the example code provided by JSCH back then:
JSch jsch = new JSch();
Session session;
session = jsch.getSession(username, hostname, port);
session.setConfig("StrictHostKeyChecking", "no");
session.setPassword(password);
session.connect();
Channel channel = session.openChannel("sftp");
channel.connect();
ChannelSftp sftpChannel = (ChannelSftp) channel;
//List our files within the directory
Vector vv = sftpChannel.ls(srcDir);
if (vv != null) {
LOGGER.debug("We have a file listing!");
for (int ii = 0; ii < vv.size(); ii++) {
Object obj = vv.elementAt(ii);
if (obj instanceof ChannelSftp.LsEntry) {
LOGGER.debug("[" + ((ChannelSftp.LsEntry) obj).getFilename() + "]");
if (ii < 1) { // empty directory contains entries for . and ..
continue;
}
String filename = ((ChannelSftp.LsEntry) obj).getFilename();
filenames.add(filename);
LOGGER.debug("filename is: {}", filename);
....
this is how i solved my problem :)
I corrected my variable declaration and it worked nicely, like you told me to :) thanks
#Override
public LsEntry connectToServer() {
String HOST = "xxxxx";
int PORT = 22;
String USER = "xxx";
String PASS = "xxxxx";
String DIR = "/dir/dir2/dir3";
Session session = null;
Channel channel = null;
ChannelSftp channelSftp = null;
// LsEntry declaration
LsEntry entry = null;
try {
JSch jsch = new JSch();
session = jsch.getSession(USER, HOST, PORT);
session.setPassword(PASS);
// the rest of the code
//....
//...
for (int i = 0; i < filelist.size(); i++) {
//cast
entry = (LsEntry) filelist.get(i);
System.out.println(((LsEntry) entry).getFilename());
}
while (session != null) {
System.out.println("Killing the session");
session.disconnect();
System.exit(0);
}
} catch (Exception ex) {
ex.printStackTrace();
}
return (LsEntry) entry;
}

SSLException:Write error: ssl=0x7f8170c780: I/O error during system call, Connection timed out

I use okhttp and retrofit2 to post a audio file,but sometimes the file broken (server side),What is the reason?
File file = new File(path);
RequestBody requestFile = RequestBody.create(MediaType.parse("audio/*"), file);
body = MultipartBody.Part.createFormData("audio_file", file.getName(), requestFile);
HashMap<String,RequestBody> params = new HashMap<>();
params.put("lecture_id",RequestBody.create(MediaType.parse("multipart/form-data"), mId + ""));
params.put("duration",RequestBody.create(MediaType.parse("multipart/form-data"),attachment.getDuration() + ""));
params.put("reply_message_id",RequestBody.create(MediaType.parse("multipart/form-data"),msg.getReplyMsgId() + ""));
Subscription subscription = ApiService.getInstance().sendAudioMessage(body,params).subscribe(new HttpObserver<IMMessage>() {
#Override
protected void onError(ApiException ex) {
CrashReport.postCatchedException(ex);
ToastUtil.showToast(getActivity(),ex.getMsg());
onSendMessageFail(msg);
}
#Override
public void onNext(IMMessage imMessage) {
onSendMessageSuccess(msg);
}
});
mCompositeSubscription.add(subscription);

HttpsURLConnection for rest service call

i am using HttpsURLConnection for calling POST method and i am unable to add request payload to the call. same request works when i execute manually from soapui tool. does any one know how to do this?
Here is the java code is am using:
// Keystore
String jksFile = "/Users/......jks";
String password = "password";
System.setProperty("javax.net.ssl.keyStore", jksFile);
System.setProperty("javax.net.ssl.keyStorePassword", password);
String u = "https://example.com:443/private/loan-application";
URL url = new URL(u);
String version = "3";
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setUseCaches(false);
conn.setConnectTimeout(10000);
conn.setReadTimeout(10000);
conn.setRequestProperty("Accept", "application/json;v=" + version);
conn.setRequestProperty("Api-Key", "XYZ");
String jsonParamString = "{\"didNumber\":\"DI457\", \" .... ";
//Create JSONObject here
JSONObject jsonParam = new JSONObject();
byte[] postData = jsonParamString.toString().getBytes();
Map<String, List<String>> requestProperties = conn.getRequestProperties();
displayHeaders(requestProperties);
OutputStream out = conn.getOutputStream();
out.write(postData);
out.close();
int respCode = conn.getResponseCode();
System.out.println("Response headers:");
displayHeaders(
conn.getHeaderFields());
InputStream is = null;
if (respCode == 200 || respCode == 203) {
is = conn.getInputStream();
}
if (is == null) {
System.out.println("Using error stream");
is = conn.getErrorStream();
}
is.close();
One possible explanation for why your HttpsURLConnection call is failing is that you have not configured your SSL settings properly. Specifically, the domain example.com is presenting a certificate which is not in your trust store, and therefore your program is failing during the SSL handshake. Try adding the following code, which will configure your program to trust all certificates:
SSLContext sslContext = SSLContext.getInstance("TLS");
TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { }
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { }
public X509Certificate[] getAcceptedIssuers() { return null; }
};
sslContext.init(null, new TrustManager[]{tm}, null);
conn.setSSLSocketFactory(sslContext.getSocketFactory());
Note that you should probably not use this code in production, because it accepts any site as secure. In production, you should configure your program to only accept trusted certificates.

Proxy Username/Password in Apache HttpClient

I'm looking to perform a GET on the yahoo currency rate service via Apache HttpClient 4.1.2, but I'm getting an UknownHostException when I'm accessing via company firewall. The code works fine when I try it from home(without any proxy config, of course), though.
Also, the URL opens on my browser, but can't be pinged from command prompt.
A sample URL is http://quote.yahoo.com/d/quotes.csv?f=l1&s=USDINR=X
EDIT 2: Here's the complete code I used to connect to the Yahoo finance service:
GetRate.java
public class GetRate {
public static void main(String[] args) {
final String FROM = "USD";
final String TO = "INR";
ArrayList<String> paramsList = new ArrayList<String>();
paramsList.add(FROM + TO);
System.out.println("Tracking "+ TO + " vs. " + FROM + " Exchange Rate...");
try {
double _new = new Double(RestClient.doGet(paramsList));
double _old = _new;
while(true) {
_new = new Double(RestClient.doGet(paramsList));
if(_old != _new)
_old = _new;
Thread.sleep(1000);
}
} catch (HttpException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
RestClient.java
public class RestClient {
public static final int HTTP_OK = 200;
public static final String SERVER_URL = "http://quote.yahoo.com/d/quotes.csv";
public static final String DEFAULT_ENCODING = "UTF-8";
public static String doGet(final ArrayList<String> params) throws HttpException,
IOException, URISyntaxException {
DefaultHttpClient httpClient = new DefaultHttpClient();
HttpConnectionParams
.setConnectionTimeout(httpClient.getParams(), 10000);
httpClient = proxyConfig(httpClient);
HttpHost targetHost = new HttpHost(SERVER_URL);
String urlParams = "?f=l1";
if(!params.isEmpty()) {
for(String param : params) {
String paramString = "s=" + URLEncoder.encode(param, DEFAULT_ENCODING) + "=X";
urlParams += (urlParams.length() > 1) ? ("&" + paramString) : paramString;
}
}
HttpGet httpget = new HttpGet(urlParams);
System.out.println("Final URL: " + httpget.getURI().toString());
HttpResponse response = httpClient.execute(targetHost, httpget);
HttpEntity entity = response.getEntity();
InputStream instream = entity.getContent();
return read(instream);
}
private static String read(InputStream in) throws IOException {
StringBuilder sb = new StringBuilder();
BufferedReader r = new BufferedReader(new InputStreamReader(in), 1000);
for (String line = r.readLine(); line != null; line = r.readLine()) {
sb.append(line + ",");
}
in.close();
return sb.toString().substring(0, sb.length() - 1);
}
/** Proxy config Approach 1 */
private static DefaultHttpClient proxyConfig(DefaultHttpClient httpClient) {
AuthScope auth = new AuthScope("proxy.tcs.com", 8080);
Credentials creds = new UsernamePasswordCredentials("USER_NAME", "PASSWORD");
httpClient.getCredentialsProvider().setCredentials(auth, creds);
return httpClient;
}
} for(String param : params) {
String paramString = "s=" + URLEncoder.encode(param, DEFAULT_ENCODING) + "=X";
urlParams += (urlParams.length() > 1) ? ("&" + paramString) : paramString;
}
}
HttpGet httpget = new HttpGet(urlParams);
HttpResponse response = httpClient.execute(targetHost, httpget);
HttpEntity entity = response.getEntity();
InputStream instream = entity.getContent();
Approach 2: I also tried the following proxy config, but couldn't find out how to add the username/password.
/** Proxy config Approach 2 */
HttpHost proxy = new HttpHost("PROXY_HOST", PROXY_PORT);
httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
Thanks,
Debojit
EDIT 1:
Stacktrace for Approach 1:
java.net.UnknownHostException: http://quote.yahoo.com/d/quotes.csv
at java.net.Inet6AddressImpl.lookupAllHostAddr(Native Method)
at java.net.InetAddress$1.lookupAllHostAddr(Unknown Source)
at java.net.InetAddress.getAddressFromNameService(Unknown Source)
at java.net.InetAddress.getAllByName0(Unknown Source)
at java.net.InetAddress.getAllByName(Unknown Source)
at java.net.InetAddress.getAllByName(Unknown Source)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.resolveHostname(DefaultClientConnectionOperator.java:242)
at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:130)
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:776)
at ws.client.RestClient.doGet(RestClient.java:48)
at ws.client.GetRate.main(GetRate.java:22)
Stacktrace for Approach 2:
Exception in thread "main" java.lang.NumberFormatException: For input string: "<HEAD><TITLE>Proxy Authorization Required</TITLE></HEAD>,<BODY BGCOLOR="white" FGCOLOR="black"><H1>Proxy Authorization Required</H1><HR>,<FONT FACE="Helvetica,Arial"><B>,Description: Authorization is required for access to this proxy</B></FONT>,<HR>,<!-- default "Proxy Authorization Required" response (407) -->,</BODY>,"
at sun.misc.FloatingDecimal.readJavaFormatString(Unknown Source)
at java.lang.Double.valueOf(Unknown Source)
at java.lang.Double.<init>(Unknown Source)
at ws.client.GetRate.main(GetRate.java:22)
The thing is, I'm not sure where the code is getting the HTML as input, and why.
Are you using "PROXY_HOST" literally for proxy constructor? If so, you have to use the proxy host in your browser configuration. Same for PROXY_PORT.
You will not be able to ping Yahoo from Your company because of the firewall, but you can access through your browser because it is configured to use a proxy server.

Resources