Compare commits

..

10 commits

5 changed files with 77 additions and 36 deletions

View file

@ -1,14 +1,10 @@
package de.tudbut.tryumph; package de.tudbut.tryumph;
import java.util.Arrays;
import de.tudbut.async.Task;
import de.tudbut.tryumph.config.IRequestCatcher; import de.tudbut.tryumph.config.IRequestCatcher;
import de.tudbut.tryumph.config.RequestCatcherConfig; import de.tudbut.tryumph.config.RequestCatcherConfig;
import de.tudbut.tryumph.config.TryConfig; import de.tudbut.tryumph.config.TryConfig;
import de.tudbut.tryumph.err.ProjectException; import de.tudbut.tryumph.err.ProjectException;
import de.tudbut.tryumph.server.http.Server; import de.tudbut.tryumph.server.http.Server;
import de.tudbut.tryumph.util.Bug;
import tudbut.global.DebugStateManager; import tudbut.global.DebugStateManager;
public class Launch { public class Launch {
@ -32,7 +28,7 @@ public class Launch {
IRequestCatcher requestCatcher = catcher.load().ok().await(); IRequestCatcher requestCatcher = catcher.load().ok().await();
server.listen(requestCatcher); server.listen(requestCatcher);
} catch(Throwable e) { } catch(Throwable e) {
throw new Bug("HTTP server died, but all errors from HTTP should usually be catched", e); throw new Error("HTTP Server died.", e);
} }
} }

View file

@ -1,5 +1,6 @@
package de.tudbut.tryumph.example; package de.tudbut.tryumph.example;
import java.io.File;
import java.net.Socket; import java.net.Socket;
import org.w3c.dom.Document; import org.w3c.dom.Document;
@ -7,12 +8,14 @@ import org.w3c.dom.Element;
import de.tudbut.async.Callback; import de.tudbut.async.Callback;
import de.tudbut.async.ComposeCallback; import de.tudbut.async.ComposeCallback;
import de.tudbut.async.Task;
import de.tudbut.async.TaskCallable; import de.tudbut.async.TaskCallable;
import de.tudbut.tryumph.config.IRequestCatcher; import de.tudbut.tryumph.config.IRequestCatcher;
import de.tudbut.tryumph.config.TryConfig; import de.tudbut.tryumph.config.TryConfig;
import de.tudbut.tryumph.events.GET; import de.tudbut.tryumph.events.GET;
import de.tudbut.tryumph.events.Path; import de.tudbut.tryumph.events.Path;
import de.tudbut.tryumph.events.RequestHandler; import de.tudbut.tryumph.events.RequestHandler;
import de.tudbut.tryumph.server.BrowserContext;
import de.tudbut.tryumph.server.Request; import de.tudbut.tryumph.server.Request;
import de.tudbut.tryumph.server.Response; import de.tudbut.tryumph.server.Response;
import tudbut.parsing.TCN; import tudbut.parsing.TCN;
@ -58,28 +61,28 @@ public class FileServer implements IRequestCatcher, RequestHandler.Listener {
private String fileContent(Request request, String s) { private String fileContent(Request request, String s) {
String r; String r;
if(!s.endsWith(".html") && !s.endsWith(".htm")) { if(new File(s + "/index.html").exists())
r = request.context.file(s); s += "/index.html";
if(!s.endsWith(".html") && !s.endsWith(".htm") && !(new File(s).isDirectory())) {
r = request.context.fileUTF(s, data.getBoolean("autoindex") ? request.realPath : null);
r = "<pre>" + r.replace("<", "&lt;").replace(">", "&gt;") + "</pre>"; r = "<pre>" + r.replace("<", "&lt;").replace(">", "&gt;") + "</pre>";
} }
else else
r = request.context.fileUTF(s); r = request.context.fileUTF(s, data.getBoolean("autoindex") ? request.realPath : null);
return r; return r;
} }
@GET @GET
@Path(".*/") @Path("/.*")
public void onIndex(Request request, Callback<Response> res, Callback<Throwable> rej) {
res.call(new Response(request, fileContent(request, data.getString("dir") + request.realPath.replace("..", "") + "/index.html"), 200, "OK"));
}
@GET
@Path("/.+")
public void onFile(Request request, Callback<Response> res, Callback<Throwable> rej) { public void onFile(Request request, Callback<Response> res, Callback<Throwable> rej) {
if(request.realPath.equals("/style.css")) { if(request.realPath.equals("/style.css")) {
res.call(new Response(request, request.context.file("style.css"), 200, "OK", "text/css")); res.call(new Response(request, request.context.file("style.css"), 200, "OK", "text/css"));
return; return;
} }
if(request.realPath.matches("/.$|/./|/..$|/../")) {
res.call(new Response(request, "<h1>" + request.realPath + " is an illegal path</h1>", 400, "Bad request"));
return;
}
res.call(new Response(request, fileContent(request, data.getString("dir") + request.realPath.replace("..", "")), 200, "OK")); res.call(new Response(request, fileContent(request, data.getString("dir") + request.realPath.replace("..", "")), 200, "OK"));
} }
@ -88,4 +91,13 @@ public class FileServer implements IRequestCatcher, RequestHandler.Listener {
rej.call(error); rej.call(error);
} }
@Override
public Task<BrowserContext> processBrowserContext(BrowserContext context) {
if(data.getBoolean("noscript") != null)
context.addJavaScript = !data.getBoolean("noscript");
if(data.getBoolean("cookies") != null)
context.addState = data.getBoolean("cookies");
return IRequestCatcher.super.processBrowserContext(context);
}
} }

View file

@ -3,6 +3,7 @@ package de.tudbut.tryumph.server;
import static de.tudbut.async.Async.*; import static de.tudbut.async.Async.*;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@ -26,8 +27,9 @@ public class BrowserContext {
public final UUID uuid = UUID.randomUUID(); public final UUID uuid = UUID.randomUUID();
public TCN data; public TCN data;
private final IRequestCatcher requestCatcher; private final IRequestCatcher requestCatcher;
public boolean useJavaScript = false;
private boolean needsChange = false; private boolean needsChange = false;
public boolean addState = true;
public boolean addJavaScript = true;
private BrowserContext(IRequestCatcher requestCatcher) { private BrowserContext(IRequestCatcher requestCatcher) {
this.requestCatcher = requestCatcher; this.requestCatcher = requestCatcher;
@ -64,6 +66,7 @@ public class BrowserContext {
private Task<BrowserContext> init() { private Task<BrowserContext> init() {
return t((res, rej) -> { return t((res, rej) -> {
requestCatcher.processBrowserContext(this).err(rej).then(res).ok(); requestCatcher.processBrowserContext(this).err(rej).then(res).ok();
if(addState)
needsChange = true; needsChange = true;
}); });
} }
@ -77,7 +80,7 @@ public class BrowserContext {
public Task<Response> onSend(Response response) { public Task<Response> onSend(Response response) {
return AsyncJSON.write(data) return AsyncJSON.write(data)
.compose((resp, res, rej) -> { .compose((resp, res, rej) -> {
if(response.isHTML) { if(addJavaScript && response.isHTML) {
Document document = response.getHTML(); Document document = response.getHTML();
Element element = document.createElement("script"); Element element = document.createElement("script");
Node text = document.createTextNode( Node text = document.createTextNode(
@ -109,11 +112,13 @@ public class BrowserContext {
head.appendChild(element); head.appendChild(element);
response.updateHTMLData(); response.updateHTMLData();
} }
if(addState) {
if(needsChange) { if(needsChange) {
response.cookiesToSet.put("tryumph.data", resp); response.cookiesToSet.put("tryumph.data", resp);
needsChange = false; needsChange = false;
} }
response.cookiesToSet.put("tryumph.uuid", uuid.toString()); response.cookiesToSet.put("tryumph.uuid", uuid.toString());
}
res.call(response); res.call(response);
}); });
} }
@ -124,20 +129,37 @@ public class BrowserContext {
private static final HashMap<String, String> cache = new HashMap<>(); private static final HashMap<String, String> cache = new HashMap<>();
public String file(String file) { public String file(String file) {
return file(file, null);
}
public String fileUTF(String file) {
return fileUTF(file, null);
}
public String file(String file, String path) {
if(cache.containsKey(file)) if(cache.containsKey(file))
return cache.get(file); return cache.get(file);
StringBuilder builder = new StringBuilder(); StringBuilder builder = new StringBuilder();
try { try {
InputStream stream = requestCatcher.getClass().getClassLoader().getResourceAsStream(file); InputStream stream = requestCatcher.getClass().getClassLoader().getResourceAsStream(file);
if(stream == null) if(stream == null) {
if(new File(file).isDirectory() && path != null) {
while(path.endsWith("/")) path = path.substring(0, path.length() - 1);
File[] files = new File(file).listFiles();
builder.append("<ul>");
for(int i = 0; i < files.length; i++) {
builder.append("<li><a href=\"" + path + "/" + files[i].getName() + "\">" + files[i].getName() + "</a></li>");
}
builder.append("</ul>");
return builder.toString();
}
stream = new FileInputStream(file); stream = new FileInputStream(file);
}
int i = 0; int i = 0;
while((i = stream.read()) != -1) { while((i = stream.read()) != -1) {
builder.append((char) i); builder.append((char) i);
} }
stream.close(); stream.close();
if(!TryConfig.nocache) if(!TryConfig.nocache)
cache.put(file, builder.toString()); cache.put(file, builder.toString());
} catch (IOException e) { } catch (IOException e) {
@ -146,14 +168,26 @@ public class BrowserContext {
} }
return builder.toString(); return builder.toString();
} }
public String fileUTF(String file) { public String fileUTF(String file, String path) {
if(cache.containsKey(file)) if(cache.containsKey(file))
return cache.get(file); return cache.get(file);
String st = null; String st = null;
try { try {
InputStream stream = requestCatcher.getClass().getClassLoader().getResourceAsStream(file); InputStream stream = requestCatcher.getClass().getClassLoader().getResourceAsStream(file);
if(stream == null) if(stream == null) {
if(new File(file).isDirectory() && path != null) {
while(path.endsWith("/")) path = path.substring(0, path.length() - 1);
File[] files = new File(file).listFiles();
StringBuilder builder = new StringBuilder();
builder.append("<ul>");
for(int i = 0; i < files.length; i++) {
builder.append("<li><a href=\"" + path + "/" + files[i].getName() + "\">" + files[i].getName() + "</a></li>");
}
builder.append("</ul>");
return builder.toString();
}
stream = new FileInputStream(file); stream = new FileInputStream(file);
}
ByteArrayOutputStream s = new ByteArrayOutputStream(); ByteArrayOutputStream s = new ByteArrayOutputStream();
int i = 0; int i = 0;
@ -164,6 +198,7 @@ public class BrowserContext {
stream.close(); stream.close();
s.close(); s.close();
st = new String(s.toByteArray()); st = new String(s.toByteArray());
if(!TryConfig.nocache) if(!TryConfig.nocache)
cache.put(file, st); cache.put(file, st);
} catch (IOException e) { } catch (IOException e) {

View file

@ -93,18 +93,11 @@ public class Server {
break; break;
} }
} catch (Stop stop) { } catch (Stop stop) {
if(stop.getMessage() != null) {
System.out.println("Connection stopped: " + stop.getMessage());
}
else {
System.out.println("Connection stopped");
}
} }
try { try {
socket.close(); socket.close();
} catch (IOException e) { } catch (IOException e) {
} }
System.out.println("Connection with " + socket + " ended");
}).start(); }).start();
} }
serverSocket.close(); serverSocket.close();

View file

@ -39,3 +39,8 @@ input,button,select {
input.button,button,select { input.button,button,select {
border: 1px solid #cdd; border: 1px solid #cdd;
} }
a {
color: #fff;
text-decoration: underline dashed #888 1px;
}