POST sends no data using URLconnection with 1.5.0_03

I'm porting an applet from the MSJVM environment in a signed CAB file to JDK1.5.0_03 with a signed JAR file. I've already run into the issue of calling the applet from Javascript and any methods called being untrusted regardless of the signing as they retain Javascript's untrusted status.

Now I have a simple problem, or it sounds it! My applet loads an image from the load hard drive, scales it and attempts to POST it to an IIS server where an ASP script receives the file and writes it to the server's filesystem. All the server back-end is tried and tested via the old MS flavour applet and can also be tested by a simple HTML form carrying out the same POST.

I've many examples of using the URL class to connect to a server and have even copied and pasted many of them into my applet to test. Simply put, my problem is that the code produces no run-time errors but also does not POST anything! An Ethereal (network sniffer) trace shows a socket being opened to port 80 on the server but no data ever being POSTed to it.

Am I doing something stupid? The file being POSTed to is on the same server as the JAR file and so should not even require signing... Any ideas really appreciated as I'm stumped!

privatevoid writeIMG(){

DataOutputStream dataOut;

URL url;

URLConnection urlConn;

try{

url =new URL(getCodeBase().toString() + getParam("Script","upload.asp"));

urlConn = url.openConnection();

urlConn.setDoInput(true);

urlConn.setDoOutput(true);

urlConn.setUseCaches(false);

urlConn.setRequestProperty("Content-Type","multipart/form-data, boundary=AaB03x");

dataOut =new DataOutputStream(urlConn.getOutputStream());

dataOut.writeBytes("--AaB03x\r\n");

dataOut.writeBytes("Content-Disposition: form-data; name=\"file\"; filename=\"" + getParam("JFileName","image.jpg") +"\"\r\n");

dataOut.writeBytes("Content-Type: image/jpeg\r\n");

dataOut.writeBytes("\r\n");

// Squirt file data to output stream here

dataOut.writeBytes("\r\n--AaB03x--\r\n");

dataOut.flush();

dataOut.close();

showStatus("Picture Upload Completed");

}

catch (MalformedURLException me){

showStatus("ERROR: The Picture could not be uploaded to the server");

System.err.println("MalformedURLException: " + me);

}

catch (IOException ioe){

showStatus("ERROR: The Picture could not be uploaded to the server");

System.err.println("IOException: " + ioe.getMessage());

}

}

[3568 byte] By [Ian_McMichaela] at [2007-10-1 14:10:57]
# 1

I had a problem with .net when uploading because the upload script had a different auth

than the .net application:

webroot/dotNetApp/ was intergrated windows

webroot/uploadScript/ was anonymous.

IE refused to post any multipart data from the intergr. w to the anonymous folder.

Here is the code I used to POST multipart using the socket, it might work for you

the URLConnection wich would be the better option (proxy, session)

http://forum.java.sun.com/thread.jspa?threadID=530445&tstart=270

harmmeijera at 2007-7-10 17:34:58 > top of Java-index,Security,Signed Applets...
# 2
Sorry, http://forum.java.sun.com/thread.jspa?threadID=530445&tstart=270IS using URLConnection, the old version was using a socket.
harmmeijera at 2007-7-10 17:34:58 > top of Java-index,Security,Signed Applets...
# 3

After a day of experimenting and reading about the new .setChunkedStreamingMode method I finally realised where the problem was. Somehow the URLConnection class was failing to notice when it needed to send something. Clearly in the 1.5 release calling the .close method on the OutputStream is not enough for it to notice, count the bytes and send the POST command.

I've also changed over to a HttpURLConnection class and use the .setRequestMethod with a parameter of "POST" to be 100% sure the class realises what I'm trying to do.

To overcome the end of data issue I've added:

int iResp = urlConn.getResponseCode();

This is done immediately after closing the OutputStream. It seems to make the class work out it needs to send something over the wire and triggers the appropriate POST.

Hopefully this information will help someone else as confused as I've been for the last couple of days!

Ian_McMichaela at 2007-7-10 17:34:58 > top of Java-index,Security,Signed Applets...
# 4

Hi,

The URLCOnnection needs a complete handshake for a POST to occur. This means, once you open a connection, you have to readback the response for the POST to actually take place. I got stuck till this thought hit me. I tried and it worked. I'm posting a code for everyone's benefit !!

Hopefully, this (schema) should resolve your proble,

Cheersz

Balrog

URL url = new URL("http://localhost:8000/PublisherWeb/PublisherServlet");

URLConnection connection = url.openConnection();

connection.setDoOutput(true);

connection.setDoInput(true);

BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(connection.getOutputStream()));

String settledTradeXML = getTradeXML(0);//bid

System.out.println("PRinting : "+settledTradeXML);

if(settledTradeXML == null) {

throw new Exception("Error creating template");

}

writer.write(settledTradeXML);

writer.flush();

writer.close();

BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));

String s;

StringBuffer sb = new StringBuffer();

while((s = reader.readLine()) != null) {

sb.append(s);

}

reader.close();

Balrog1978a at 2007-7-10 17:34:58 > top of Java-index,Security,Signed Applets...
# 5

Hello Ian, here I am again.

Noticed the urlConn.setDoInput(true), this would make the URLConnection want to

receive something even if you don't.

It is allways a good idea to read the full response afterr connection because of the

implementation of "keep-alive"

http://java.sun.com/j2se/1.5.0/docs/guide/net/http-keepalive.html

Here is the code from the URL mentioned above:

// didn't mention what to do when setDoInput(false); but try to get responsecode and

// errorstream anyway:

// http://java.sun.com/j2se/1.5.0/docs/guide/net/http-keepalive.html

// need to read text

private String readTextInputStream(InputStream is,URLConnection urlc){

byte[] buf = new byte[1024];

ByteArrayOutputStream bos = new ByteArrayOutputStream();

try {

int len = 0;

while ((len = is.read(buf)) > 0) {

bos.write(buf, 0, len);

}

// close the inputstream

is.close();

} catch (IOException e) {

try {

// now failing to read the inputstream does not mean the server did not send

// any data, here is how you can read that data, this is needed for the same

// reason mentioned above.

((HttpURLConnection) urlc).getResponseCode();

InputStream es = ((HttpURLConnection) urlc).getErrorStream();

int ret = 0;

// read the response body

while ((ret = es.read(buf)) > 0) {

}

// close the errorstream

es.close();

} catch (IOException ex) {

// deal with the exception

}

}

// TODO: check if there was an enc in the response

//if so use that to convert the byte[] to string

//instead of the default

return new String(bos.toByteArray());

}

harmmeijera at 2007-7-10 17:34:59 > top of Java-index,Security,Signed Applets...
# 6

I just wanted to thank you guys for this thread. I was wrestling with this problem for a couple of days and wasn't able to cappture any kind of exceptions or stack traces...it appeared as though the binary streams written from an applet to a servlet were sucked into a "black hole". It turned out that two way communication was required as you guys state above to perform the POST. Thank you again.

wecoxepaa at 2007-7-10 17:34:59 > top of Java-index,Security,Signed Applets...
# 7

I faced the same problem but on trying to use the DataInputStream I got the following security exception

The exception is java.security.AccessControlException: access denied (java.util.PropertyPermission http.strictPostRedirect read)

My code is as below

DataOutputStream outFd;

URL currentPage = getCodeBase();

String protocol = currentPage.getProtocol();

String host = currentPage.getHost();

int port = currentPage.getPort();

String urlSuffix = "/deleteData";

URL postUrl = new URL(protocol, host, port, urlSuffix);

System.out.println("The url is " + postUrl.toString());

URLConnection urlConn = postUrl.openConnection();

urlConn.setUseCaches(false);

urlConn.setDoInput(true);

urlConn.setDoOutput(true);

urlConn.setRequestProperty("Cookie", authCookie);

outFd = new DataOutputStream( urlConn.getOutputStream());

outFd.writeBytes("user=");

outFd.flush();

outFd.close();

DataInputStream inpFd = new DataInputStream(urlConn.getInputStream());

The url that is getting created for the connection us the url from which the applet was served. Any help much appreciated.

gautamnva at 2007-7-10 17:34:59 > top of Java-index,Security,Signed Applets...
# 8
A little more investigation shows that the server is returning a 400 bad request and I have absolutely no clue why this would happen. Any ideas please?
gautamnva at 2007-7-10 17:34:59 > top of Java-index,Security,Signed Applets...
# 9

Hi folks,

I am still battling with the HTTP Post in Java.

The Request is executed allright but the actual POST data is not sent accross the wire, as I can see using a HTTP Sniffer. All headers - includeng the Content-Length - are set correctly though...

Any help is highly appreciated!

My Code:

public void connect()

{

String loginData="Username=foo&Passwd=bar"

URL url=new URL("http", "192.168.32.250", 80, "/tgi/login.tgi");

System.out.println("Connecting...");

URLConnection conn=url.openConnection();

conn.setDoOutput(true);

conn.setDoInput(true);

DataOutputStream out=new DataOutputStream(conn.getOutputStream());

out.writeBytes(loginData);

out.flush();

out.close();

StringBuffer document = readResult(conn);

System.out.println(new String(document));

}

private static StringBuffer readResult(URLConnection c) throws IOException

{

StringBuffer document=new StringBuffer();

String str;

DataInputStream in=new DataInputStream(c.getInputStream());

while(null!=(str=in.readLine()))

{

document.append(str).append('\n');

}

return document;

}

benvogela at 2007-7-10 17:34:59 > top of Java-index,Security,Signed Applets...