Where people come together to learn, code, and play. Custom-built HTTP server, site generator, and website from scratch using no external libraries. Goal is to be as minimalistic and fun as possible.
http://projectdivar.com
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
154 lines
8.7 KiB
154 lines
8.7 KiB
import java.io.BufferedReader;
|
|
import java.io.IOException;
|
|
import java.io.InputStreamReader;
|
|
import java.io.OutputStream;
|
|
import java.net.ServerSocket;
|
|
import java.net.Socket;
|
|
import java.net.SocketException;
|
|
import java.net.URLDecoder;
|
|
import java.nio.charset.StandardCharsets;
|
|
import java.nio.file.Files;
|
|
import java.nio.file.Path;
|
|
import java.nio.file.Paths;
|
|
import java.nio.file.attribute.FileTime;
|
|
import java.time.Instant;
|
|
import java.time.ZoneId;
|
|
import java.time.ZonedDateTime;
|
|
import java.time.format.DateTimeFormatter;
|
|
import java.time.temporal.ChronoUnit;
|
|
import java.util.HashMap;
|
|
import java.util.concurrent.TimeUnit;
|
|
import java.util.regex.Pattern;
|
|
|
|
public class sigServer {
|
|
ServerSocket socket;
|
|
sigServer() {
|
|
try {
|
|
socket = new ServerSocket(sigPlace.PORT);
|
|
System.out.println("Listening on port "+sigPlace.PORT+".");
|
|
while (true) {
|
|
try (Socket client = socket.accept()) {
|
|
System.out.println("New client connection detected: "+client.toString());
|
|
BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
|
|
String requestLine,line;
|
|
ZonedDateTime modifiedDate = null;
|
|
requestLine=in.readLine(); //Read the first line, this should be our request.
|
|
if (requestLine!=null) {
|
|
while (!(line=in.readLine()).isBlank()) {
|
|
//System.out.println(requestLine);
|
|
if (line.contains("If-Modified-Since: ")) {
|
|
String modifiedSince=line.replace("If-Modified-Since: ","");
|
|
modifiedDate = ZonedDateTime.parse(modifiedSince,DateTimeFormatter.RFC_1123_DATE_TIME);
|
|
//System.out.println("Found a modified date of: "+modifiedDate);
|
|
}
|
|
}
|
|
String[] splitter = requestLine.split(Pattern.quote(" "));
|
|
if (splitter.length==3) {
|
|
//This is valid.
|
|
if (splitter[0].equals("GET")) { //This is a GET request.
|
|
if (splitter[2].equals("HTTP/1.1")||splitter[2].equals("HTTP/2.0")) {
|
|
String[] requestSplit = splitter[1].split(Pattern.quote("?"));
|
|
String requestloc = requestSplit[0];
|
|
HashMap<String,String> requestParams = new HashMap<>();
|
|
if (requestSplit.length>1) {
|
|
String[] params = requestSplit[1].split(Pattern.quote("&"));
|
|
for (String s : params) {
|
|
String key = s.substring(0,s.indexOf('='));
|
|
String value = s.substring(s.indexOf('=')+1);
|
|
requestParams.put(key,value);
|
|
}
|
|
System.out.println(" ==Params for this request are: "+requestParams);
|
|
}
|
|
if (requestloc.equals("/")) {
|
|
//Send default directory.
|
|
if (modifiedDate==null||modifiedDate.isBefore(GetLastModifiedDate(sigPlace.OUTDIR,"testfile.html"))) {
|
|
System.out.println(GetLastModifiedDate(sigPlace.OUTDIR,"testfile.html")+"//"+modifiedDate);
|
|
CreateRequest(client,"200","OK","testfile.html");
|
|
} else {
|
|
//System.out.println(" testfile.html is cached! No sending required.");
|
|
CreateRequest(client,"304","Not Modified","testfile.html");
|
|
}
|
|
} else {
|
|
String location = URLDecoder.decode(requestloc.replaceFirst("/",""),StandardCharsets.UTF_8);
|
|
if (modifiedDate==null||modifiedDate.isBefore(GetLastModifiedDate(sigPlace.OUTDIR,location)))
|
|
{
|
|
CreateRequest(client,"200","OK",location);
|
|
} else {
|
|
//System.out.println(" "+location+" is cached! No sending required.");
|
|
CreateRequest(client,"304","Not Modified",location);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
CreateRequest(client,"501","Not Implemented","testfile.html");
|
|
}
|
|
}
|
|
}
|
|
} catch(SocketException|NullPointerException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
private ZonedDateTime GetLastModifiedDate(String first,String...more) throws IOException {
|
|
Instant newTime = Files.getLastModifiedTime(Paths.get(first,more)).toInstant();
|
|
newTime = newTime.truncatedTo(ChronoUnit.SECONDS);
|
|
return newTime.atZone(ZoneId.of("GMT"));
|
|
}
|
|
|
|
private void CreateRawRequest(OutputStream stream, String statusCode, String statusMsg, String contentType, byte[] content) {
|
|
CreateRawRequest(stream, statusCode, statusMsg, contentType, content,null);
|
|
}
|
|
|
|
private void CreateRawRequest(OutputStream stream, String statusCode, String statusMsg, String contentType, byte[] content, FileTime lastModified) {
|
|
try {
|
|
stream.write(("HTTP/1.1 "+statusCode+" "+statusMsg+"\r\n").getBytes());
|
|
stream.write(("ContentType: "+contentType+"\r\n").getBytes());
|
|
if (lastModified!=null) {
|
|
ZonedDateTime date = lastModified.toInstant().truncatedTo(ChronoUnit.SECONDS).atZone(ZoneId.of("GMT"));
|
|
stream.write(("Last-Modified: "+date.format(DateTimeFormatter.RFC_1123_DATE_TIME)+"\r\n").getBytes());
|
|
}
|
|
stream.write("\r\n".getBytes());
|
|
stream.write(content);
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
|
|
private void CreateRequest(Socket client, String statusCode, String statusMsg, String string) {
|
|
long startTime = System.currentTimeMillis();
|
|
Path file = Paths.get(sigPlace.OUTDIR,string);
|
|
try {
|
|
OutputStream clientOutput = client.getOutputStream();
|
|
if (statusCode.equals("200")) {
|
|
if (Files.exists(file)) {
|
|
if (Files.isDirectory(file)) {
|
|
CreateRawRequest(clientOutput,statusCode,statusMsg,"text/html",Files.readAllBytes(Paths.get(sigPlace.OUTDIR,string,sigPlace.DIRECTORYLISTING_FILENAME)),Files.getLastModifiedTime(file));
|
|
clientOutput.write(("<div class=\"generateTime\">Webpage generated in "+(System.currentTimeMillis()-startTime)+"ms</div>\r\n").getBytes());
|
|
} else {
|
|
CreateRawRequest(clientOutput,statusCode,statusMsg,Files.probeContentType(file),Files.readAllBytes(file),Files.getLastModifiedTime(file));
|
|
String contentType = Files.probeContentType(file);
|
|
if (contentType!=null&&contentType.equals("text/html")) {
|
|
clientOutput.write(("<div class=\"generateTime\">Webpage generated in "+(System.currentTimeMillis()-startTime)+"ms</div>\r\n").getBytes());
|
|
}
|
|
}
|
|
System.out.println("Sent "+file+" to client "+client+".");
|
|
} else {
|
|
CreateRawRequest(clientOutput,statusCode,statusMsg,"text/html","<!DOCTYPE html>\nWe're sorry, your webpage is in another castle!".getBytes());
|
|
System.out.println("Sent [404] "+statusMsg+" to client "+client+" for "+file+".");
|
|
}
|
|
} else {
|
|
CreateRawRequest(clientOutput,statusCode,statusMsg,"text/html","<!DOCTYPE html>\nWe're sorry, your webpage exploded!".getBytes());
|
|
System.out.println("Sent ["+statusCode+"] "+statusMsg+" to client "+client+" for "+file+".");
|
|
}
|
|
clientOutput.write("\r\n\r\n".getBytes());
|
|
clientOutput.flush();
|
|
client.close();
|
|
} catch (IOException e) {
|
|
e.printStackTrace();
|
|
}
|
|
}
|
|
}
|
|
|