2016-03-01 19:30:42 +00:00
|
|
|
import vibe.core.core;
|
|
|
|
import vibe.core.log;
|
|
|
|
import vibe.core.net;
|
2017-09-02 15:39:20 +00:00
|
|
|
import vibe.core.stream;
|
2016-03-01 19:30:42 +00:00
|
|
|
|
2016-10-24 06:22:37 +00:00
|
|
|
import std.exception : enforce;
|
2016-03-01 19:30:42 +00:00
|
|
|
import std.functional : toDelegate;
|
2017-09-02 15:39:20 +00:00
|
|
|
import std.range.primitives : isOutputRange;
|
2016-03-01 19:30:42 +00:00
|
|
|
|
2016-10-24 06:22:37 +00:00
|
|
|
|
2016-03-01 19:30:42 +00:00
|
|
|
void main()
|
|
|
|
{
|
|
|
|
void staticAnswer(TCPConnection conn)
|
|
|
|
nothrow @safe {
|
|
|
|
try {
|
|
|
|
while (!conn.empty) {
|
|
|
|
while (true) {
|
|
|
|
CountingRange r;
|
|
|
|
conn.readLine(r);
|
|
|
|
if (!r.count) break;
|
|
|
|
}
|
2017-09-02 15:39:20 +00:00
|
|
|
conn.write(cast(const(ubyte)[])"HTTP/1.1 200 OK\r\nContent-Length: 13\r\nContent-Type: text/plain\r\nConnection: keep-alive\r\n\r\nHello, World!");
|
2016-03-01 19:30:42 +00:00
|
|
|
conn.flush();
|
|
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
|
|
scope (failure) assert(false);
|
|
|
|
logError("Error processing request: %s", e.msg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto listener = listenTCP(8080, &staticAnswer, "127.0.0.1");
|
2017-09-02 15:39:20 +00:00
|
|
|
logInfo("Listening to HTTP requests on http://127.0.0.1:8080/");
|
2016-03-01 19:30:42 +00:00
|
|
|
|
2017-09-02 15:39:20 +00:00
|
|
|
runApplication();
|
2016-03-01 19:30:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct CountingRange {
|
|
|
|
@safe nothrow @nogc:
|
|
|
|
ulong count = 0;
|
|
|
|
void put(ubyte) { count++; }
|
|
|
|
void put(in ubyte[] arr) { count += arr.length; }
|
|
|
|
}
|
|
|
|
|
2016-10-24 06:22:37 +00:00
|
|
|
void readLine(R, InputStream)(InputStream stream, ref R dst, size_t max_bytes = size_t.max)
|
2017-09-02 15:39:20 +00:00
|
|
|
if (isInputStream!InputStream && isOutputRange!(R, ubyte))
|
2016-03-01 19:30:42 +00:00
|
|
|
{
|
|
|
|
import std.algorithm.comparison : min, max;
|
|
|
|
import std.algorithm.searching : countUntil;
|
|
|
|
|
2016-10-24 06:22:37 +00:00
|
|
|
enum end_marker = "\r\n";
|
2017-09-02 15:39:20 +00:00
|
|
|
enum nmarker = end_marker.length;
|
2016-03-01 19:30:42 +00:00
|
|
|
|
|
|
|
size_t nmatched = 0;
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
enforce(!stream.empty, "Reached EOF while searching for end marker.");
|
|
|
|
enforce(max_bytes > 0, "Reached maximum number of bytes while searching for end marker.");
|
|
|
|
auto max_peek = max(max_bytes, max_bytes+nmarker); // account for integer overflow
|
|
|
|
auto pm = stream.peek()[0 .. min($, max_bytes)];
|
|
|
|
if (!pm.length) { // no peek support - inefficient route
|
|
|
|
ubyte[2] buf = void;
|
|
|
|
auto l = nmarker - nmatched;
|
|
|
|
stream.read(buf[0 .. l]);
|
|
|
|
foreach (i; 0 .. l) {
|
|
|
|
if (buf[i] == end_marker[nmatched]) {
|
|
|
|
nmatched++;
|
|
|
|
} else if (buf[i] == end_marker[0]) {
|
|
|
|
foreach (j; 0 .. nmatched) dst.put(end_marker[j]);
|
|
|
|
nmatched = 1;
|
|
|
|
} else {
|
|
|
|
foreach (j; 0 .. nmatched) dst.put(end_marker[j]);
|
|
|
|
nmatched = 0;
|
|
|
|
dst.put(buf[i]);
|
|
|
|
}
|
|
|
|
if (nmatched == nmarker) return;
|
|
|
|
}
|
|
|
|
} else {
|
2017-09-02 15:39:20 +00:00
|
|
|
assert(nmatched == 0);
|
|
|
|
|
2016-03-01 19:30:42 +00:00
|
|
|
auto idx = pm.countUntil(end_marker[0]);
|
|
|
|
if (idx < 0) {
|
|
|
|
dst.put(pm);
|
|
|
|
max_bytes -= pm.length;
|
|
|
|
stream.skip(pm.length);
|
|
|
|
} else {
|
|
|
|
dst.put(pm[0 .. idx]);
|
2017-09-02 15:39:20 +00:00
|
|
|
if (idx+1 < pm.length && pm[idx+1] == end_marker[1]) {
|
|
|
|
assert(nmarker == 2);
|
|
|
|
stream.skip(idx+2);
|
|
|
|
return;
|
|
|
|
} else {
|
|
|
|
nmatched++;
|
|
|
|
stream.skip(idx+1);
|
|
|
|
}
|
2016-03-01 19:30:42 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|