0

So I just spent 6 hours worth of work, figuring out this 'little' fact: Without calling client.getResponseCode() THE POST REQUEST DOES NOT GO THROUGH.

I hope that someone can explain why! Specifically, for this minimalistic android client standalone code literally nothing happens without the line int status = client.getResponseCode(); but with it,everything works like magic. I didn't find any official documentation about this, so I'm wondering what's up, or what I don't understand (The people implementing Java usually do outstanding job, so it's probably me not getting something :) ).

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final String theUrl = "http://xx.yyy.zz.aa:bb/securitiesFollowServer/users";
        final String TAG = getClass().getSimpleName();

        AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
            @Override
            protected Void doInBackground(Void... params) {
                String body = "BODY OF MESSAGE";

                HttpURLConnection client = null;
                BufferedWriter outputPost = null;

                try {
                    URL url = new URL(theUrl);

                    //  open the connection
                    client = (HttpURLConnection) url.openConnection();
                    client.setRequestProperty("content-type", "text/plain");
                    //client.setRequestMethod("POST"); Someone claimed that setDoOutput(true) works so I will try that instead (I tried both,mutually and exclusively so all 3 options).
                    client.setDoOutput(true);

                    outputPost = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()));
                    outputPost.write(body);
                    outputPost.flush();
                    outputPost.close();
                    int status = client.getResponseCode();
                    StackTraceElement[] r = Thread.currentThread().getStackTrace();
                    String toNotepad = "";
                    for (int i = 0; i < r.length; ++i) {
                        toNotepad += '\n' + String.valueOf(i) + '.' + ':' + r[i].toString();
                    }
                    // This is where I set a breakpoint and got the stacktrace value from toNotepad,and copy pasted it.
                } catch (IOException e) {
                    Log.e(TAG, "Error ", e);
                } finally {
                    if (client != null) {
                        client.disconnect();
                    }
                    if (outputPost != null) {
                        try {
                            outputPost.close();
                        } catch (IOException e) {
                            Log.e(TAG, "IO ERROR");
                        }
                    }

                    return null;
                }
            }
        };
        task.execute();
    }
}

For completeness of the question, here is the "server side" minimalistic code

@POST
@Consumes(MediaType.TEXT_PLAIN)
@Produces(MediaType.TEXT_PLAIN)
public String setDebugResource(String a){
    return "I got this string:"+a;}

And here is the stacktrace (I made it obvious in the code above where exactly I copy-pasted its value):

When not working(or working, it is exactly the same stacktrace).:

0.:dalvik.system.VMStack.getThreadStackTrace(Native Method)
1.:java.lang.Thread.getStackTrace(Thread.java:580)
2.:dor.only.dorking.android.apppostrequest.MainActivity$1.doInBackground(MainActivity.java:52)
3.:dor.only.dorking.android.apppostrequest.MainActivity$1.doInBackground(MainActivity.java:28)
4.:android.os.AsyncTask$2.call(AsyncTask.java:292)
5.:java.util.concurrent.FutureTask.run(FutureTask.java:237)
6.:android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:231)
7.:java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1112)
8.:java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:587)
9.:java.lang.Thread.run(Thread.java:818)
Lucy
  • 23
  • 4
Yoni Keren
  • 1,170
  • 2
  • 13
  • 24
  • https://developer.android.com/reference/java/net/HttpURLConnection.html#getResponseCode() – Nirav Ranpara May 25 '16 at 10:26
  • Please provide the stack trace in your question. – user207421 May 25 '16 at 10:48
  • @EJP OK I did give the stacktrace for the client side (there is none for the server side since the method is not being called at all whatsoever. I put a breakpoint at the very beginning of the method and it gets there only when I call getResponseCode()). – Yoni Keren May 25 '16 at 11:28

1 Answers1

1

According to the HttpUrlConnection docs you must call setDoOutput(true) on the client object instead of setting the method to POST. The method will be set automatically to POST through this. They have an example under section "Posting Content".

There's an example here as well and a larger discussion here

Frankly, I would skip using the raw HttpUrlConnection class and use something like Volley.

Community
  • 1
  • 1
Horia Coman
  • 8,681
  • 2
  • 23
  • 25
  • You must *instead* call `setDoOutput(true)`. Doing that sets the request method to POST, but setting it to POST doesn't set `doOutput` to `true`. It isn't necessary to do both. – user207421 May 25 '16 at 10:48
  • Not necessary indeed. There are other request types (PUT, PATCH, custom stuff) which would require both though, and I'd say it's good practice to do it. – Horia Coman May 25 '16 at 10:55
  • @Horia Coman I've tried that just now (I've reflected that in the code in the question) and the behavior is EXACTLY the same. Pretty annoying huh? :) – Yoni Keren May 25 '16 at 11:29
  • @YoniKeren Yes it is. The bad quality of the APIs in Android is a constant pain-point. Have you tried replacing the getResponseCode() with getInputStream() and reading from that. I assume at some point you're going to have to read the response (or is it a one-way thing?). Perhaps it's just an optimization in the library to not make a request if nothing is read from it. Also, what type do you get for client? HttpUrlConnection is an abstract class, but perhaps the concrete one is also in AOSP and we can then see exactly what it is up to. – Horia Coman May 25 '16 at 12:10