From eae566d0cc8ac5a09be6dcaf9bea913599a67581 Mon Sep 17 00:00:00 2001 From: "Adam D. Ruppe" Date: Sat, 22 Feb 2014 16:43:48 -0500 Subject: [PATCH] timezone --- cgi.d | 66 +++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 51 insertions(+), 15 deletions(-) diff --git a/cgi.d b/cgi.d index 98a91a1..34d5155 100644 --- a/cgi.d +++ b/cgi.d @@ -324,6 +324,8 @@ class Cgi { scriptName = args[0]; scriptFileName = args[0]; + environmentVariables = cast(const) environment.toAA; + foreach(arg; args[1 .. $]) { if(arg.startsWith("--")) { nextArgIs = arg[2 .. $]; @@ -499,6 +501,10 @@ class Cgi { return *e; }; + environmentVariables = env is null ? + cast(const) environment.toAA : + env; + // fetching all the request headers string[string] requestHeadersHere; foreach(k, v; env is null ? cast(const) environment.toAA() : env) { @@ -1219,6 +1225,7 @@ class Cgi { + environmentVariables = cast(const) environment.toAA; idlol = inputData; @@ -1266,9 +1273,10 @@ class Cgi { auto header = cast(string) line.idup; if(headerNumber == 1) { // request line - auto parts = header.split(" "); - requestMethod = to!RequestMethod(parts[0]); - requestUri = parts[1]; + auto parts = al.splitter(header, " "); + requestMethod = to!RequestMethod(parts.front); + parts.popFront(); + requestUri = parts.front; scriptName = requestUri[0 .. pathInfoStarts]; @@ -1359,9 +1367,6 @@ class Cgi { requestHeaders = assumeUnique(requestHeadersHere); - cookiesArray = getCookieArray(); - cookies = keepLastOf(cookiesArray); - ByChunkRange dataByChunk; // reading Content-Length type data @@ -1413,6 +1418,10 @@ class Cgi { this.keepAliveRequested = keepAliveRequested; this.acceptsGzip = acceptsGzip; this.cookie = cookie; + + cookiesArray = getCookieArray(); + cookies = keepLastOf(cookiesArray); + } BufferedInputRange idlol; @@ -1543,6 +1552,11 @@ class Cgi { } private string responseStatus = null; + /// Returns true if it is still possible to output headers + bool canOutputHeaders() { + return !isClosed && !outputtedResponseData; + } + /// Sets the location header, which the browser will redirect the user to automatically. /// Note setResponseLocation() must be called *before* you write() any data to the output. /// The optional important argument is used if it's a default suggestion rather than something to insist upon. @@ -1610,13 +1624,13 @@ class Cgi { /// Note setCookie() must be called *before* you write() any data to the output. void setCookie(string name, string data, long expiresIn = 0, string path = null, string domain = null, bool httpOnly = false, bool secure = false) { assert(!outputtedResponseData); - string cookie = name ~ "="; - cookie ~= data; + string cookie = std.uri.encodeComponent(name) ~ "="; + cookie ~= std.uri.encodeComponent(data); if(path !is null) cookie ~= "; path=" ~ path; // FIXME: should I just be using max-age here? (also in cache below) if(expiresIn != 0) - cookie ~= "; expires=" ~ printDate(cast(DateTime) Clock.currTime + dur!"msecs"(expiresIn)); + cookie ~= "; expires=" ~ printDate(cast(DateTime) Clock.currTime(UTC()) + dur!"msecs"(expiresIn)); if(domain !is null) cookie ~= "; domain=" ~ domain; if(secure == true) @@ -1624,9 +1638,15 @@ class Cgi { if(httpOnly == true ) cookie ~= "; HttpOnly"; - responseCookies ~= cookie; + if(auto idx = name in cookieIndexes) { + responseCookies[*idx] = cookie; + } else { + cookieIndexes[name] = responseCookies.length; + responseCookies ~= cookie; + } } private string[] responseCookies; + private int[string] cookieIndexes; /// Clears a previously set cookie with the given name, path, and domain. void clearCookie(string name, string path = null, string domain = null) { @@ -1674,7 +1694,7 @@ class Cgi { goto websocket; if(nph) { // we're responsible for setting the date too according to http 1.1 - hd ~= "Date: " ~ printDate(cast(DateTime) Clock.currTime); + hd ~= "Date: " ~ printDate(cast(DateTime) Clock.currTime(UTC())); } // FIXME: what if the user wants to set his own content-length? @@ -1921,6 +1941,8 @@ class Cgi { private bool outputtedResponseData; private bool noCache = true; + const(string[string]) environmentVariables; + /** What follows is data gotten from the HTTP request. It is all fully immutable, partially because it logically is (your code doesn't change what the user requested...) and partially because I hate how bad programs in PHP change those superglobals to do @@ -2468,7 +2490,7 @@ mixin template CustomCgiMain(CustomCgi, alias fun, long maxContentLength = defau throw new Exception("bind"); } - if(sock.listen(16) == -1) { + if(sock.listen(128) == -1) { close(sock); throw new Exception("listen"); } @@ -2482,6 +2504,7 @@ mixin template CustomCgiMain(CustomCgi, alias fun, long maxContentLength = defau newPid = fork(); if(newPid == 0) { // start serving on the socket + //ubyte[4096] backingBuffer; for(;;) { bool closeConnection; uint i; @@ -2491,12 +2514,17 @@ mixin template CustomCgiMain(CustomCgi, alias fun, long maxContentLength = defau if(s == -1) throw new Exception("accept"); + //ubyte[__traits(classInstanceSize, BufferedInputRange)] bufferedRangeContainer; auto ir = new BufferedInputRange(s); + //auto ir = emplace!BufferedInputRange(bufferedRangeContainer, s, backingBuffer); while(!ir.empty) { + ubyte[__traits(classInstanceSize, CustomCgi)] cgiContainer; + Cgi cgi; try { cgi = new CustomCgi(ir, &closeConnection); + //cgi = emplace!CustomCgi(cgiContainer, ir, &closeConnection); } catch(Throwable t) { // a construction error is either bad code or bad request; bad request is what it should be since this is bug free :P // anyway let's kill the connection @@ -2541,6 +2569,7 @@ mixin template CustomCgiMain(CustomCgi, alias fun, long maxContentLength = defau int status; // FIXME: maybe we should respawn if one dies unexpectedly while(-1 != wait(&status)) { + import std.stdio; writeln("Process died ", status); processCount--; goto reopen; } @@ -3011,9 +3040,16 @@ class BufferedInputRange { do { auto freeSpace = underlyingBuffer[underlyingBuffer.ptr - view.ptr + view.length .. $]; + try_again: auto ret = source.receive(freeSpace); - if(ret == Socket.ERROR) - throw new Exception("uh oh"); // FIXME + if(ret == Socket.ERROR) { + version(Posix) { + import core.stdc.errno; + if(errno == EINTR) + goto try_again; + } + throw new Exception("uh oh " ~ lastSocketError); // FIXME + } if(ret == 0) { sourceClosed = true; return; @@ -3138,7 +3174,7 @@ class ListeningConnectionManager { listener = new TcpSocket(); listener.setOption(SocketOptionLevel.SOCKET, SocketOption.REUSEADDR, true); listener.bind(new InternetAddress(port)); - listener.listen(10); + listener.listen(128); } Socket listener;