Hi all,

I am writing a server in Java and I have an issue which I've been working on for days now and I can't seem to find a solution. I want to upload files to the server using an HTML form. I can read the whole POST request and the data that it contains but when I try to create the file in my server space, it seems corrupted. Here is the upload request:

POST /uploadprofilepicture HTTP/1.1
Host: www.gravyty.com
User-Agent: Mozilla/5.0 (Windows NT 6.1; rv:2.0.1) Gecko/20100101 Firefox/4.0.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip, deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Connection: keep-alive
Referer: http://www.gravyty.com/UserHome.html
Content-Type: multipart/form-data; boundary=---------------------------105852418210285
Content-Length: 812

-----------------------------105852418210285
Content-Disposition: form-data; name="uploadfile"; filename="bday.gif"
Content-Type: image/gif

GIF89a
-----------------------------105852418210285--

and here's the way I read that request:

BufferedReader is = new BufferedReader( new InputStreamReader( s.getInputStream() ) );
String clientData = "", method = "", boundary = "", line;
int lineCount = 0;
         	
while ( (line = is.readLine()) != null ) {
	if ( line.toLowerCase().startsWith( "get" ) )
		method = "g";
	else if ( line.toLowerCase().startsWith( "post" ) )
		method = "p";
	
	if ( line.length() <= 0 && method.equals( "g" ) )
		break;
	else if ( method.equals( "p" ) ) {
		if ( line.contains( "boundary=" ) ) {
			boundary = line.substring( line.indexOf( "boundary=" ) + 9, line.length() );
		}
		else if ( !boundary.equals( "" ) && line.equals( "--" + boundary + "--" ) ) {
			clientData += line + '\n'; // separate each new line.
			break;
		}
	}
	
	clientData += line + '\n';
	lineCount++;
}

and here's how I create the file:

try {
	FileOutputStream fos = new FileOutputStream( "Resources/" + name );
	fos.write(data.getBytes());
	fos.close();
	// data is the string of symbols from the request
}

Any ideas? I have tried using JFileUpload but with no luck and I can upload .txt files.

when I try to create the file in my server space, it seems corrupted

Have you compared the input file to the output file (byte by byte) to see exactly what the differences are?

Where do you read/handle binary/non-text data? Your posted code appears to only handle text.

Edited 5 Years Ago by NormR1: n/a

Have you compared the input file to the output file (byte by byte) to see exactly what the differences are?

Yeah, I checked that and I found out that my file has some new lines inserted in some places ( I assume that's coming from the way I read the request? ) Also I tried to open the .pdf file ( for example ), copy its contents, create a new file with the same name elsewhere and copy the contents there and it doesn't open. Actually, it does but gives me an error saying the file is corrupted.

You are reading the incoming data as text/characters vs as binary bytes.

clientData += line + '\n';

What does this line do?

Edited 5 Years Ago by NormR1: n/a

it is supposed to add a new line to the end of the line that is read since readline() does not include the \n. This might be the problem actually. I have tried a number of ways for reading the request but they were not working properly.

Files made of binary data like images don't contain "lines" with line-end characters.
They contain bytes with any of 256 different values.

Edited 5 Years Ago by NormR1: n/a

OK, here's what I have so far. I managed to read the POST request but Java adds extra '?' characters in some places and I don't know why. Could it be an encoding issue? Here's how I read the POST data:

int contentType;
String line;
String headers;

// Read header lines.
while ( (line = is.readLine()).length() > 0 ) {
    headers += (line + "\n");
    if ( line.startsWith( "Content-Length: " ) )
	len = Integer.parseInt( line.substring( "Content-Length: ".length(), line.length() ) );
    numLines++;
}

// Read data.
char[] buffer = new char[ len ];
char c;
int count = 0;
while ( count < len ) {
    c = (char) is.read();
    buffer[ count ] = c;
    count++;
}

You may still be creating problems by trying to read binary data as if it is character. That will read 1 byte per character from the input stream, but convert to Unicode 2-byte chars to store in a char array, with results that may be unexpected for random binary input.
To read a binary file you can read it verbatim from the input stream (not a Reader) in nice chunks with
read(byte[] b) - Reads some number of bytes from the input stream and stores them into the buffer array b. The number of bytes actually read is returned as an integer.

By way of illustration, here a little bit of code that does the opposite of your case - ie copies an arbitrary binary file from a local file to a remote client - but it illustrates the ideas well

public void send(InputStream file, String mimeType, Socket clientSocket) {
		// send a file that has an input stream already opened
		try {
			// Acquire an output stream
			DataOutputStream outbound = new DataOutputStream(clientSocket
					.getOutputStream());
			// Send the response header and content
			outbound.writeBytes("HTTP/1.0 200 OK\r\n");
			outbound.writeBytes("Content-type: " + mimeType + "\r\n");
			outbound.writeBytes("Content-Length: " + file.available() + "\r\n");
			outbound.writeBytes("\r\n");

			byte[] data = new byte[4096];
			int count;
			while ((count = file.read(data)) != -1) {
				outbound.write(data, 0, count);
			}
			file.close();
			outbound.close();
		} catch (IOException ex) {
			System.out.println(ex);
		}
	}

Edited 5 Years Ago by JamesCherrill: n/a

Thanks for the advice.. Got it working now - I'm reading bytes instead of characters by using what you've suggested above.

This question has already been answered. Start a new discussion instead.