HttpURLConnection.getReadTimeout() / HttpURLConnection.getConnectionTimeout() of -1 - java

I'm trying to determine what the current readTimeout and connectionTimeout is on my Java HttpURLConnection object. They are both returning a -1 with during the logging statements below:
private InputStream getSomethingImportant(final String letterId, final String documentId,
HttpURLConnection connection) throws IOException {
InputStream pdfStream = null;
final String url = this.getBaseURL() + "/letters/" + letterId + "/documents/" + documentId;
connection = RequestResponseUtil.initializeRequest(url, "GET", this.getAuthenticationHeader(), true, MediaType.APPLICATION_PDF_VALUE);
LOG.info("ConnectionTimeout is: {}", connection.getConnectTimeout());
LOG.info("ReadTimeout is: {}", connection.getReadTimeout());
// ...other non-relevant code...
}
public static HttpURLConnection initializeRequest(final String url, final String method,
final String httpAuthHeader, final boolean multiPartFormData, final String responseType) {
HttpURLConnection conn = null;
try {
conn = (HttpURLConnection) new URL(url).openConnection();
conn.setRequestMethod(method);
conn.setRequestProperty("X-Something-Authentication", httpAuthHeader);
conn.setRequestProperty("Accept", responseType);
if (multiPartFormData) {
conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=BOUNDARY");
conn.setDoOutput(true);
}
else {
conn.setRequestProperty("Content-Type", "application/xml");
}
}
catch (final MalformedURLException e) {
throw new CustomException(e);
}
catch (final IOException e) {
throw new CustomException(e);
}
return conn;
}
The JavaDocs on getConnectTimeout and getReadTimeout both list 0 as a return option but say nothing about -1. How should I interpret this?
Also, the url I am using is valid and I am returning an InputStream successfully.
Finally, I am using Oracle JDK 1.8.0_77. And, of note, when I actually print out the conn class that is being used at runtime it is weblogic.net.http.SOAPHttpsURLConnection (I am using WebLogic 12.2).
Thank you.

Related

How to send post request in java with a JSON body

I am confused as to how to send a post request in Java with JSON parameters. I have seen many examples that use HttpPost library which I can not access. Below is my code:
public class endpointtest {
public String endpoint(String urlStr, String username) {
final StringBuilder response = new StringBuilder();
try {
//creating the connection
URL url = new URL(urlStr);
HttpClient client = HttpClient.newHttpClient();
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");
connection.connect();
//builds the post body, adds parameters
final DataOutputStream out = new DataOutputStream(connection.getOutputStream());
//out.writeBytes(toJSON(globalId));
out.flush();
out.close();
//Reading the response
BufferedReader in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
String inputline;
while ((inputline = in.readLine()) != null) {
response.append(inputline);
}
in.close();
connection.getResponseCode();
connection.disconnect();
} catch (final Exception ex) {
ex.printStackTrace();
System.out.println(" error ");
}
return response.toString();
}
}
class main {
public static void main(String[] args){
endpointtest ep = new endpointtest();
ep.endpoint("localhost:8080/endpoint","""
{
"name": "mike",
"Id": "123"
}
""");
}
}
I am trying to pass the json in the main method (I know I am not doing it right), and was wondering as to how I would do this correctly.
This is the simplest way to do it.
public class Main {
public static void main(String[] args) throws IOException {
String apiUrl = "http://myserver/rest/V1.0/manage/export"; // Your api/http link
String userName = "admin"; // Your username
String password = "adminpro"; // Your password
sendRequest(basicUrl, userName, password);
}
public static void sendRequest(String apiurl,String userName,String password){
try{
URL url = new URL(apiurl);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type","application/json");
connection.setRequestProperty("Accept", "application/json");
connection.setRequestProperty("Authorization", "Basic " + Base64.getEncoder().encodeToString((userName + ":" + password).getBytes()));
String payload = "{\"sampleKey\":\"sampleValue\"}";// This should be your json body i.e. {"Name" : "Mohsin"}
byte[] out = payload.getBytes(StandardCharsets.UTF_8);
OutputStream stream = connection.getOutputStream();
stream.write(out);
System.out.println(connection.getResponseCode() + " " + connection.getResponseMessage()); // THis is optional
connection.disconnect();
}catch (Exception e){
System.out.println(e);
System.out.println("Failed successfully");
}
}
}
This Question is asked before here:
HTTP POST using JSON in Java
See it and comment this if you face any problem.

Re try method on certain exceptions

I have the following method which uses a proxy to retrieve information from a server. Sometimes due to a bad proxy I get SocketException, SSLException, SSLHandshakeException or ConnectException
As you can see in my method I am already using catch (IOException ioe) I need to do that in order to get the contents of server response if the server returns anything other than code 200.
How can I make the method retry in case of the above exceptions?
public String getMeta() throws IOException
{
HttpsURLConnection con = null;
InputStream is = null;
StringWriter writer = new StringWriter();
try
{
String url = "https://api.myapp.com/meta";
URL urlObj = new URL(url);
if (useProxy && fullProxy)
{
myapp.Proxy proxyCustom = getRandomProxy();
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyCustom.getProxyIp(), proxyCustom.getProxyPort()));
con = (HttpsURLConnection) urlObj.openConnection(proxy);
}
else
{
con = (HttpsURLConnection) urlObj.openConnection();
}
con.setRequestMethod("GET");
con.setRequestProperty("User-Agent", USER_AGENT);
con.setRequestProperty("Content-Type", "application/json; charset=utf-8");
con.setRequestProperty("host", urlObj.getHost());
con.setRequestProperty("Connection", "Keep-Alive");
int responseCode = 0;
responseCode = con.getResponseCode();
is = con.getInputStream();
writer = new StringWriter();
IOUtils.copy(is, writer, "UTF-8");
}
catch (IOException ioe)
{
if (con instanceof HttpsURLConnection)
{
HttpsURLConnection httpConn = (HttpsURLConnection) con;
int statusCode = httpConn.getResponseCode();
if (statusCode != 200)
{
is = httpConn.getErrorStream();
writer = new StringWriter();
IOUtils.copy(is, writer, "UTF-8");
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
return writer.toString();
}
How can I make the method retry in case of the above exceptions?
One way shown below is to have the getMeta method actually throw the IOException. You can then then have a caller method recursively call itself due to any caught Exception.
I hope there is an simple way of setting how times it should retry
To be able to call the method n number of times, pass in the number of times as an argument and deal with the stopping criteria logic accordingly. For example:
public String caller(int total) throws IOException{
return callerImpl(1, total);
}
public String callerImpl(int current, int total) throws IOException{
try{
return getMeta();
}catch(IOException e){
current++;
if ( current > total ){
throw e;//or return null or empty string, depending upon upstream requirements
}
return callerImpl(current, total);
}
return null;
}
In getMeta:
try{
....
}catch(IOException io){
//log or handle io
throw io;
}
Note the above doesn't deal with the logging/logic of the thrown exceptions, which you may want to handle in some way.
The way I would do is create a new retry method and invoke it at the end of your getMeta() method so it is called in only in case of abnormalities
I am assuming you should call the retry only a few times and hence getMeta should throw some exception like RetryException after certain number of times
public String getMeta() throws IOException, RetryException
{
HttpsURLConnection con = null;
InputStream is = null;
StringWriter writer = new StringWriter();
try
{
String url = "https://api.myapp.com/meta";
URL urlObj = new URL(url);
if (useProxy && fullProxy)
{
myapp.Proxy proxyCustom = getRandomProxy();
Proxy proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyCustom.getProxyIp(), proxyCustom.getProxyPort()));
con = (HttpsURLConnection) urlObj.openConnection(proxy);
}
else
{
con = (HttpsURLConnection) urlObj.openConnection();
}
con.setRequestMethod("GET");
con.setRequestProperty("User-Agent", USER_AGENT);
con.setRequestProperty("Content-Type", "application/json; charset=utf-8");
con.setRequestProperty("host", urlObj.getHost());
con.setRequestProperty("Connection", "Keep-Alive");
int responseCode = 0;
responseCode = con.getResponseCode();
is = con.getInputStream();
writer = new StringWriter();
IOUtils.copy(is, writer, "UTF-8");
return writer.toString();
}
catch (IOException ioe)
{
if (con instanceof HttpsURLConnection)
{
HttpsURLConnection httpConn = (HttpsURLConnection) con;
int statusCode = httpConn.getResponseCode();
if (statusCode != 200)
{
is = httpConn.getErrorStream();
writer = new StringWriter();
IOUtils.copy(is, writer, "UTF-8");
return writer.toString();
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
return retryGetMeta();
}
private String retryGetMeta()
{
try
{
return getMeta();
}
finally
{
//Do your stuff
}
}
public RetryException extends Exception
{
private String message = "Retries exceeded";
public String getMessage()
{
return message;
}
}
If an exception is thrown in your getMeta(), catch will do its stuff as you are doing now, but after that , retryGetMeta will be called

InputStream being lost

I have a class titled: ServiceCaller.java
This class contains a method used to call web services:
public static Response callService(String strURL, String Token, int timeout, Boolean isPostMethod) {
String error = "";
int statusCode = HttpStatus.SC_INTERNAL_SERVER_ERROR;
HttpURLConnection urlConnection = null;
try
{
URL url = new URL(strURL);
// Allow non trusted ssl certificates
if(strURL.startsWith("https"))
{
TrustManagerManipulator.allowAllSSL();
}
urlConnection = (HttpURLConnection) url.openConnection();
if (isPostMethod) {
urlConnection.setRequestMethod("POST");
}
else {
urlConnection.setRequestMethod("GET");
}
// Allow Inputs
urlConnection.setDoInput(true);
// Allow Outputs
urlConnection.setDoOutput(true);
// Don't use a cached copy.
urlConnection.setUseCaches(false);
urlConnection.setRequestProperty("Connection", "Keep-Alive");
urlConnection.setRequestProperty("Content-Type", "application/json");
urlConnection.setRequestProperty("Token", Helpers.getUTF8Encode(Token));
urlConnection.setConnectTimeout(timeout);
DataOutputStream dos = new DataOutputStream(urlConnection.getOutputStream());
dos.flush();
dos.close();
statusCode = urlConnection.getResponseCode();
Response r = new Response(statusCode, urlConnection.getInputStream(), "No Exception");
return r;
} catch (Exception ex) {
error = ex.getMessage();
if (error != null && !error.equals("") && error.contains("401"))
statusCode = HttpStatus.SC_UNAUTHORIZED;
} finally {
urlConnection.disconnect();
}
return new Response(statusCode, null, error);
}
Here's the Response class:
public static class Response
{
private int statusCode;
private InputStream responseStream;
private String exception;
public int getStatusCode() {
return statusCode;
}
public InputStream getResponseStream() {
return responseStream;
}
public String getExceptionError() {
return exception;
}
public Response(int code, InputStream stream, String strException)
{
this.statusCode = code;
this.responseStream = stream;
this.exception = strException;
}
}
This is the Test class that I use to test the function in ServiceCaller:
public class TestDemo {
private static final String EncriptionKey = "keyValueToUse";
public static void main(String[] args) {
try {
String strURL = "http://...";
String strURL2 = "http://...";
String Token = "iTcakW5...";
int timeout = 120000;
Boolean isPostMethod = true;
ServiceCaller.Response resp = ServiceCaller.CallService(strURL2, Token, timeout, isPostMethod);
InputStream inputStream = resp.getResponseStream();
StringWriter writer = new StringWriter();
IOUtils.copy(inputStream, writer);
String resultJSON = writer.toString();
System.out.println("Status Code: " + resp.getStatusCode());
System.out.println("JSON String:\n" + resultJSON);
System.out.println("Exception: " + resp.getExceptionError());
} catch (Exception e) {
e.printStackTrace();
}
}
}
Here's the Output of executing hte previous code:
Status Code: 200
JSON String:
Exception: No Exception
Here's the problem, the InputString that is returned in the Test class appears to be empty because the conversion to string returns an empty string BUT if I do the same code to convert the InputString inside the CallService function then the conversion is successful, also note that the Status Code and Exception (strings) are being returned correctly.
public static Response CallService(String strURL, String Token, int timeout, Boolean isPostMethod) {
HttpURLConnection urlConnection = ...
...
new Response(statusCode, urlConnection.getInputStream(), "No Exception");
}
This code missing in the ... is probably the most important part. I guess you are closing the HttpURLConnection before returning back to the caller. How you do this can vary:
You simply close it before the return
try-catch-finally: You are closing it in the finally block.
you are using a try-with-resource construction as introduced in Java 7. The HttpURLConnection might be getting closed automatically. This is more unlikely since HttpURLConnection does not implement AutoClosable.
I've solved by first getting the InputStream from HttpURLConnection, then converting it to a byte array, then putting that byte array into a ByteArrayInputStream
byte[] bytes = IOUtils.toByteArray(urlConnection.getInputStream());
ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes);
return new Response(statusCode, byteStream, "");
According to the documentation a ByteArrayInputStream:
public ByteArrayInputStream(byte[] buf) Creates a ByteArrayInputStream
so that it uses buf as its buffer array. The buffer array is not
copied. The initial value of pos is 0 and the initial value of count
is the length of buf. Parameters: buf - the input buffer.
The problem is that you are already consuming the InputStream in your CallService method
statusCode = urlConnection.getResponseCode();
Response resp = new Response(statusCode, urlConnection.getInputStream(), "");
InputStream inputStream = resp.getResponseStream();
StringWriter writer = new StringWriter();
IOUtils.copy(inputStream, writer); // consuming the stream
String resultJSON = writer.toString(); // you never use this, so why is it here?
So when you try to read from it again in main() there are no bytes left.
You can only read bytes from it once.
This doesn't throw any exceptions because IOUtils simply calls InputStream#read(...) which returns -1 if the EOF has been reached.
Note that Java naming convention states that method names should start with a lowercase character.

Should i use Same HttpUrlconnection or define each time a new one?

I am using HttpUrlConnect to post data to a webservice .
This posting of data will happen , whenever there is any logging event called .(so this is continous)
I have a question with respect to this , should i use the same HttpURLConnection as shown below
private HttpURLConnection getConnection() throws Exception {
URL url = new URL("http://localhost:8080/RestTest/ajax/user_info");
HttpURLConnection conn = null;
conn = (HttpURLConnection) url.openConnection();
return conn;
}
public void execute() throws Exception {
OutputStream os = null;
try {
HttpURLConnection conn = null;
conn = getConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
String input = "{\\\"qty\\\":100,\\\"name\\\":\\\"sdsfds ddd\\\"}";
os = conn.getOutputStream();
os.write(input.getBytes());
os.flush();
conn.getInputStream();
} catch (Exception e) {
e.printStackTrace();
}
finally {
if (os != null) {
os.close();
}
}
}
Or should i define connection everythime as shown below ??
public void execute() throws Exception {
OutputStream os = null;
HttpURLConnection conn = null;
try {
URL url = new URL("http://localhost:8080/RestTest/ajax/user_info");
conn = (HttpURLConnection) url.openConnection();
conn.setDoOutput(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
String input = "{\\\"qty\\\":100,\\\"name\\\":\\\"sdsfds ddd\\\"}";
os = conn.getOutputStream();
os.write(input.getBytes());
os.flush();
conn.getInputStream();
} catch (Exception e) {
e.printStackTrace();
}
finally {
conn.disconnect();
if (os != null) {
os.close();
}
}
}
Please tell me what is appropiate in this context ??
HttpURLConnection's javadoc says:
Each HttpURLConnection instance is used to make a single request but the underlying network connection to the HTTP server may be transparently shared by other instances.
So, although in the background the connection could be the same, you should use a new intance per request.

java urlconnection get the final redirected URL

I have a url which redirects to another url.I want to be able to get the final redirected URL.My code:
public class testURLConnection
{
public static void main(String[] args) throws MalformedURLException, IOException {
HttpURLConnection con =(HttpURLConnection) new URL( "http://tinyurl.com/KindleWireless" ).openConnection();
System.out.println( "orignal url: " + con.getURL() );
con.connect();
System.out.println( "connected url: " + con.getURL() );
InputStream is = con.getInputStream();
System.out.println( "redirected url: " + con.getURL() );
is.close();
}
}
It always gives original url whereas the redirectURL is:http://www.amazon.com/Kindle-Wireless-Reading-Display-Globally/dp/B003FSUDM4/ref=amb_link_353259562_2?pf_rd_m=ATVPDKIKX0DER&pf_rd_s=center-10&pf_rd_r=11EYKTN682A79T370AM3&pf_rd_t=201&pf_rd_p=1270985982&pf_rd_i=B002Y27P3M.
How can i get this final redirected URL.
Here is what i tried with looping till we get redirects.Still doesent fetch the desired url:
public static String fetchRedirectURL(String url) throws IOException
{
HttpURLConnection con =(HttpURLConnection) new URL( url ).openConnection();
//System.out.println( "orignal url: " + con.getURL() );
con.setInstanceFollowRedirects(false);
con.connect();
InputStream is = con.getInputStream();
if(con.getResponseCode()==301)
return con.getHeaderField("Location");
else return null;
}
public static void main(String[] args) throws MalformedURLException, IOException {
String url="http://tinyurl.com/KindleWireless";
String fetchedUrl=fetchRedirectURL(url);
System.out.println("FetchedURL is:"+fetchedUrl);
while(fetchedUrl!=null)
{ url=fetchedUrl;
System.out.println("The url is:"+url);
fetchedUrl=fetchRedirectURL(url);
}
System.out.println(url);
}
Try this, I using recursively to using for many redirection URL.
public static String getFinalURL(String url) throws IOException {
HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
con.setInstanceFollowRedirects(false);
con.connect();
con.getInputStream();
if (con.getResponseCode() == HttpURLConnection.HTTP_MOVED_PERM || con.getResponseCode() == HttpURLConnection.HTTP_MOVED_TEMP) {
String redirectUrl = con.getHeaderField("Location");
return getFinalURL(redirectUrl);
}
return url;
}
and using:
public static void main(String[] args) throws MalformedURLException, IOException {
String fetchedUrl = getFinalURL("<your_url_here>");
System.out.println("FetchedURL is:" + fetchedUrl);
}
public static String getFinalRedirectedUrl(String url) {
HttpURLConnection connection;
String finalUrl = url;
try {
do {
connection = (HttpURLConnection) new URL(finalUrl)
.openConnection();
connection.setInstanceFollowRedirects(false);
connection.setUseCaches(false);
connection.setRequestMethod("GET");
connection.connect();
int responseCode = connection.getResponseCode();
if (responseCode >= 300 && responseCode < 400) {
String redirectedUrl = connection.getHeaderField("Location");
if (null == redirectedUrl)
break;
finalUrl = redirectedUrl;
System.out.println("redirected url: " + finalUrl);
} else
break;
} while (connection.getResponseCode() != HttpURLConnection.HTTP_OK);
connection.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
return finalUrl;
}
My first idea would be setting instanceFollowRedirects to false, or using URLConnection instead.
In both cases, the redirect won't be executed, so you will receive a reply to your original request. Get the HTTP Status value and, if it is 3xx, get the new redirect value.
Of course there may be a chain of redirects, so probably you will want to iterate until you reach the real (status 2xx) page.
#user719950 On my MAC-OSX - this solves the issue of truncated HTTP URL :
To your original code , just add this below line : // You have to find through your browser what is the Request Header IE / Chrome is sending. I still dont have the explanation as why this simple setting is causing correct URL :)
HttpURLConnection con =(HttpURLConnection) new URL
( "http://tinyurl.com/KindleWireless" ).openConnection();
con.setInstanceFollowRedirects(true);
con.setDoOutput(true);
System.out.println( "orignal url: " + con.getURL() );
**con.setRequestProperty("User-Agent",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_2)
AppleWebKit/536.26.17 (KHTML, like Gecko) Version/6.0.2
Safari/536.26.17");**
con.connect();
System.out.println( "connected url: " + con.getURL() );
Thread.currentThread().sleep(2000l);
InputStream is = con.getInputStream();
System.out.println( "redirected url: " + con.getURL() );
is.close();
This might help
public static void main(String[] args) throws MalformedURLException,
IOException {
HttpURLConnection con = (HttpURLConnection) new URL(
"http://tinyurl.com/KindleWireless").openConnection(proxy);
System.out.println("orignal url: " + con.getURL());
con.connect();
con.setInstanceFollowRedirects(false);
int responseCode = con.getResponseCode();
if ((responseCode / 100) == 3) {
String newLocationHeader = con.getHeaderField("Location");
responseCode = con.getResponseCode();
System.out.println("Redirected Location " + newLocationHeader);
System.out.println(responseCode);
}
}
#JEETS
Your fetchRedirectURL function may not work because there are a variety of HTTP codes for redirects. Change it to a range check and it will work.
public static String fetchRedirectURL(String url) throws IOException
{
HttpURLConnection con =(HttpURLConnection) new URL( url ).openConnection();
//System.out.println( "orignal url: " + con.getURL() );
con.setInstanceFollowRedirects(false);
con.connect();
InputStream is = con.getInputStream();
if(con.getResponseCode()>=300 && con.getResponseCode() <400)
return con.getHeaderField("Location");
else return null;
}
This one goes recursively in case there are multiple redirects:
protected String getDirectUrl(String link) {
String resultUrl = link;
HttpURLConnection connection = null;
try {
connection = (HttpURLConnection) new URL(link).openConnection();
connection.setInstanceFollowRedirects(false);
connection.connect();
int responseCode = connection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_MOVED_PERM || responseCode == HttpURLConnection.HTTP_MOVED_TEMP) {
String locationUrl = connection.getHeaderField("Location");
if (locationUrl != null && locationUrl.trim().length() > 0) {
IOUtils.close(connection);
resultUrl = getDirectUrl(locationUrl);
}
}
} catch (Exception e) {
log("error getDirectUrl", e);
} finally {
IOUtils.close(connection);
}
return resultUrl;
}

Categories

Resources