Basic Web Server

seanbp 0 Tallied Votes 935 Views Share

The server only does the basics.
TODOs:
The header method needs expanding. The file send method can't handle too large files. Maybe write custom buffer class since some buffering is done. Keep cache of recent files.

public class WebServer {

    public static String version = "Java Web Server 0.0";

    public static void main(String[] args) {
        try {
            ServerSocket ss = new ServerSocket(8080);
            System.out.println(version);
            while (ss.isBound()) new Thread(new Client(ss.accept())).start();
        } 
        catch (IOException e) { e.printStackTrace(); }
    }

}


class Client implements Runnable {

    private static final String userdir = System.getProperty("user.dir");
    static final byte[] EOL = {(byte) '\r', (byte) '\n'};
    private Socket accept;
    private InputStream is;
    private PrintStream os;

    private enum Method {

        GET,
        HEAD,
        UNSUPPORTED;
    }

    public Client(Socket accept) {
        this.accept = accept;
    }

    public void run() {
        try {

            // variables
            is = new BufferedInputStream(accept.getInputStream());
            os = new PrintStream(accept.getOutputStream());
            int character;
            String req = "";
            String[] request;
            Method method;
            File file;

            // store first line of request header
            character = is.read();
            while (character != '\n' && character != '\r') {
                req += (char) character;
                character = is.read();
            }
            System.out.println(req);
            request = req.split(" ");

            // store method
            if (request[0].matches("GET")) {
                method = Method.GET;
            } else if (request[0].matches("HEAD")) {
                method = Method.HEAD;
            } else {
                method = Method.UNSUPPORTED;
            }

            // logic!
            request[1] = request[1].replace("/", File.separator);
            file = new File(userdir + File.separator + request[1]);
            if (file.exists() && !file.isHidden()) {
                if (method == Method.GET || method == Method.HEAD) {
                    writeHeader(file, 200);
                    if (method == Method.GET) {
                        if (file.isFile()) {
                            sendFile(file);
                        } else if (file.isDirectory()) {
                            listDir(request[1], file);
                        }
                    }
                } else {
                    writeHeader(file, 501);
                }
            } else {
                writeHeader(file, 404);
            }

        } catch (IOException ex) {
            ex.printStackTrace();
        } finally {
            try {
                accept.close();
            } catch (IOException ex) {
                System.exit(1);
            }
        }
    }

    private void sendFile(File file) throws FileNotFoundException, IOException {
        int bufferlen = (int) file.length();
        byte buffer[];
        buffer = new byte[bufferlen];
        InputStream fs = new FileInputStream(file);
        int len = fs.read(buffer);
        while (len < bufferlen) {
            len += fs.read(buffer, len, bufferlen - len);
        }
        os.write(buffer);
        os.flush();
    }

    private void listDir(String currentDir, File dir) {
        currentDir = currentDir.replace(File.separator, "/");
        String listing[] = dir.list();
        if (!currentDir.endsWith("/")) {
            currentDir += "/";
        }
        os.println(WebServer.version + "<br>");
        for (String item : listing) {
            os.println("<a href=\"" + currentDir + item + "\">" + item + "</a><br>");
        }
        os.flush();
    }

    private void writeHeader(File f, int code) throws IOException {
        String fname = f.getName();
        os.print("HTTP/1.0 ");

        switch (code) {
            case 200:
                os.print("200 OK");
                break;
            case 400:
                os.print("400 Bad Request");
                break;
            case 404:
                os.print("404 Not Found");
                break;
            case 501:
                os.print("501 Not Implemented");
                break;
        }
        os.write(EOL);

        if (code == 200) {
            os.print("Content-Type: ");
            if (fname.endsWith("html") || fname.endsWith("htm")) {
                os.print("text/html");
            } else if (fname.endsWith("java")) {
                os.print("text/plain");
            } else if (fname.endsWith("jpeg") || fname.endsWith("jpg")) {
                os.print("image/gif");
            } else {
                os.print("text/html");
            }
            os.write(EOL);
        }

        os.write(EOL);
        os.flush();
    }
}
bords 1 Light Poster

ahmmm, what are the libraries that to be imported in this project....?

seanbp 4 Junior Poster
import java.io.*;
import java.net.*;
Kris_1 0 Newbie Poster

Nice. Thanks. I was looking for something like this and here I found it.

With a few small modifications I can use this to quickly serve up some static web content to test in a web browser.

Would you mind if I stick the modified version in a github repo? That way I can always get to it easily. You can of course get full credit for the code. I'll stick whatever copyright notice you like at the top of the file.

Thanks,

Kris

~s.o.s~ 2,560 Failure as a human Team Colleague Featured Poster

You might want to look at NanoHTTPD. Single file web server which supports static serving as per the home page.

JamesCherrill 4,733 Most Valuable Poster Team Colleague Featured Poster

Kris.
Content posted on Daniweb is subject to Daniweb's T&Cs, including

DaniWeb LLC reserves full rights and privileges to information posted to anywhere within the daniweb.com domain by its members and staff. Any and all information posted on DaniWeb may not be copied or used elsewhere, in any way, shape, or form, either on the Internet or in print, without prior written permission from an authorized employee of DaniWeb LLC.

Please contact Dani if you want to copy any content - you will find her friendly and cooperative as long as Daniweb's rights are protected.

Kris_1 0 Newbie Poster

@JamesCherrill: "Please contact Dani"

I thought I was contacting the author of this article by posting here.
I don't really want a lot of hassles. I liked what I found here and used it for a bit of quick testing. The code neede a few small modification to do what I want.

Should I have need of something like it again, it would be nice if I had my own 'fork' on github. But if I have to jump through a lot of hoops to do that I won't bother its not that important.

In any case I thank you all, and especially the original author of this article. The code here has helped me :-)

@.s.o.s Thanks for the pointer to NanoHttpD. Actually that looks pretty good. I might use that next time I need a quick test server.

JamesCherrill 4,733 Most Valuable Poster Team Colleague Featured Poster

Hi Kris
Please don't be put off. The T&Cs are tedious but necessary to protect us from some of the unscrupulous bad guys out there. All you need is a quick OK from Dani; no need to jump through any hoops, and nobody will give you any hassles.
J

Kris_1 0 Newbie Poster

Hi James,

Sure, I understand perfectly about the T&C. As developer working in a corporate environment, sadly I'm only too familiar with this sort of thing :-)

It's just a matter of whether or not its worth the extra time and effort right now to follow up.

I'm sure you understand that as well.

I'm still grateful for your time to respond.

All you need is a quick OK from Dani

That was what I was hoping. I.e. just ask politely and get the 'ok'. I thought that was what I was doing by posting here. This may seem like a dumb question. But if not by posting a comment here... How do I contact Dani??

You see... there's the hassle right there :-)

Kris

JamesCherrill 4,733 Most Valuable Poster Team Colleague Featured Poster

You can PM Dani directly from her user profile page http://www.daniweb.com/members/1/Dani ("Send Private Message" button near top left corner). Go ahead, she's cool.

timetraveller1992 10 Newbie Poster

@Kris I'm pretty sure you can use this code anywhere you like. After all daniweb is made for the public and anything that a person (a user) posts can be used anywhere you like. If you add credits that you found the original code here thats pretty good because your being grateful. Other than that I'm sure there are no restrictions!

JamesCherrill 4,733 Most Valuable Poster Team Colleague Featured Poster

timetraveller1992

You are 100% wrong, and posting such incorrect legal advice is dangerous for anyone foolish enough to follow it.

To make this absolutely clear, here is a relevant extract from the DaniWeb TOS that every member agrees to when they sign up:

DaniWeb LLC reserves full rights and privileges to information posted to anywhere within the daniweb.com domain by its members and staff. Any and all information posted on DaniWeb may not be copied or used elsewhere, in any way, shape, or form, either on the Internet or in print, without prior written permission from an authorized employee of DaniWeb LLC.

Dani is not a difficult or unpleasant person, but she has a huge personal investment in this site, and has every right to protect it as necessary. Contact her for any further discussion about reproduction rights - done properly it's unlikely to be a problem.

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.