1 module websocketd.request;
2 
3 import std.conv : to;
4 import std.ascii : isWhite;
5 import std.algorithm : endsWith;
6 
7 struct Request {
8    string method;
9    string path;
10    string httpVersion;
11    string[string] headers;
12    string message;
13    bool done = false;
14 
15    static Request parse(ubyte[] bytes) {
16       static ubyte[] data = [];
17       static Request req = Request();
18 
19       data ~= bytes;
20       string message = (cast(char[])data).to!string;
21       if (!message.endsWith("\r\n\r\n"))
22          return req;
23 
24       size_t i = 0;
25       string token = "";
26 
27       // get method
28       for (; i < message.length; i++) {
29          if (message[i] == ' ')
30             break;
31          token ~= message[i];
32       }
33       i++; // skip whitespace
34       req.method = token;
35       token = "";
36 
37       // get path
38       for (; i < message.length; i++) {
39          if (message[i] == ' ')
40             break;
41          token ~= message[i];
42       }
43       i++;
44       req.path = token;
45       token = "";
46 
47       // get version
48       for (; i < message.length; i++) {
49          if (message[i] == '\r')
50             break;
51          token ~= message[i];
52       }
53       i++; // skip \r
54       if (message[i] != '\n')
55          return req;
56       i++;
57       req.httpVersion = token;
58       token = "";
59 
60       // get headers
61       string key = "";
62       for (; i < message.length; i++) {
63          token = "";
64          key = "";
65          if (message[i] == '\r')
66             break;
67          for (; i < message.length; i++) {
68             if (message[i] == ':' || message[i].isWhite)
69                break;
70             token ~= message[i];
71          }
72          i++;
73          key = token;
74          token = "";
75          for (; i < message.length; i++)
76             if (!message[i].isWhite)
77                break; // ignore whitespace
78          for (; i < message.length; i++) {
79             if (message[i] == '\r')
80                break;
81             token ~= message[i];
82          }
83          i++;
84          if (message[i] != '\n')
85             return req;
86          req.headers[key] = token;
87       }
88 
89       i++;
90       if (message[i] != '\n')
91          return req;
92       i++;
93 
94       req.message = message[i .. $];
95       req.done = true;
96       Request ans = req;
97       req = Request.init;
98       data = [];
99       return ans;
100    }
101 }