I am using an Android app to send a base64 encoded string to a CherryPy server. The Android code works like this:
URL url = new URL("http://foo.bar/blabla");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestProperty("Content-Type", "application/octet-stream");
conn.setDoOutput(true);
conn.setFixedLengthStreamingMode(base64s.length());
OutputStream out = new BufferedOutputStream(conn.getOutputStream());
out.write(base64s.getBytes());
So, you'd say the amount of bytes sent equals the amount of bytes in the Content-Length header. However, in Python, when I run this:
cl = cherrypy.request.headers['Content-Length']
rawbody = cherrypy.request.body.read()
print "{} bytes, {}".format(len(rawbody), cl)
The numbers cl and len(rawbody) are different.
How can that be?
Maybe you forgot to close the stream with out.close(); ?
your server sould send a "close header" so the client will no its end stream for him.
Related
I'm trying to use HttpURLConnection to send and receive messages in an Android application. This code works fine in a java application, but when running on Android I get the following exception:
java.lang.ClassCastException: com.android.okio.RealBufferedSink$1 cannot be cast to java.io.ByteArrayOutputStream
The code where this occurs:
URL url = new URL(destURI.toString());
HttpURLConnection con = (HttpURLConnection) url.openConnection();
// Set request properties and headers
con.setDoOutput(true);
con.setDoInput(true);
con.setRequestProperty(HEADER_CONTENT_TYPE, CONTENT_TYPE_LS);
con.setRequestProperty(HEADER_CONTENT_LENGTH, new Integer(wrapperBytes.length).toString());
con.setRequestMethod(METHOD_POST);
// Set connect and read timeouts
con.setConnectTimeout(timeoutInMillis);
con.setReadTimeout(timeoutInMillis);
// Write request content
ByteArrayOutputStream out = (ByteArrayOutputStream) con.getOutputStream();
out.write(wrapperBytes);
out.flush();
I've looked at the android reference pages and these seem to say what I'd expect, getOutputStream() returns an OutputStream. This should then be able to be cast to a ByteArrayOutputStream.
Where is the RealBufferedSink coming from? Why am I not getting an OutputStream back?
Any help would be greatly appreciated!
Casting
ByteArrayOutputStream out = (ByteArrayOutputStream) con.getOutputStream();
is not recommended,
you might try:
OutputStream out = new BufferedOutputStream(con.getOutputStream());
I am making an android test app that just sends a String to server which is an instance on AWS EC2. However I am seeing 404 even though the IP is correct. What else can be wrong here?
URL serverUrl = new URL("http://aa.bb.cc.dd");
connection = (HttpURLConnection) serverUrl.openConnection();
connection.setRequestMethod("GET");
OutputStream stream = connection.getOutputStream();
String testString = "test123";
byte[] bytes = testString.getBytes();
stream.write(bytes);
stream.flush();
int retcode = connection.getResponseCode();
retcode is 404.
On the server side I have all sources allowed for the following in the security group being used:
All TCP, port 0 - 65535
HTTP, port 80
There is a string variable and an image photo taken from the camera intent. The directory location of the photo is known. I want to make a HTTP post of the string variable and the image photo to a webserver at the same time. Is that possible ? If so , how to do it ?
From what I understand, you need to send an image and a string to your webserver within a single POST request. Here's how you'd proceed.
You first need to Base64 encode your image.
Start by converting your image into a byte array:
InputStream image = new FileInputStream(<path_to_image>);
byte[] buff = new byte[8192];
int readBytes;
ByteArrayOutputStream byteArrOS = new ByteArrayOutputStream();
try {
while ( (readBytes = inputStream.read(buff) ) != -1) {
byteArrOS.write(buff, 0, readBytes);
}
} catch (IOException e) {
e.printStackTrace();
}
byte[] b = byteArrOS.toByteArray();
Then convert it to Base64:
String bsfEncodedImage = Base64.encodeToString(b, Base64.DEFAULT);
Then build a query with the the string and the resulting Base64 both encoded with URLEncoder and "utf-8":
strImgQuery = "str="+URLEncoder.encode(<string_data>, "utf-8")+"&image="+URLEncoder.encode(bsfEncodedImage, "utf-8");
Declare a new URL:
URL postUrl = new URL("http://<IP>/postreq");
Open the connection:
HttpURLConnection conn = (HttpURLConnection)postUrl.openConnection();
Set output to "true" (needed for a POST request but not for GET):
conn.setDoOutput(true);
Set the request method to POST:
conn.setRequestMethod("POST");
The timeout:
conn.setReadTimeout(1e4);
Buffer the output to the output stream and flush/run:
Writer buffWriter = new OutputStreamWriter(conn.getOutputStream());
buffWrite.write(strImgQuery);
buffWriter.flush();
buffWriter.close();
At server side you'll get the str and image POST params which is dependent on your server implementation.
Note that your url must follow the URL Specification, otherwise you'll get a MalformedURLException. If that's the case, be sure to check what exactly the issue is. For example if you use a non-existing ttp "protocol" instead of http your exception will look something like this:
java.net.MalformedURLException: unknown protocol: ttp
at java.net.URL.<init>(URL.java:592)
at java.net.URL.<init>(URL.java:482)
at java.net.URL.<init>(URL.java:431)
at com.pheromix.core.lang.NumberFormatExceptionExample.MalformedURLExceptionExample.sendGetRequest(MalformedURLExceptionExample.java:28)
at com.pheromix.core.lang.NumberFormatExceptionExample.MalformedURLExceptionExample.main(MalformedURLExceptionExample.java:17)
Also, this is a synchronous operation and is ran on the UI thread. It might be costly or it might not depending on other operations you're already running and the size of the POST data. If the problem arises, run the job on another thread.
You can use URLEncoder
String strUrl = "http://192.168.1.9/impots/" +URLEncoder.encode("outil.php?action=OutilImporterDonneesMobile", "utf-8");
URL url = new URL(strUrl);
I've already created my HTTPUrlConnection :
String postData = "x=val1&y=val2";
URL url = new URL(strURL);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
conn.setRequestProperty("Set-Cookie", sessionCookie);
conn.setRequestProperty("Content-Length", "" + Integer.toString(postData.getBytes().length));
// How to add postData as http body?
conn.setUseCaches(false);
conn.setDoInput(true);
conn.setDoOutput(true);
I don't know how to set postData in http body. How to do so? Would I better use HttpPost instead?
Thanks for your help.
If you want to send String only try this way:
String str = "some string goes here";
byte[] outputInBytes = str.getBytes("UTF-8");
OutputStream os = conn.getOutputStream();
os.write( outputInBytes );
os.close();
But if you want to send as Json change Content type to:
conn.setRequestProperty("Content-Type","application/json");
and now our str we can write:
String str = "{\"x\": \"val1\",\"y\":\"val2\"}";
Hope it will help,
Guruparan's link in the comment above gives a really nice answer to this question. I highly recommend looking at it. Here is the principle that makes his solution work:
From what I understand, the HttpURLConnection represents the response body as an OutputStream. So you need to call something like:
get the connection's output stream
OutputStream op = conn.getOuputStream();
write the response body
op.write( [/*your string in bit form*/] );
close the output stream
op.close();
and then carry on your merry way with the connection (which you will still need to close).
Below is the code I am using to send SOAP requests in my Android app and it works fine with all requests except one. This code throws IOException : Content-length exceeded on wr.flush(); when there are chinese characters in requestBody variable.
The content-length in that case is 409
URL url = new URL(Constants.HOST_NAME);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// Modify connection settings
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "text/xml; charset=utf-8");
connection.setRequestProperty("SOAPAction", soapAction);
String requestBody = new String(soapRequest.getBytes(),"UTF-8");
int lngth = requestBody.length();
connection.setRequestProperty("Content-Length", (""+lngth));
// Enable reading and writing through this connection
connection.setDoInput(true);
connection.setDoOutput(true);
// Connect to server
connection.connect();
OutputStreamWriter wr = new OutputStreamWriter(connection.getOutputStream(), "UTF-8");
wr.write(requestBody);
wr.flush();
wr.close();
Any clue what is going wrong when there are chinese characters in the string?
EDIT: I have removed the 'content-lenght' header field and it works, but why?
This code sets the request's Content-Length property to the number of characters in the string representation of the message:
String requestBody = new String(soapRequest.getBytes(),"UTF-8");
int lngth = requestBody.length();
connection.setRequestProperty("Content-Length", (""+lngth));
But then you convert that string representation back to bytes before writing:
OutputStreamWriter wr = new OutputStreamWriter(connection.getOutputStream(), "UTF-8");
So you end up writing more bytes then you've claimed. You'll run into the same problem with any non-ASCII characters. Instead, you should do something like this (copy-and-paste, so may have syntax errors):
byte[] message = soapRequest.getBytes();
int lngth = message.length;
connection.setRequestProperty("Content-Length", (""+lngth));
// ...
connection.getOutputStream().write(message);
To simplify the other answer: Content-Length MUST be length in bytes, and you are specifying length in chars (Java's 16-bit char type). These are different, in general. Since UTF-8 is a variable-byte-length encoding, there is difference for anything beyond basic 7-bit ASCII range. The other answer shows proper way to write code.
My guess is that you have not converted the chinese to utf-8. If you support users entering doublewide and extended character sets into your fields, you'll need to make sure to convert your inputs from those character sets (ASCII, UNICODE or UCS) to UTF-8.
Once you determine the character encodings you are working with, you can use something like:
FileInputStream(inputFile), "inputencoding");
Writer output = new OutputStreamWriter(new FileOutputStream(outputFile), "outputencoding");
Reference
when creating your streams for reading/writing to convert between two.
Another alternative is to look into setting the request property controlling the language of the http request. I do not know much about that.