I'm using a hessdroid proxy to communicate between my android application and my webservice/hessianservlet. It works immediatly after starting the app, but when I wait a minute and let the app call a network function again (e.g. logout()) I get this error message:
com.caucho.hessian.client.HessianConnectionException: 500: java.io.EOFException
at com.caucho.hessian.client.HessianProxy.invoke(HessianProxy.java:197)
at $Proxy1.getPassword(Native Method)
at tsch.serviceApp.net.DataHandler.getPassword(DataHandler.java:50)
at tsch.serviceApp.PageSystemApps$1$1.run(PageSystemApps.java:91)
Caused by: java.io.EOFException
at libcore.io.Streams.readAsciiLine(Streams.java:203)
at libcore.net.http.HttpEngine.readResponseHeaders(HttpEngine.java:573)
at libcore.net.http.HttpEngine.readResponse(HttpEngine.java:821)
at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:283)
at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:495)
at com.caucho.hessian.client.HessianProxy.invoke(HessianProxy.java:167)
.
public String login() {
HessianProxyFactory factory = new HessianProxyFactory();
String url = "http://192.168.56.1:8080/hessianServer";
factory.setHessian2Reply(false); // avoid hessian reply error
try {
userCon = (IUserService) factory.create(IUserService.class, url+"/IUserService");
} catch (MalformedURLException e) {
e.printStackTrace();
}
return "Logged in!";
}
public void logout() {
userCon.logout();
}
I runned into the same problem on android 4.1 ,but it's ok on android 4.0.3. I added a statement " conn.setRequestProperty("Connection", "Close");" in method openConnection of class HessianProxyFactory.
protected URLConnection openConnection(URL url)
throws IOException {
URLConnection conn = url.openConnection();
conn.setDoOutput(true);
if (_readTimeout > 0) {
try {
conn.setReadTimeout((int) _readTimeout);
} catch (Throwable e) { // intentionally empty
}
}
conn.setRequestProperty("Content-Type", "x-application/hessian");
conn.setRequestProperty("Connection", "Close");
if (_basicAuth != null)
conn.setRequestProperty("Authorization", _basicAuth);
else if (_user != null && _password != null) {
_basicAuth = "Basic " + base64(_user + ":" + _password);
conn.setRequestProperty("Authorization", _basicAuth);
}
return conn;
}
and the problem disappeared.
Used Flamingo instead of Hessdroid and everything works fine!
Related
I have a very simple method to get InputStream from url:
private InputStream request(String uri) {
Log.d(TAG, "initialize request: "+uri);
try {
URL url = new URL(uri));
Log.d(TAG, "initialize req: "+url);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
Log.d(TAG, "initialize open conn");
if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {
Log.d(TAG, "initialize return is");
return connection.getInputStream();
} else {
Log.d(TAG, "initialize: fail");
}
} catch (Exception e) {
e.printStackTrace();
}
Log.d(TAG, "initialize: what happened?");
return null;
}
and it used to work perfect. But now, when I'm trying to use it, for some reason it stops on 'connection.getResponseCode()'. Just stops, nothing else happens. The logs looks like this:
tag: initialize req: http://uri.provided.to.method
tag: initialize open conn
And that's it. It literally stops there and doesn't print or return anything else. Same effect for 'connection.getResponseMessage()'. Any ideas why it happens and how to fix it?
Ok, problem solved. Apparently connection was made too early, before the url was ready.
I'm writing a program that connects to a servlet thanks to a HttpURLConnection but I stuck while checking the url
public void connect (String method) throws Exception {
server = (HttpURLConnection) url.openConnection ();
server.setDoInput (true);
server.setDoOutput (true);
server.setUseCaches (false);
server.setRequestMethod (method);
server.setRequestProperty ("Content-Type", "application / xml");
server.connect ();
/*if (server.getResponseCode () == 200)
{
System.out.println ("Connection OK at the url:" + url);
System.out.println ("------------------------------------------- ------- ");
}
else
System.out.println ("Connection failed");
}*/
I got the error :
java.net.ProtocolException: Cannot write output after reading input.
if i check the url with the code in comments but it work perfectly without it
unfortunately, I need to check the url so i think the problem comes from the getResponseCode method but i don t know how to resolve it
Thank you very much
The HTTP protocol is based on a request-response pattern: you send your request first and the server responds. Once the server responded, you can't send any more content, it wouldn't make sense. (How could the server give you a response code before it knows what is it you're trying to send?)
So when you call server.getResponseCode(), you effectively tell the server that your request has finished and it can process it. If you want to send more data, you have to start a new request.
Looking at your code you want to check whether the connection itself was successful, but there's no need for that: if the connection isn't successful, an Exception is thrown by server.connect(). But the outcome of a connection attempt isn't the same as the HTTP response code, which always comes after the server processed all your input.
I think the exception is not due toprinting url. There should some piece of code which is trying to write to set the request body after the response is read.
This exception will occur if you are trying to get HttpURLConnection.getOutputStream() after obtaining HttpURLConnection.getInputStream()
Here is the implentation of sun.net.www.protocol.http.HttpURLConnection.getOutputStream:
public synchronized OutputStream getOutputStream() throws IOException {
try {
if (!doOutput) {
throw new ProtocolException("cannot write to a URLConnection"
+ " if doOutput=false - call setDoOutput(true)");
}
if (method.equals("GET")) {
method = "POST"; // Backward compatibility
}
if (!"POST".equals(method) && !"PUT".equals(method) &&
"http".equals(url.getProtocol())) {
throw new ProtocolException("HTTP method " + method +
" doesn't support output");
}
// if there's already an input stream open, throw an exception
if (inputStream != null) {
throw new ProtocolException("Cannot write output after reading
input.");
}
if (!checkReuseConnection())
connect();
/* REMIND: This exists to fix the HttpsURLConnection subclass.
* Hotjava needs to run on JDK.FCS. Do proper fix in subclass
* for . and remove this.
*/
if (streaming() && strOutputStream == null) {
writeRequests();
}
ps = (PrintStream)http.getOutputStream();
if (streaming()) {
if (strOutputStream == null) {
if (fixedContentLength != -) {
strOutputStream =
new StreamingOutputStream (ps, fixedContentLength);
} else if (chunkLength != -) {
strOutputStream = new StreamingOutputStream(
new ChunkedOutputStream (ps, chunkLength), -);
}
}
return strOutputStream;
} else {
if (poster == null) {
poster = new PosterOutputStream();
}
return poster;
}
} catch (RuntimeException e) {
disconnectInternal();
throw e;
} catch (IOException e) {
disconnectInternal();
throw e;
}
}
I have this problem too, what surprises me is that the error is caused by my added code System.out.println(conn.getHeaderFields());
Below is my code:
HttpURLConnection conn=(HttpURLConnection)url.openConnection();
conn.setRequestMethod("POST");
configureConnection(conn);
//System.out.println(conn.getHeaderFields()); //if i comment this code,everything is ok, if not the 'Cannot write output after reading input' error happens
conn.connect();
OutputStream os = conn.getOutputStream();
os.write(paramsContent.getBytes());
os.flush();
os.close();
I had the same problem.
The solution for the problem is that you need to use the sequence
openConnection -> getOutputStream -> write -> getInputStream -> read
That means..:
public String sendReceive(String url, String toSend) {
URL url = new URL(url);
URLConnection conn = url.openConnection();
connection.setDoInput(true);
connection.setDoOutput(true);
connection.sets...
OutputStreamWriter out = new OutputStreamWriter(conn.getOutputStream());
out.write(toSend);
out.close();
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String receive = "";
do {
String line = in.readLine();
if (line == null)
break;
receive += line;
} while (true);
in.close();
return receive;
}
String results1 = sendReceive("site.com/update.php", params1);
String results2 = sendReceive("site.com/update.php", params2);
...
I am trying to hit a web service. it is working fine with android 4.4 or android 5.X. but when i am trying to hit "http://inmotion-prod.cloudapp.net:145/service1.svc/json/GetCustomerUUID" using android 4.1.1 it always returning me 307 status code. but this url is working fine with android 4.4 or 5.x. i also tried to hit other url it is working fine on android 4.1.1.
so please tell me what is the problem
Log.i(TAG, url);
String response = null;
HttpURLConnection conn = null;
try {
URL webServiceUrl = new URL(url);
conn = (HttpURLConnection) webServiceUrl
.openConnection();
Log.i(TAG, "Connection open");
conn.setRequestMethod(GET);
conn.setConnectTimeout(CONNECTION_TIME_OUT);
conn.setRequestProperty(CONTENT_TYPE, contentType);
conn.setRequestProperty(ACCEPT_TYPE, acceptType);
conn.setDoInput(true);
conn.connect();
Log.i(TAG, "Connection Connected");
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK && conn.getInputStream() != null) {
response = StreamUtility.convertStreamToString(conn.getInputStream());
conn.getInputStream().close();
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (conn != null) {
conn.disconnect();
}
}
return response;
}
Replace your URL address with http://inmotion-prod.cloudapp.net:145/service1.svc/json/GetCustomerUUID/ (pay attention to / at the end). The response code will be 200.
UPDATE:
With your current URL address (http://inmotion-prod.cloudapp.net:145/service1.svc/json/GetCustomerUUID) without / at the end, you can use the following code:
String address = "http://inmotion-prod.cloudapp.net:145/service1.svc/json/GetCustomerUUID";
URL url = new URL(address);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setInstanceFollowRedirects(false);
// if print out (debug or logging), you will see secondURL has / at the end
URL secondURL = new URL(urlConnection.getHeaderField("Location"));
HttpURLConnection urlConnection1 = (HttpURLConnection) secondURL.openConnection();
Then use urlConnection1.getResponseCode()
Hope it helps!
BNK's answer helped, I fixed it like this so that it also works on newer devices (location header was returned as null / empty!)
String headerLocation = httpsUrlConnection.getHeaderField("Location");
logger.debug("Location header: " + headerLocation);
// if the redirect URL ends with a "/" sign, but the original URL does not, it's probably the redirect bug
String originalURL = url.toString();
if (!TextUtils.isEmpty(headerLocation) && headerLocation.endsWith("/") && !originalURL.endsWith("/"))
{
logger.info("Redirect Location differs from original URL, create new connection to: " + headerLocation);
httpsUrlConnection = (HttpsURLConnection) new URL(headerLocation).openConnection();
// optional
httpsUrlConnection.setSSLSocketFactory(sslSocketFactory);
}
I'm writing an Android app that connects to a cPanel server (Apache 2.2.22) page which is password protected. When the authentication credentials are correct, I have no problem connecting. However, when the credentials are incorrect, my Android application seems to freeze in the HttpURLConnection.getResponseCode() method. The logs on the server show hundreds of requests being sent from my Android device, all returning a 401 as expected, but for some reason this is not reflected in my application.
Here is my code, executed from within an AsyncTask:
#Override
protected Integer doInBackground(String... bookInfoString) {
// Stop if cancelled
if(isCancelled()){
return null;
}
Log.i(getClass().getName(), "SendToDatabase.doInBackground()");
String apiUrlString = getResources().getString(R.string.url_vages_library);
try{
NetworkConnection connection = new NetworkConnection(apiUrlString);
connection.appendPostData(bookInfoString[0]);
int responseCode = connection.getResponseCode();
Log.d(getClass().getName(), "responseCode: " + responseCode);
return responseCode;
} catch(IOException e) {
return null;
}
}
This code makes use of my own class NetworkConnection, which is just a basic wrapper class around an HttpURLConnection, to avoid repeating code. Here it is:
public class NetworkConnection {
private String url;
private HttpURLConnection connection;
public NetworkConnection(String urlString) throws IOException{
Log.i(getClass().getName(), "Building NetworkConnection for the URL \"" + urlString + "\"");
url = urlString;
// Build Connection.
try{
URL url = new URL(urlString);
connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setReadTimeout(1000 /* 1 seconds */);
connection.setConnectTimeout(1000 /* 1 seconds */);
} catch (MalformedURLException e) {
// Impossible: The only two URLs used in the app are taken from string resources.
e.printStackTrace();
} catch (ProtocolException e) {
// Impossible: "GET" is a perfectly valid request method.
e.printStackTrace();
}
}
public void appendPostData(String postData) {
try{
Log.d(getClass().getName(), "appendPostData() called.\n" + postData);
Log.d(getClass().getName(), "connection.getConnectTimeout(): " + connection.getConnectTimeout());
Log.d(getClass().getName(), "connection.getReadTimeout(): " + connection.getReadTimeout());
// Modify connection settings.
connection.setRequestMethod("POST");
connection.setDoOutput(true);
connection.setRequestProperty("Content-Type", "application/json");
// Get OutputStream and attach POST data.
OutputStreamWriter writer = new OutputStreamWriter(connection.getOutputStream(), "UTF-8");
writer.write(postData);
if(writer != null){
writer.flush();
writer.close();
}
} catch (SocketTimeoutException e) {
Log.w(getClass().getName(), "Connection timed out.");
} catch (ProtocolException e) {
// Impossible: "POST" is a perfectly valid request method.
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
// Impossible: "UTF-8" is a perfectly valid encoding.
e.printStackTrace();
} catch (IOException e) {
// Pretty sure this is impossible but not 100%.
e.printStackTrace();
}
}
public int getResponseCode() throws IOException{
Log.i(getClass().getName(), "getResponseCode()");
int responseCode = connection.getResponseCode();
Log.i(getClass().getName(), "responseCode: " + responseCode);
return responseCode;
}
public void disconnect(){
Log.i(getClass().getName(), "disconnect()");
connection.disconnect();
}
}
And finally, here is a fraction of the logcat logs:
05-03 11:01:16.315: D/vages.library.NetworkConnection(3408): connection.getConnectTimeout(): 1000
05-03 11:01:16.315: D/vages.library.NetworkConnection(3408): connection.getReadTimeout(): 1000
05-03 11:01:16.585: I/vages.library.NetworkConnection(3408): getResponseCode()
05-03 11:04:06.395: I/vages.library.MainActivity$SendToDatabase(3408): SendToDatabase.onPostExecute(null)
You can see the the method seems to just return null after a random amount of time. The longest I have waited was exactly 15 minutes. There are also several memory logs (GC_CONCURRENT) from dalikvm between the last two info logs which I have omitted.
I should also say that at the moment I am not using https, although I do not believe that should cause any problems. I would be very grateful for any feedback with this, whether it's a complete answer or just a comment telling me what isn't the problem, as I am still unsure whether this problem is server-side or client-side.
Thank you very much,
William
EDIT: I forgot to mention before, I am attaching my authentication credentials with my own custom java.net.Authenticator:
public class CustomAuthenticator extends Authenticator {
Context mContext;
public CustomAuthenticator(Context context){
super();
mContext = context;
}
#Override
protected PasswordAuthentication getPasswordAuthentication() {
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
String username = sharedPreferences.getString(SettingsActivity.KEY_USERNAME_PREFERENCE, null);
String password = sharedPreferences.getString(SettingsActivity.KEY_PASSWORD_PREFERENCE, null);
return new PasswordAuthentication(username, password.toCharArray());
}
}
which I set in the activity'sonCreate() method:
Authenticator.setDefault(new CustomAuthenticator(mContext));
Also, I have used curl to request the password protected resource, and have received a 401 as expected. I am now assuming the problem is client-side.
It seems to be an issue with using Authenticator in POST connections. It's quite old so I don't know if it still exists.
I would try two things:
Add a log line in the getPasswordAuthentication of the Authenticator to see if it's effectively called. If nothing is printed, you should check that you add the default Authenticator before it's called. You say you do it in the onCreate(), so it should be fine but it's good to be sure.
Avoid using the Authenticator (at least for testing purposes) and send the auth info directly in the HTTP Request. I usually do it this way:
String auth = user + ":" + pass;
conn = (HttpURLConnection) url.openConnection();
conn.setRequestProperty("Authorization",
"Basic " + Base64.encode(auth.getBytes()));
// Set other parameters and read the result...
The problem was that the 401 Unauthorized status is sent when the Authorization header is missing and when the credentials contained within the header are incorrect. Therefore, my app was constantly sending the same request over and over to no avail. I have therefore found a workaround to the problem by adding a counter into my CustomAuthenticator:
public class CustomAuthenticator extends Authenticator {
public static int RETRIES = 3;
int mRetriesLeft;
Context mContext;
public CustomAuthenticator(Context context){
super();
mRetriesLeft = RETRIES;
mContext = context;
}
#Override
protected PasswordAuthentication getPasswordAuthentication() {
Log.i(getClass().getName(), "getPasswordAuthentication() - mCounter: " + mRetriesLeft);
if(mRetriesLeft > 0){
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
String username = sharedPreferences.getString(SettingsActivity.KEY_USERNAME_PREFERENCE, null);
String password = sharedPreferences.getString(SettingsActivity.KEY_PASSWORD_PREFERENCE, null);
mRetriesLeft--;
return new PasswordAuthentication(username, password.toCharArray());
} else {
Log.w(getClass().getName(), "No more retries. Returning null");
mRetriesLeft = RETRIES;
return null;
}
}
public void reset(){
mRetriesLeft = RETRIES;
}
}
I should say however that I do not like this solution and therefore, have not accepted it. You have to remember to reset the counter whenever you make a new request (I do it in AsyncTask.onPreExecute()), or else every third request will fail. Also, I'm sure there must be a native way to do this, although after scouring the documentation I can't find it. I would still be very grateful if anyone can point it out to me.
I don't know if I am right or not but my solution has worked for me for a whole day without a glitch.
Try doing this
byte[] buf = new byte[4096];
Inputstream is;
do
{
http conn code etc;
is=conn.getInputStream();
if(is.read(buf)==0)
{
flag=1;
}
//u can either is.close(); or leave as is
//code
int serverResponseCode = connection.getResponseCode();
String serverResponseMessage = connection.getResponseMessage();
conn.disconnect();
} while(flag==1);
I'm seeing a StrictMode failure, and I can't see what's wrong with what I'm doing. The failure is:
java.lang.Throwable: Explicit termination method 'end' not called
E/StrictMode(26875): at dalvik.system.CloseGuard.open(CloseGuard.java:184)
E/StrictMode(26875): at java.util.zip.Inflater.<init>(Inflater.java:82)
E/StrictMode(26875): at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:96)
E/StrictMode(26875): at java.util.zip.GZIPInputStream.<init>(GZIPInputStream.java:81)
E/StrictMode(26875): at libcore.net.http.HttpEngine.initContentStream(HttpEngine.java:528)
E/StrictMode(26875): at libcore.net.http.HttpEngine.readResponse(HttpEngine.java:836)
E/StrictMode(26875): at libcore.net.http.HttpURLConnectionImpl.getResponse(HttpURLConnectionImpl.java:274)
E/StrictMode(26875): at libcore.net.http.HttpURLConnectionImpl.getResponseCode(HttpURLConnectionImpl.java:486)
E/StrictMode(26875): at com.mycompany.MyClass.sendJson(MyClass.java:267)
I configure StrictMode:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
StrictMode.setVmPolicy(new StrictMode.VmPolicy.Builder()
.detectLeakedSqlLiteObjects().detectLeakedClosableObjects().penaltyLog()
.penaltyDeath().build());
}
The code looks something like the following:
HttpURLConnection connection = null;
OutputStream outputStream = null;
InputStream in = null;
try {
connection = (HttpURLConnection)new URL("http://our.server/some/path").openConnection();
connection.setRequestProperty("Accept", "application/json");
connection
.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
connection.setDoOutput(true);
outputStream = connection.getOutputStream();
String content = "{\"some\":\"json data\"}";
byte bytes[] = content.getBytes("UTF-8");
outputStream.write(bytes);
outputStream.flush();
responseCode = connection.getResponseCode(); // This is line 267 in the stack trace
if (HttpURLConnection.HTTP_OK == responseCode
|| HttpURLConnection.HTTP_CREATED == responseCode) {
// do something with a successful response
}
}
} catch (IOException e) {
// report the exception
} finally {
if (null != connection) {
connection.disconnect();
}
if (null != outputStream) {
try {
outputStream.close();
} catch (IOException e) {
}
}
if (null != in) {
try {
in.close();
} catch (IOException e) {
}
}
}
I found somebody complaining of seeing the same StrictMode failure when using Google AdMob SDK (https://groups.google.com/forum/?fromgroups=#!topic/google-admob-ads-sdk/yVss4ufdPp4) but I've not been able to find any solution so far.
What happens if you get the response stream, read it completely and close it (even if the response code is not OK).
I think this will invoke HttpEngine.release(), and thus avoid the exception when the GzipInputStream is later finalized (as the exception is prepared in the constructor but throwed in finalize())
I think connection.getResponseCode() opens an input stream. So you will need to retrieve the input stream and close it.