0

Attempting to build a web server from scratch. It's working for html, and other plain text files. Tested in Firefox and Chrome. But I'm having difficulty getting images to display properly. Status 200 returned, in Firefox I get the attached image on request. Other than the response header, do I need to handle image filetypes differently with the printstream?

enter image description here

FileInputStream fileIn = new FileInputStream("test/" +
                file);

// split specified file path
String[] pathTokens = tokens[1].split("/|\\.");
String fileExt = pathTokens[tokens.length - 1];

// build response
out.println("HTTP/1.1 200 OK");
if(fileExt.equals("jpg") || fileExt.equals("jpeg") ||fileExt.equals("png") || 
   fileExt.equals("ico"))
  out.println("Content type: image/" + fileExt);
else
  out.print("Content type: text/");
if(fileExt.equals("html"))
  out.println(fileExt);
else
  out.println("plain");

long size = fileIn.getChannel().size();

out.println("Content-Length: " + Long.toString(size));
out.println("Connect: Close");
out.println("");

int read = 0;
byte[] buffer = new byte[1024];

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

If any further information is needed, please request. I'm more than willing to provide any additional details, or answer any questions I can.

EDIT: Upon further examination I'm actually getting 404 in Firefox, and I'm not really sure what Chrome is, the page displayed is "This site cannot be reached...", but it appears I'm getting 200 returned.

  • 1
    `if(fileExt.equals("html"))` should be `else if(fileExt.equals("html"))` (or some how attached to your previous `else`... basically, **use** braces). Also, **why** are you doing this? – Elliott Frisch May 28 '17 at 00:09
  • The line terminator should be `\r\n`, not whatever `println()` gives you. – user207421 May 28 '17 at 00:40
  • @ElliottFrisch Sorry preemptive comment earlier. You are correct thought, that was a problem. The other half of my issue wasn't shown in the selected code. –  May 28 '17 at 00:52
  • @EJP Both maybe acceptable then, because I currently have it working and I'm not using `\r\n`. –  May 28 '17 at 00:54
  • @wanderbread Then you're using Windows. Care to guess how we know? (Spoiler: That's the only place it will work. Not Mac, not Linux). – Elliott Frisch May 28 '17 at 00:56
  • @ElliottFrisch That's actually not the case. I'm running Sierra. Notice my path syntax, that's something that wouldn't work on Windows. –  May 28 '17 at 01:06
  • @wanderbread Actually, Java will translate paths. Apologies. The default line ending on classic macs was "\r" and I think they've switched to "\n". Regardless, HTTP requires "\r\n". https://stackoverflow.com/questions/5757290/http-header-line-break-style – Elliott Frisch May 28 '17 at 01:07
  • @ElliottFrisch All I'm saying is it's currently working without me explicitly putting that in, so maybe something else has changed that you weren't aware of. I'm not going to comment further in regards to this because it's no longer productive. You can believe what you want. –  May 28 '17 at 01:13
  • 2
    It doesn't matter what's acceptable. What matters is what is right. The RFC philosophy is 'be conservative in what you send and liberal in what you accept'. *Ergo* you should send only what's correct. – user207421 May 28 '17 at 01:42
  • You need to decide whether you're getting 404 or 200. You aren't getting both. If you're getting 404, this code isn't being executed. – user207421 May 28 '17 at 01:43
  • @EJP I agree with your point. Yeah turns out the test statement for printing the 404 line in the response, wasn't working as I expected. But in the Chrome developers console it shows these associated requests for the file, there's three that look very similar, each time I attempt to access the file, (and these aren't showing in the associated window in Firefox) `Request URL:data:image/png;base64,[too much to include] Request Method:GET Status Code:200 OK (from memory cache) Referrer Policy:no-referrer-when-downgrade`. I'm no expert just trying to learn, but that's what I was referring to. –  May 28 '17 at 01:57
  • A cached response doesn't execute this code either. – user207421 May 28 '17 at 02:13

1 Answers1

0

I think I can see a bug:

if(fileExt.equals("jpg") || fileExt.equals("jpeg") ||fileExt.equals("png") || 
   fileExt.equals("ico"))
  out.println("Content type: image/" + fileExt);
else
  out.print("Content type: text/");
if(fileExt.equals("html"))
  out.println(fileExt);
else
  out.println("plain");

If I re-indent and insert {}'s where the Java compiler thinks they would be.

if (fileExt.equals("jpg") || fileExt.equals("jpeg") || 
    fileExt.equals("png") || fileExt.equals("ico")) {
    out.println("Content type: image/" + fileExt);
} else {
    out.print("Content type: text/");
}
if (fileExt.equals("html")) {
    out.println(fileExt);
} else {
    out.println("plain");
}

See the problem? If the extension is (say) "jpg", you will get a spurious "plain" line added to the header.

I think you actually meant to write this:

if (fileExt.equals("jpg") || fileExt.equals("jpeg") || 
    fileExt.equals("png") || fileExt.equals("ico")) {
    out.println("Content type: image/" + fileExt);
} else {
    out.print("Content type: text/");
    if (fileExt.equals("html")) {
        out.println(fileExt);
    } else {
        out.println("plain");
    }
}

This illustrates:

  1. The importance of getting making the indentation of your code match what the code actually says. (Hint: use your IDE's auto-indentation functionality!)
  2. That you should get into the habit of always using curly bracket blocks with all control constructs.
  3. Reinventing the wheel is not a good idea. Unless you like fixing broken wheels.
Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • Yes. This is correct, it had been mentioned above. Thank you for posting an answer though. So it is clear to any who are curious. –  May 28 '17 at 02:16
  • In future, if you have your answer from the comments, it could be a good idea to delete the question ..... – Stephen C May 28 '17 at 02:20