mirror of https://github.com/adamdruppe/arsd.git
reliability improvements for threaded http server
This commit is contained in:
parent
77867da284
commit
5d1adc8976
56
cgi.d
56
cgi.d
|
@ -1520,8 +1520,10 @@ class Cgi {
|
||||||
if(header.indexOf("HTTP/1.0") != -1) {
|
if(header.indexOf("HTTP/1.0") != -1) {
|
||||||
http10 = true;
|
http10 = true;
|
||||||
autoBuffer = true;
|
autoBuffer = true;
|
||||||
if(closeConnection)
|
if(closeConnection) {
|
||||||
|
// on http 1.0, close is assumed (unlike http/1.1 where we assume keep alive)
|
||||||
*closeConnection = true;
|
*closeConnection = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// other header
|
// other header
|
||||||
|
@ -1542,8 +1544,16 @@ class Cgi {
|
||||||
else if (name == "connection") {
|
else if (name == "connection") {
|
||||||
if(value == "close" && closeConnection)
|
if(value == "close" && closeConnection)
|
||||||
*closeConnection = true;
|
*closeConnection = true;
|
||||||
if(value.toLower().indexOf("keep-alive") != -1)
|
if(value.toLower().indexOf("keep-alive") != -1) {
|
||||||
keepAliveRequested = true;
|
keepAliveRequested = true;
|
||||||
|
|
||||||
|
// on http 1.0, the connection is closed by default,
|
||||||
|
// but not if they request keep-alive. then we don't close
|
||||||
|
// anymore - undoing the set above
|
||||||
|
if(http10 && closeConnection) {
|
||||||
|
*closeConnection = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (name == "transfer-encoding") {
|
else if (name == "transfer-encoding") {
|
||||||
if(value == "chunked")
|
if(value == "chunked")
|
||||||
|
@ -2739,6 +2749,9 @@ mixin template CustomCgiMainImpl(CustomCgi, alias fun, long maxContentLength = d
|
||||||
throw new Exception("bind");
|
throw new Exception("bind");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: if this queue is full, it will just ignore it
|
||||||
|
// and wait for the client to retransmit it. This is an
|
||||||
|
// obnoxious timeout condition there.
|
||||||
if(sock.listen(128) == -1) {
|
if(sock.listen(128) == -1) {
|
||||||
close(sock);
|
close(sock);
|
||||||
throw new Exception("listen");
|
throw new Exception("listen");
|
||||||
|
@ -2970,6 +2983,9 @@ void doThreadHttpConnection(CustomCgi, alias fun)(Socket connection) {
|
||||||
sendAll(connection, plainHttpError(false, "500 Internal Server Error", null));
|
sendAll(connection, plainHttpError(false, "500 Internal Server Error", null));
|
||||||
connection.close();
|
connection.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
connection.setOption(SocketOptionLevel.SOCKET, SocketOption.RCVTIMEO, dur!"seconds"(10));
|
||||||
|
|
||||||
bool closeConnection;
|
bool closeConnection;
|
||||||
auto ir = new BufferedInputRange(connection);
|
auto ir = new BufferedInputRange(connection);
|
||||||
|
|
||||||
|
@ -3319,6 +3335,11 @@ class BufferedInputRange {
|
||||||
try_again:
|
try_again:
|
||||||
auto ret = source.receive(freeSpace);
|
auto ret = source.receive(freeSpace);
|
||||||
if(ret == Socket.ERROR) {
|
if(ret == Socket.ERROR) {
|
||||||
|
if(wouldHaveBlocked()) {
|
||||||
|
// gonna treat a timeout here as a close
|
||||||
|
sourceClosed = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
version(Posix) {
|
version(Posix) {
|
||||||
import core.stdc.errno;
|
import core.stdc.errno;
|
||||||
if(errno == EINTR || errno == EAGAIN) {
|
if(errno == EINTR || errno == EAGAIN) {
|
||||||
|
@ -3377,33 +3398,6 @@ class BufferedInputRange {
|
||||||
bool sourceClosed;
|
bool sourceClosed;
|
||||||
}
|
}
|
||||||
|
|
||||||
class ConnectionThread2 : Thread {
|
|
||||||
import std.concurrency;
|
|
||||||
this(void function(Socket) handler) {
|
|
||||||
this.handler = handler;
|
|
||||||
super(&run);
|
|
||||||
}
|
|
||||||
|
|
||||||
void run() {
|
|
||||||
tid = thisTid();
|
|
||||||
available = true;
|
|
||||||
while(true)
|
|
||||||
receive(
|
|
||||||
(/*Socket*/ size_t s) {
|
|
||||||
available = false;
|
|
||||||
try {
|
|
||||||
handler(cast(Socket) cast(void*) s);
|
|
||||||
} catch(Throwable t) {}
|
|
||||||
available = true;
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool available;
|
|
||||||
Tid tid;
|
|
||||||
void function(Socket) handler;
|
|
||||||
}
|
|
||||||
|
|
||||||
import core.sync.semaphore;
|
import core.sync.semaphore;
|
||||||
import core.atomic;
|
import core.atomic;
|
||||||
|
|
||||||
|
@ -3457,6 +3451,10 @@ class ListeningConnectionManager {
|
||||||
|
|
||||||
while(!loopBroken && running) {
|
while(!loopBroken && running) {
|
||||||
auto sn = listener.accept();
|
auto sn = listener.accept();
|
||||||
|
// disable Nagle's algorithm to avoid a 40ms delay when we send/recv
|
||||||
|
// on the socket because we do some buffering internally. I think this helps,
|
||||||
|
// certainly does for small requests, and I think it does for larger ones too
|
||||||
|
sn.setOption(SocketOptionLevel.TCP, SocketOption.TCP_NODELAY, 1);
|
||||||
while(queueLength >= queue.length)
|
while(queueLength >= queue.length)
|
||||||
Thread.sleep(1.msecs);
|
Thread.sleep(1.msecs);
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
|
|
Loading…
Reference in New Issue