Sending data in HTTP request's body fails - blackberry

I am using the HttpConnection class of J2ME in my BlackBerry app to send data to a web server. I need to send the contents of an image in the body of the HTTP request.
This is what I do
Get the bytes of the file in an array
Open HTTP connection
Set content type header as image/jpeg
Get output stream of the connection
Write the bytes to the output stream
Close the output stream and connection
But the image is not uploaded to the server. What could be the problem?
Thanks.
EDIT - Adding code
HttpConnection conn = null;
OutputStream out = null;
try{
conn = new HttpConnection(Connector.open(myURL));
conn.setRequestProperty("Content-Type", "image/jpeg");
conn.setRequestMethod(HttpConnection.POST);
conn.setRequestProperty("Content-Disposition", "form-data");
conn.setRequestProperty("Connection", "Keep-Alive");
out = conn.openOutputStream;
out.write(buffer, 0, buffer.length);
conn.setRequestProperty("Content-Length", buffer.length);
out.flush();
}
catch(Exception e){
e.printStackTrace();
}
finally{
if(out != null)
out.close();
if(conn != null){
System.out.println("" + conn.getResponseCode());
conn.close();
}
}
EDIT
The same code, when I try it with a string, works fine and sends the string to the server. But it is still a problem with the image bytes.

A few things that may be missing from your list:
use HttpConnection.setRequestMethod(HttpConnection.POST) between 2 and 3.
set content length with HttpConnection.setRequestProperty("Content-Length",...) between 5 and 6.
knowing the HTTP request response code can help debug your issues: call HttpConnection.getResponseCode() after you've closed the OutputStream but before you close the HttpConnection.

conn = new HttpConnection(Connector.open(myURL));
This line is wrong. Connection is a factory class that creates new Connection objects by looking it's appropriate protocol implementation.
HttpConnection conn = (HttpConnection) Connector.open(myURL);
The rest of the code seems ok. When you're POSTing, at minimun you need to define the content-type and content-length.

You most definitely need to set all headers before sending the POST data, including the Content-Length header.
Also, make sure you are sending headers valid for requests, and not response-only headers.

You'll need to encode the bytes (preferably Base-64) and send that string. The raw bytes aren't likely to be http safe.
Then on the server, you'll need to decode them back into a byte array and do whatever you were going to do with it (save as file, stuff into database, etc.)

Related

How do I add a file into a HTTP PUT request calling the Microsoft Graph API?

I am trying to upload a file to a SharePoint Drive by using Microsoft Graph. I am new to REST APIs and Microsoft Graph.
This is what the documentation says:
PUT /me/drive/root:/FolderA/FileB.txt:/content
Content-Type: text/plain
The contents of the file goes here.
Before all of this, I do have my authorization/bearer token and I am able to call the HTTP get but I am not able to upload the file using HTTP PPU.
URL url = new URL(newUrl);
String readLine;
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("Authorization","Bearer "+ token);
connection.setRequestProperty("Accept","application/json");
This returns java.io.IOException: Server returned HTTP response code: 411 for URL.
I have tried passing it as a binary stream but the request is still failing.
The "type" of the file is determined by the Content-Type header. For some context, the Accept header states the format you expect the response body to use while the Content-Type states the format of your request.
To upload a standard text file, you'll want to use Content-Type: text/plain:
URL url = new URL(newUrl);
String readLine;
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestProperty("Authorization","Bearer "+ token);
connection.setRequestProperty("Accept","application/json");
connection.setRequestProperty("Content-Type","text/plain");

Decompressing REST response with GZIPInputStream

I'm trying to decompress a gzip:ed response i receive from a REST service:
Content-Encoding=[gzip], Content-Type=[application/json], Content-Length=[710] ...
I'm using the Grails REST Client Builder Plugin:
def response = new RestBuilder().get(HOST + "/api/..."){
contentType "application/json"
accept "application/json"
}
The returned response is a Spring ResponseEntity. I'm trying to decompress the data using GZIPInputStream:
String body = response.getBody()
new GZIPInputStream(new ByteArrayInputStream(body.getBytes())).text
This fails to Caused by ZipException: Not in GZIP format
Obviously there is something I'm doing wrong, but I can't figure out what. All advice is appriciated.
If you really need to keep using the Rest Client Builder you only need to modify your client code slightly:
def response = new RestBuilder().get(HOST + "/api/..."){
contentType "application/json"
accept byte[].class, "application/json" }
Note the extra parameter in the accept call - byte[].class - which signifies that RestTemplate should refrain from any parsing of the response.
To decompress you can now do:
new GZIPInputStream(new ByteArrayInputStream(response.body))
Yeah, I know, already answered with accept but some might still find it helpful in case switching Rest components is not an option.
I never managed to get it to work with grails / groovy libraries, so i switched to spring and httpcomponents:
HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory(HttpClientBuilder.create().build());
RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);
ResponseEntity<String> response = restTemplate.exchange(
"some/url/", HttpMethod.GET, new HttpEntity<Object>(requestHeaders),
String.class);
Which decoded gzip automatically and thus there are no longer any need for manual decoding.

multipart http request to upload images

I m trying to use multipart post request to upload two string parameters( token and source) and an image captured from mobile device ( return jpeg encoded byte[] ). But it is generating error which I am sure is due to incorrect request.
I am still not sure about notation on creating a multipart post request. So any helpful links and resources would be good.
The code is for Blackberry java development
//------------------------------------------------------------------------------//
StringBuffer buffer = new StringBuffer();
String boundary = "--##$--";
byte[] image = byte[] from camera.getsnapshot;
buffer.append(boundary+"\r\nContent-Disposition: form- data;name=\"token\"\r\n"+token+"\r\n");
buffer.append(boundary+"\r\nContent-Disposition: form- data;name=\"source\"\r\n"+"Blackberry"+"\r\n");
buffer.append(boundary+"\r\nContent-Disposition: form- data;name=\"file.jpg\";filename=\""+ "file.jpg"+"\""+"\n" + "Content- Type:image/jpeg"+"\n"+ "Content-Transfer-Encoding: binary" + boundary +"\r\n" +new String(image));
buffer.append("\r\n" + boundary + "\r\n");
String string = new String(buffer);
byte[] post = string.getBytes();
HttpConnection connection = (HttpConnection)Connector.open(url);
connection.setRequestMethod("POST");
connection.setRequestProperty(HttpProtocolConstants.HEADER_CONTENT_TYPE,
HttpProtocolConstants.CONTENT_TYPE_MULTIPART_FORM_DATA+
";boundary="+boundary);
connection.setRequestProperty(HttpProtocolConstants.HEADER_CONTENT_LENGTH,String.valueOf(post.length));
connection.setRequestProperty("User-Agent", "Profile/MIDP_2.0 Configuration/CLDC-1.0");
OutputStream postStream =connection.openOutputStream();
postStream.write(post,0,post.length);
postStream.close();
\----------------------------------------------------------------------------------\
Perhaps this Nokia Community wiki page will help you: HTTP Post multipart file upload in Java ME

I am sending data over HTTPS but the server side says it is not receiving it

I create an application that sends some data to a secured network.
At the server side they need the data as JSON object. For that am creating the data as JSON object and writing that data in the OutputStream of the connection.
But the response from the server side telling it is not getting the data that I am passing.
The code snippet that am using is something like given below:
HttpsConnection _connection = (HttpsConnection)Connector.open("https://gmail.com/",Connector.READ_WRITE, true); _connection.setRequestMethod(HttpsConnection.POST);
_connection.setRequestProperty("If-Modified-Since", "29 Oct 1999 19:43:31 GMT");
_connection.setRequestProperty("User-Agent","Profile/MIDP-2.0 Configuration/CLDC-1.0");
_connection.setRequestProperty("Content-Language", "en-US");
_connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
byte[] postData = jsonObject.toString().getBytes("UTF-8");
_connection.setRequestProperty("Content-Length", Integer.toString(postData.length));
_connection.setRequestProperty("jsondata",jsonObject.toString());
OutputStream os = _connection.openOutputStream();
os.write(postData);
os.flush();
Please help me to solve the issue.
I guess the reason is "Content-Type" => "application/x-www-form-urlencoded". This type of a POST exists for sending a list of key=value pairs. So the server on its side will parse the post data in terms of key=value pairs. I believe in your case it just fails to parse the got post data, because you don't send the data in the key=value pairs form (instead you just pour the entire json string jsonObject.toString().getBytes("UTF-8") in it).
So basically you need to form a key value pair "json=YOUR_JSON_HERE". Then on the server you will get your data as the json parameter value:
URLEncodedPostData encPostData = new URLEncodedPostData("UTF-8", false);
encPostData.append("json", jsonObject.toString());
byte[] postData = encPostData.toString().getBytes("UTF-8");
Another option (and BTW it would be the most proper way to do this particular task) would be to use "multipart/form-data" POST type. However it will be a bit harder to implement it if you've never done that before on BB.
You have to append appropriate suffix to to your url
eg: If you use simulator use:https://gmail.com/;deviceside=true etc
I have same this problem but finally find solution:
HttpConnection c = (HttpConnection)Connector.open(url);
c.setRequestMethod(HttpConnection.POST);
c.setRequestProperty(
HttpProtocolConstants.HEADER_CONTENT_TYPE, PostData.getContentType());
c.setRequestProperty(
HttpProtocolConstants.HEADER_CONTENT_LENGTH,String.valueOf(oPostData.size()));
c.setRequestProperty("Content-Length", Integer.toString(oPostData.size()));
c.setRequestProperty("Content-Type","application/json");
byte [] postDataBytes = jobj.toString().getBytes("UTF-8");
os = c.openOutputStream();
os.write(postDataBytes);
os.flush();

HttpURLConnection implementation

I have read that HttpURLConnection supports persistent connections, so that a connection can be reused for multiple requests. I tried it and the only way to send a second POST was by calling openConnection for a second time. Otherwise I got a IllegalStateException("Already connected");
I used the following:
try{
URL url = new URL("http://someconection.com");
}
catch(Exception e){}
HttpURLConnection con = (HttpURLConnection) url.openConnection();
//set output, input etc
//send POST
//Receive response
//Read whole response
//close input stream
con.disconnect();//have also tested commenting this out
con = (HttpURLConnection) url.openConnection();
//Send new POST
The second request is send over the same TCP connection (verified it with wireshark) but I can not understand why (although this is what I want) since I have called disconnect.
I checked the source code for the HttpURLConnection and the implementation does keep a keepalive cache of connections to the same destinations. My problem is that I can not see how the connection is placed back in the cache after I have send the first request. The disconnect closes the connection and without the disconnect, still I can not see how the connection is placed back in the cache. I saw that the cache has a run method to go through over all idle connections (I am not sure how it is called), but I can not find how the connection is placed back in the cache. The only place that seems to happen is in the finished method of httpClient but this is not called for a POST with a response.
Can anyone help me on this?
EDIT
My interest is, what is the proper handling of an HttpUrlConnection object for tcp connection reuse. Should input/output stream be closed followed by a url.openConnection(); each time to send the new request (avoiding disconnect())? If yes, I can not see how the connection is being reused when I call url.openConnection() for the second time, since the connection has been removed from the cache for the first request and can not find how it is returned back.
Is it possible that the connection is not returned back to the keepalive cache (bug?), but the OS has not released the tcp connection yet and on new connection, the OS returns the buffered connection (not yet released) or something similar?
EDIT2
The only related i found was from JDK_KeepAlive
...when the application calls close()
on the InputStream returned by
URLConnection.getInputStream(), the
JDK's HTTP protocol handler will try
to clean up the connection and if
successful, put the connection into a
connection cache for reuse by future
HTTP requests.
But I am not sure which handler is this. sun.net.www.protocol.http.Handler does not do any caching as I saw
Thanks!
Should input/output stream be closed
followed by a url.openConnection();
each time to send the new request
(avoiding disconnect())?
Yes.
If yes, I can not see how the connection is being
reused when I call
url.openConnection() for the second
time, since the connection has been
removed from the cache for the first
request and can not find how it is
returned back.
You are confusing the HttpURLConnection with the underlying Socket and its underlying TCP connection. They aren't the same. The HttpURLConnection instances are GC'd, the underlying Socket is pooled, unless you call disconnect().
From the javadoc for HttpURLConnection (my emphasis):
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. Calling the
close() methods on the InputStream or
OutputStream of an HttpURLConnection
after a request may free network
resources associated with this
instance but has no effect on any
shared persistent connection. Calling
the disconnect() method may close the
underlying socket if a persistent
connection is otherwise idle at that
time.
I found that the connection is indeed cached when the InputStream is closed. Once the inputStream has been closed the underlying connection is buffered. The HttpURLConnection object is unusable for further requests though, since the object is considered still "connected", i.e. its boolean connected is set to true and is not cleared once the connection is placed back in the buffer. So each time a new HttpUrlConnection should be instantiated for a new POST, but the underlying TCP connection will be reused, if it has not timed out.
So EJP answer's was the correct description. May be the behavior I saw, (reuse of the TCP connection) despite explicitly calling disconnect() was due to caching done by the OS? I do not know. I hope someone who knows can explain.
Thanks.
How do you "force use of HTTP1.0" using the HttpUrlConnection of JDK?
According to the section ā€˛Persistent Connectionsā€¯ of the Java 1.5 guide support for HTTP1.1 connections can be turned off or on using the java property http.keepAlive (default is true). Furthermore, the java property http.maxConnections indicates the maximum number of (concurrent) connections per destination to be kept alive at any given time.
Therefore, a "force use of HTTP1.0" could be applied for the whole application at once by setting the java property http.keepAlive to false.
Hmmh. I may be missing something here (since this is an old question), but as far as I know, there are 2 well-known ways to force closing of the underlying TCP connection:
Force use of HTTP 1.0 (1.1 introduced persistent connections) -- this as indicated by the http request line
Send 'Connection' header with value 'close'; this will force closing as well.
Abandoning streams will cause idle TCP connections. The response stream should be read completely. Another thing I overlooked initially, and have seen overlooked in most answers on this topic is forgetting to deal with the error stream in case of exceptions. Code similar to this fixed one of my apps that wasn't releasing resources properly:
HttpURLConnection connection = (HttpURLConnection)new URL(uri).openConnection();
InputStream stream = null;
BufferedReader reader = null;
try {
stream = connection.getInputStream();
reader = new BufferedReader(new InputStreamReader(stream, Charset.forName("UTF-8")));
// do work on part of the input stream
} catch (IOException e) {
// read the error stream
InputStream es = connection.getErrorStream();
if (es != null) {
BufferedReader esReader = null;
esReader = new BufferedReader(new InputStreamReader(es, Charset.forName("UTF-8")));
while (esReader.ready() && esReader.readLine() != null) {
}
if (esReader != null)
esReader.close();
}
// do something with the IOException
} finally {
// finish reading the input stream if it was not read completely in the try block, then close
if (reader != null) {
while (reader.readLine() != null) {
}
reader.close();
}
// Not sure if this is necessary, closing the buffered reader may close the input stream?
if (stream != null) {
stream.close();
}
// disconnect
if (connection != null) {
connection.disconnect();
}
}
The buffered reader isn't strictly necessary, I chose it because my use case required reading one line at a time.
See also: http://docs.oracle.com/javase/1.5.0/docs/guide/net/http-keepalive.html

Resources