3

I am having problem with an HttpPost on Android 4.2. I am trying to call an authentication service that is hosted in a .NET WebAPI service.

The service requires that the request be made as a POST method, and that several custom request headers be supplied. The body of the request sends Json values to the service.

Here is how I am composing my request;

HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://api.fekke.com/api/account/login");
httppost.addHeader(HTTP.TARGET_HOST, "api.fekke.com");
httppost.addHeader("Accept", "application/json");
httppost.addHeader("Fekke-AccessKey", "some-access-key");
httppost.addHeader("Date", dateString);
httppost.addHeader("Fekke-Signature", "some-encoded-value");
httppost.addHeader("Content-Type", "application/json; charset=utf-8");

String jsonmessage = "{\"Username\": \"myusername\", \"Password\": \"mypassword987\"}";
httppost.setEntity(new StringEntity(jsonmessage, HTTP.UTF_8));

HttpResponse response = httpclient.execute(httppost);

I have tried to call this with a "Content-Length" header, and it throws an exception saying that the header already exists in the request.

I have also tried calling this using an HttpURLConnection object, which what Google proposes using from this point forward, but this also runs into the same problem.

I have been able to make this request call from the iOS and .NET without a problem, so I know it is not the service.

UPDATE #1

I ran the following example through a local version of the service, and I was able to isolate the error to when I pass a hashed value in one of the http headers. I am using a JWT security token that uses the HMAC SHA-256 hashing algorithm to set a value used by the service. This hashed value causes the execution of the request to blow up.

UPDATE #2

I was finally able to resolve the problem. The problem was caused by the Base64 encodeToString method adding an invisble character to the value. It was forcing a corruption in the header. I was using the default setting of 0 or Base64.DEFAULT. I changed the value to Base64.NO_WRAP, and it resolved the issue.

David Fekke
  • 399
  • 2
  • 5
  • 13

1 Answers1

0

you should not worry about setting 'content-length' header on a post if you are using the correct methods. With Post, you usually use some overloaded version of 'SetEntity($Type-stream/string/encodedArray...)'

look at this source( search on length) to see examples of how the API takes care of the length for you on a post.

You should evaluate what lib you will use for http and find POST examples showing methods like 'setEntity' to set the body of the post. that way , you will not get errors related to content-length. see example

Sample code "HttpConnection" class - using links from my comment...

For JSON OR Bitmap:

try {                       
    HttpResponse response = null;
    switch (method) {
    case GET:
        HttpGet httpGet = new HttpGet(url);             
        response = httpClient.execute(httpGet);
        break;
    //Note on NIO - using a FileChannel and  mappedByteBuffer may be NO Faster
    // than using std httpcore  http.entity.FileEntity
    case POST:
        //TODO bmp to stream to bytearray for data entity
        HttpPost httpPost = new HttpPost(url); //urlends "audio OR "pic" 
        if (  !url.contains("class") ){                 
            ByteArrayOutputStream stream = new ByteArrayOutputStream();
            //can alter belo for smaller uploads to parse .JPG , 40,strm
            bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);               
            httpPost.setEntity(new ByteArrayEntity(stream.toByteArray()));

        }else if(data != null && (url.contains("class"))){
            //bug data is blank
            httpPost.setEntity(new StringEntity(data));
            Log.d(TAG, "DATA in POST run-setup " +data);
        }

        response = httpClient.execute(httpPost);
        break;
    case PUT:
        HttpPut httpPut = new HttpPut(url);
        httpPut.setEntity(new StringEntity(data));
        response = httpClient.execute(httpPut);
        break;
    case DELETE:
        response = httpClient.execute(new HttpDelete(url));
        break;
    case BITMAP:
        response = httpClient.execute(new HttpGet(url));
        processBitmapEntity(response.getEntity());
        break;
    }
    if (method < BITMAP)
        processEntity(response.getEntity());
} catch (Exception e) {
    handler.sendMessage(Message.obtain(handler,
            HttpConnection.DID_ERROR, e));
}

For XML body in Post:

try {
    HttpResponse response = null;
    switch (method) {

    case POST:
        HttpPost httpPost = new HttpPost(url);
        if (data != null){
            System.out.println(" post data not null ");
            httpPost.setEntity(new StringEntity(data));
        }
        if (entry != null){
            ContentProducer cp = new ContentProducer() {
                public void writeTo(OutputStream outstream) throws IOException {

                     ExtensionProfile ep = new ExtensionProfile();
                     ep.addDeclarations(entry);
                     XmlWriter xmlWriter = new XmlWriter(new OutputStreamWriter(outstream, "UTF-8"));
                     entry.generate(xmlWriter, ep);
                     xmlWriter.flush();
                }
            };
            httpPost.setEntity(new EntityTemplate(cp));
        }
        httpPost.addHeader("GData-Version", "2");
        httpPost.addHeader("X-HTTP-Method-Override", "PATCH");
        httpPost.addHeader("If-Match", "*");
        httpPost.addHeader("Content-Type", "application/xml");
        response = httpClient.execute(httpPost);

        break;
    }
    if (method < BITMAP)
        processEntity(response.getEntity());
} catch (Exception e) {
    handler.sendMessage(Message.obtain(handler,
            HttpConnection.DID_ERROR, e));
}
Community
  • 1
  • 1
Robert Rowntree
  • 6,230
  • 2
  • 24
  • 43
  • I rewrote the HttpPost so I create the entity first, set the content type, then I set the entity to the post. It looks like the following. `StringEntity body = new StringEntity(jsonmessage, HTTP.UTF_8); body.setContentType("application/json; charset=utf-8"); httppost.setEntity(body); // Execute HTTP Post Request HttpResponse response = httpclient.execute(httppost);` I still get the same 411 error. – David Fekke Apr 28 '13 at 04:23
  • hmm. dont know why. what httpclient are you using? If you want to rethink your implementation of httpclient then you could do this: example - http://masl.cis.gvsu.edu/2010/04/05/android-code-sample-asynchronous-http-connections/ that is for async use of http and very good use of the network. Then - https://code.google.com/p/httpclientandroidlib/ for a lib that can be used to implement. – Robert Rowntree Apr 28 '13 at 14:36
  • I have tried every API I could find. I have used the DefaultHttpClient, the loopj Async client, the HttpURLConnection with the same results. The whole thing blows up when I set one of the headers. – David Fekke Apr 29 '13 at 17:16
  • https://github.com/rowntreerob/gpsclipper/blob/master/src/com/b2bpo/media/geophoto/HttpConnection.java connection used in github project. http://stackoverflow.com/questions/14459360/put-log4j-logging-httpclient/14550628#14550628 discuss full logging WIRE and HEADERS in the 'httpclientandroidlib' project.. with full wire and headers you should be able to curl the same statements that your app is sending so you know ahead of time that your apps calls to http will all work. – Robert Rowntree Apr 29 '13 at 20:19