Member Avatar for masterofpuppets

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.

Member Avatar for masterofpuppets

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?

Member Avatar for masterofpuppets

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.

Member Avatar for masterofpuppets

ahh, thanks man dodn't know that :D, I'll try to fix it now

Get a HexEditor and look at the contents of different types of files.

Member Avatar for masterofpuppets

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++;
}
Member Avatar for masterofpuppets

Is there a way that I can view the browser request before it is sent to the server?

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);
		}
	}
Member Avatar for masterofpuppets

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

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.