0

I created a Java webserver that should send clients webpage files when the server's IP address is searched on their browsers. The problem is that I can only send an HTML file but I need to send CSS and also images that is embedded in the HTML file. Although I already linked the HTML file to an external CSS code and images, the CSS and images weren't displayed. I was at least able to get the CSS working because I inserted all the CSS codes directly in the HTML code. I am looking to find a way that enables the images to be displayed in the client's browser and if possible, also a way to send the external CSS code so I don't need to write CSS codes directly into HTML files in the future. It would be great if you could show the codes to fix the problem.

This is my main Server class:

package myserver.pkg1.pkg0;

import java.net.*;

public class Server implements Runnable {

    protected boolean isStopped = false;
    protected static ServerSocket server = null;

    public static void main(String[] args) {

        try {

            server = new ServerSocket(9000);
            System.out.println("Server is ON and listening for incoming requests...");
            Thread t1 = new Thread(new Server());
            t1.start();

        } catch(Exception e) {
            System.out.println("Could not open port 9000.\n" + e);
        }

    }

    @Override
    public void run() {

        while(!isStopped) {

            try {
                Socket client = server.accept();
                System.out.println(client.getRemoteSocketAddress() + " has connected.");
                Thread t2 = new Thread(new Server());
                t2.start();
                new Thread(new Worker(client)).start();
            } catch(Exception e) {
                System.out.println(e);
            }

        }

    }

}

As you can see after the server accepts request, the client socket variable is forwarded to a new class Worker. The Worker class handles each output to each clients.

This is Worker class:

package myserver.pkg1.pkg0;

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

public class Worker implements Runnable {

    protected Socket client;

    public Worker(Socket client) {
        this.client = client;
    }

    @Override
    public void run() {

        try {
            PrintWriter out = new PrintWriter(client.getOutputStream());       
            out.println("HTTP/1.1 200 OK");
            out.println("Content-type: text/html");
            out.println("\r\n");
            out.flush();
            out.close();
            client.close();

        } catch(Exception e) {
            System.out.println(e);
        }

    }

}
6
  • are you working with apache? Commented Jul 31, 2017 at 6:30
  • You are faking a HTTP server but only send a response. Why not use an existing HTTP server? Problems: a) You does not read a request from the client. b) Your running server instance starts a new server instance on each client request. Commented Jul 31, 2017 at 6:34
  • you can use inline data: images tools.ietf.org/html/rfc2397 Commented Jul 31, 2017 at 6:42
  • @user7294900 no Commented Aug 1, 2017 at 7:20
  • @Konrad What do you mean by using an existing HTTP server? I'm really new in java networking and HTTP. Commented Aug 1, 2017 at 7:23

4 Answers 4

1

Since you are re-inventing the wheel, i'm assuming this question is for academic purposes. If not, you can always host your css, images and other static content on a CDN and refer to them in your HTML.

Now, what you are doing here is responding to a TCP request and not a HTTP request. Your first step should be to write a Request Handler, that captures the inputstream from the TCP socket. Then parse the stream into a valid HTTP Request. Then capture the URL path from the http request and serve content based on the path. This way you can refer to relative paths on your server for images/css. The handler for those paths should be able to map to a filesystem and pick the relevant file and compose it into a http response.

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

Comments

0

I think you can do something like this in your Worker class,

    @Override
        public void run() {

            try {

           // Get html content in string or build your static string here.
           StringBuilder contentBuilder = new StringBuilder();
           try {
             BufferedReader in = new BufferedReader(new FileReader("mypage.html"));
             String str;
             while ((str = in.readLine()) != null) {
               contentBuilder.append(str);
             }
             in.close();
           } catch (IOException e) {
           }
           String content = contentBuilder.toString();

           // Here logic to search and get that file here.
           File file = new File("demo.html");

           //After getting file, to write data in that file,
           PrintWriter writer = new PrintWriter(file);
           writer.write(content);
           writer.close();

            } catch(Exception e) {
                System.out.println(e);
            }

        }

Hope this helps.

Comments

0
   out.println("<img src=\"https://static.oschina.net/uploads/space/2017/0730/143737_rMYR_2903254.jpg\">");

just this code can display ur image

Comments

0

As of Java 6, there is an http server in the JDK that you can use.

Otherwise, you need to read the request, at least the first line, and supply a different output depending on the URL in the request.

UPDATE:

You can read the HTTP line like this:

private String readHttpLine() throws IOException {
    InputStream stream = client.getInputStream();
    Reader reader = new InputStreamReader(stream);
    BufferedReader in = new BufferedReader(reader);
    String line = in.readLine();
    if (line == null) {
        throw new IOException("No HTTP line");
    }
    return line;
}

You can use a regexp to parse the HTTP line:

private static Pattern HTTP_LINE = Pattern.compile(
        "([A-Z]+) +(.*) +HTTP/([0-9]+\\.[0-9]+)",
        Pattern.CASE_INSENSITIVE);

You would then parse it like this:

        String line = readHttpLine();
        Matcher matcher = HTTP_LINE.matcher(line);
        if (!matcher.matches()) {
            throw new IOException("Invalid HTTP line");
        }
        String method = matcher.group(1).toUpperCase();
        String path = matcher.group(2);
        String httpVersion = matcher.group(3);

Now you can test the method and the path to provide the HTTP response:

        if (method.equals("GET")) {
            switch (path) {
                case "/":
                case "/index.html":
                    PrintWriter out = new PrintWriter(client.getOutputStream());       
                    out.print("HTTP/1.1 200 OK\r\n");
                    out.print("Content-type: text/html\r\n");
                    out.print("\r\n");
                    //In this line I used out.println("full html code"); but I'd like a simpler way where it can search for the html file in the directory and send it.
                    out.flush();
                    out.close();
                    break;
                case "/style.css":
                    // provide CSS stylesheet
                    break;
                case "/image1.png":
                    // provide image 1
                    break;
                case "/image2.jpeg":
                    // provide image 1
                    break;
            }
        }

Of course, unless the content is dynamic, you can keep in in files and return the appropriate file content.

UPDATE 2:

Example to supply files in resources:

...

    if (method.equals("GET")) {
        switch (path) {
            case "/":
            case "/index.html":
                Writer out = new OutputStreamWriter(
                        client.getOutputStream(), "UTF-8");       
                out.write("HTTP/1.1 200 OK\r\n");
                out.write("Content-type: text/html\r\n");
                out.write("\r\n");
                //In this line I used out.println("full html code"); but I'd like a simpler way where it can search for the html file in the directory and send it.
                out.close();
                break;
            default:
                supplyFile(path);
                break;
        }
    }

The supplyFile method looks like that:

private void supplyFile(String path) throws IOException {
    String contentType = mimetypes.getContentType(path);
    OutputStream stream = client.getOutputStream();
    Writer out = new OutputStreamWriter(stream, "UTF-8");       
    out.write("HTTP/1.1 200 OK\r\n");
    out.write("Content-type: " + contentType + "\r\n");
    out.write("\r\n");
    out.flush();
    try (InputStream istream = getClass().getResourceAsStream(path)) {
        byte[] buf = new byte[4096];
        for (int n = istream.read(buf); n > 0; n = istream.read(buf)) {
            stream.write(buf, 0, n);
        }
    }
    out.close();
}

3 Comments

How do I provide the css file and images in the switch case statement?
@SomBoii the same way you provide the html
@SomBoii except that you shouldn't use println, but always end a line with "\r\n"

Your Answer

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