2

First of all, my question is about HttpServer in Java to handle the POST request from a client, not about a Java client who can upload file to a web server.

OK. I am using a lightweight HttpServer in Java to handle "GET" || "POST" requests. The source code of the HttpServer is copied from http://www.prasannatech.net/2008/11/http-web-server-java-post-file-upload.html.

/*
 * HTTPPOSTServer.java
 * Author: S.Prasanna
 * @version 1.00 
 */

import java.io.*;
import java.net.*;
import java.util.*;

public class HTTPPOSTServer extends Thread {

    static final String HTML_START = 
        "<html>" +
        "<title>HTTP POST Server in java</title>" +
        "<body>";

    static final String HTML_END = 
        "</body>" +
        "</html>";

    Socket connectedClient = null;    
    BufferedReader inFromClient = null;
    DataOutputStream outToClient = null;


    public HTTPPOSTServer(Socket client) {
        connectedClient = client;
    }            

    public void run() {

        String currentLine = null, postBoundary = null, contentength = null, filename = null, contentLength = null;
        PrintWriter fout = null;

        try {

            System.out.println( "The Client "+
                    connectedClient.getInetAddress() + ":" + connectedClient.getPort() + " is connected");

            inFromClient = new BufferedReader(new InputStreamReader (connectedClient.getInputStream()));                  
            outToClient = new DataOutputStream(connectedClient.getOutputStream());

            currentLine = inFromClient.readLine();
            String headerLine = currentLine;                
            StringTokenizer tokenizer = new StringTokenizer(headerLine);
            String httpMethod = tokenizer.nextToken();
            String httpQueryString = tokenizer.nextToken();

            System.out.println(currentLine);

            if (httpMethod.equals("GET")) {    
                System.out.println("GET request");        
                if (httpQueryString.equals("/")) {
                    // The default home page
                    String responseString = HTTPPOSTServer.HTML_START + 
                        "<form action=\"http://127.0.0.1:5000\" enctype=\"multipart/form-data\"" +
                        "method=\"post\">" +
                        "Enter the name of the File <input name=\"file\" type=\"file\"><br>" +
                        "<input value=\"Upload\" type=\"submit\"></form>" +
                        "Upload only text files." +
                        HTTPPOSTServer.HTML_END;
                    sendResponse(200, responseString , false);                                
                } else {
                    sendResponse(404, "<b>The Requested resource not found ...." +
                            "Usage: http://127.0.0.1:5000</b>", false);                  
                }
            }
            else { //POST request
                System.out.println("POST request"); 
                do {
                    currentLine = inFromClient.readLine();

                    if (currentLine.indexOf("Content-Type: multipart/form-data") != -1) {
                        String boundary = currentLine.split("boundary=")[1];
                        // The POST boundary                           

                        while (true) {
                            currentLine = inFromClient.readLine();
                            if (currentLine.indexOf("Content-Length:") != -1) {
                                contentLength = currentLine.split(" ")[1];
                                System.out.println("Content Length = " + contentLength);
                                break;
                            }                      
                        }

                        //Content length should be < 2MB
                        if (Long.valueOf(contentLength) > 2000000L) {
                            sendResponse(200, "File size should be < 2MB", false);
                        }

                        while (true) {
                            currentLine = inFromClient.readLine();
                            if (currentLine.indexOf("--" + boundary) != -1) {
                                filename = inFromClient.readLine().split("filename=")[1].replaceAll("\"", "");                                        
                                String [] filelist = filename.split("\\" + System.getProperty("file.separator"));
                                filename = filelist[filelist.length - 1];                          
                                System.out.println("File to be uploaded = " + filename);
                                break;
                            }                      
                        }

                        String fileContentType = inFromClient.readLine().split(" ")[1];
                        System.out.println("File content type = " + fileContentType);

                        inFromClient.readLine(); //assert(inFromClient.readLine().equals("")) : "Expected line in POST request is "" ";

                        fout = new PrintWriter(filename);
                        String prevLine = inFromClient.readLine();
                        currentLine = inFromClient.readLine();              

                        //Here we upload the actual file contents
                        while (true) {
                            if (currentLine.equals("--" + boundary + "--")) {
                                fout.print(prevLine);
                                break;
                            }
                            else {
                                fout.println(prevLine);
                            }    
                            prevLine = currentLine;                      
                            currentLine = inFromClient.readLine();
                        }

                        sendResponse(200, "File " + filename + " Uploaded..", false);
                        fout.close();                   
                    } //if                                              
                }while (inFromClient.ready()); //End of do-while
            }//else
        } catch (Exception e) {
            e.printStackTrace();
        }    
    }

    public void sendResponse (int statusCode, String responseString, boolean isFile) throws Exception {

        String statusLine = null;
        String serverdetails = "Server: Java HTTPServer";
        String contentLengthLine = null;
        String fileName = null;        
        String contentTypeLine = "Content-Type: text/html" + "\r\n";
        FileInputStream fin = null;

        if (statusCode == 200)
            statusLine = "HTTP/1.1 200 OK" + "\r\n";
        else
            statusLine = "HTTP/1.1 404 Not Found" + "\r\n";    

        if (isFile) {
            fileName = responseString;            
            fin = new FileInputStream(fileName);
            contentLengthLine = "Content-Length: " + Integer.toString(fin.available()) + "\r\n";
            if (!fileName.endsWith(".htm") && !fileName.endsWith(".html"))
                contentTypeLine = "Content-Type: \r\n";    
        }                        
        else {
            responseString = HTTPPOSTServer.HTML_START + responseString + HTTPPOSTServer.HTML_END;
            contentLengthLine = "Content-Length: " + responseString.length() + "\r\n";    
        }            

        outToClient.writeBytes(statusLine);
        outToClient.writeBytes(serverdetails);
        outToClient.writeBytes(contentTypeLine);
        outToClient.writeBytes(contentLengthLine);
        outToClient.writeBytes("Connection: close\r\n");
        outToClient.writeBytes("\r\n");        

        if (isFile) sendFile(fin, outToClient);
        else outToClient.writeBytes(responseString);

        outToClient.close();
    }

    public void sendFile (FileInputStream fin, DataOutputStream out) throws Exception {
        byte[] buffer = new byte[1024] ;
        int bytesRead;

        while ((bytesRead = fin.read(buffer)) != -1 ) {
            out.write(buffer, 0, bytesRead);
        }
        fin.close();
    }

    public static void main (String args[]) throws Exception {

        ServerSocket Server = new ServerSocket (5000);         
        System.out.println ("HTTP Server Waiting for client on port 5000");

        while(true) {                                         
            Socket connected = Server.accept();
            (new HTTPPOSTServer(connected)).start();
        }      
    }
}

I read through the code, I think the code should be all right.

But when I try to upload a file, it will print out POST request, and then hang there and never receive any bytes.

If you are willing to, you can run the above source code directly. After launch it, you can type 127.0.0.1:5000 in a browser, and it will show a file upload, then if I try upload a file, it will hang there after printing PoST request.

If you are bored to read the code, may I ask the following simpler question?

So, what exactly Chrome or any other web browser do about form -> input type='file'?

If I am using a ServerSocket to handle the HTTP request, I just get the InputStream of the request, and then all the content (including HTTP headers & the uploading file's content) will go through that InputStream, right?

The above code can analyse the headers, but then it seems nothing is sent from the browser any more.

Can anyone pls help?

Thanks

1
  • did you find answer for this? Commented Oct 6, 2017 at 19:11

3 Answers 3

2

It hangs because client (Chrome, in my case) does not provide Content-Length. RFC 1867 is pretty vague about it. It kind of suggests it but does not force it and does not have an example. Apparently clients would not always send it. The code should safeguard against missing length. Instead it goes through the loop until it reaches the end of file. Then it hangs.

Using debugger is very helpful at times.

Sign up to request clarification or add additional context in comments.

Comments

0

Thats a lotta code :)

Let start by moving the break; calls out of the if statements inside the POST section, starting with line 83. We need to figure out what is hanging and those while statements could easily be the issue.

This will help us figure out where the issue is.

If you just want it to work, and don't really care what the bug is, this is sort of re-inventing the wheel, there are a ton of libraries out there to make this a one or two line operation.

Here's a good one : http://www.servlets.com/cos/ - look at the MultiPartRequest class (source is available in download)

Comments

0

This is an old question, but in case others stumble upon it looking for an answer to the title question rather than the specific bug mentioned in the details (I have a feeling that's most viewers)... I would recommend you save yourself the pain and not use the above code snippet.

It is not an HTTP server and it will fail on any but the simplest use case (and apparently even then), nor does is follow basic good coding practices. Even if it weren't for that, it explicitly states it supports text files only (and indeed reads the whole file into a String), and even then doesn't properly handle charset encodings.

That being said, you're probably here looking for one of two answers - how you can accept file uploads in your application, or how an HTTP server itself implements this.

If you are interested in how to do this for fun or educational purposes, I do highly recommend reading the RFCs (RFC 7230 for core HTTP/1.1, RFC 2046 section 5.1 for multipart parsing) and trying to write a simple HTTP-like server like this one. It's a good way to learn, especially if you have an experienced developer to review your code and give you tips and help you find edge cases. As an exercise, you can even start with the code above and try to fix its shortcomings and make it a bit more usable, though still, don't confuse that with a real HTTP server for use in production.

If you don't care for all this and just want to get things done in a real application, I recommend just using a proper HTTP server. There are plenty of them around that will let you do what the above snippet tries to, with much less code and bugs.

Disclaimer: I'm the author of JLHTTP - The Java Lightweight HTTP Server which is a tiny one-file server (or ~50K/35K jar) with no dependencies that strives to be RFC-compliant and supports file uploads among other things. Feel free to use it, or just browse the code and documentation for a relatively simple example of how an HTTP server and multipart parsing (file uploads) might work, both as implemented by the server itself and how you can use this in your application. Or check out any of the many other HTTP servers out there that can do the same.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.