ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/repos/Smersh/Daemon.cpp
(Generate patch)

Comparing Smersh/Daemon.cpp (file contents):
Revision 174 by Douglas Thrift, 2004-06-21T20:16:43-07:00 vs.
Revision 176 by Douglas Thrift, 2004-06-25T20:32:24-07:00

# Line 6 | Line 6
6  
7   #include "Daemon.hpp"
8  
9 + string Daemon::crlf("\r\n");
10 +
11   void Daemon::serve(int port, bool fork, Daemon* self)
12   {
13          api::TcpSocket server;
# Line 40 | Line 42 | void Daemon::serve(int port, bool fork,
42          }
43   }
44  
45 + Daemon::Status Daemon::request(istream& sin, Environment& env, ostream& post,
46 +        ostream& log)
47 + {
48 +        string line;
49 +        Matcher request("^([A-Z]+) .*?(\\?.+)? HTTP/(\\d+)\\.(\\d+)$");
50 +
51 +        getline(sin, line);
52 +
53 +        log << '"' << line << "\" ";
54 +
55 +        env.put("HTTP_REFERER=-");
56 +        env.put("HTTP_USER_AGENT=-");
57 +
58 +        if (line == request)
59 +        {
60 +                if (lexical_cast<unsigned>(request[3]) > 1) return version;
61 +
62 +                Matcher method("^GET|HEAD|POST$");
63 +
64 +                if (request[1] != method) return notImplemented;
65 +
66 +                env.set("REQUEST_METHOD", method);
67 +
68 +                if (!request[2].empty()) env.set("QUERY_STRING", request[2].substr(1));
69 +
70 +                headers(sin, env);
71 +
72 +                if (method[0] == "POST") return message(sin, env, post);
73 +
74 +                return ok;
75 +        }
76 +
77 +        return notFound;
78 + }
79 +
80 + void Daemon::response(ostream& sout, Status status)
81 + {
82 +        sout << "HTTP/1.1 " << status << ' ';
83 +
84 +        switch (status)
85 +        {
86 +        case ok:
87 +                sout << "OK";
88 +                break;
89 +        case found:
90 +                sout << "Found";
91 +                break;
92 +        case seeOther:
93 +                sout << "See Other";
94 +                break;
95 +        case bad:
96 +                sout << "Bad Request";
97 +                break;
98 +        case notFound:
99 +                sout << "Not Found";
100 +                break;
101 +        case lengthRequired:
102 +                sout << "Length Required";
103 +                break;
104 +        case mediaType:
105 +                sout << "Unsupported Media Type";
106 +                break;
107 +        case serverError:
108 +                sout << "Internal Server Error";
109 +                break;
110 +        case notImplemented:
111 +                sout << "Not Implemented";
112 +                break;
113 +        case version:
114 +                sout << "HTTP Version not supported";
115 +        }
116 +
117 +        sout << crlf << "Date: " << date() << crlf << "Server: Smersh/0.9" << crlf
118 +                << "Connection: close" << crlf;
119 + }
120 +
121 + void Daemon::error(ostream& sout, Status status)
122 + {
123 +        sout << crlf;
124 + }
125 +
126 + string Daemon::date(bool log)
127 + {
128 +        time_t now(time(NULL));
129 +        tm time;
130 +
131 +        if (log) localtime_r(&now, &time); else gmtime_r(&now, &time);
132 +
133 +        const char* format(log ? "[%m/%d/%Y:%T %z]" : "%a, %d %b %Y %T GMT");
134 +        char when[log ? 29 : 30];
135 +
136 +        strftime(when, log ? 29 : 30, format, &time);
137 +
138 +        return when;
139 + }
140 +
141   int Daemon::handle(api::TcpSocket* client)
142   {
143          ios::InputOutputStreamBufAdapter adapter(*client);
144 <        iostream socket(&adapter);
144 >        iostream sio(&adapter);
145 >        Environment env;
146 >        stringstream post;
147 >        ostringstream log;
148 >        Status code(request(sio, env, post, log));
149 >
150 >        response(sio, code);
151  
152 <        //
152 >        if (code == ok)
153 >        {
154 >                ostringstream output;
155 >                Smersh smersh(post, output, env);
156 >                string content(output.str().substr(40));
157 >
158 >                sio << "Content-Length: " << content.length() << crlf
159 >                        << "Content-Type: text/html; charset=UTF-8" << crlf << crlf;
160 >
161 >                sio.write(content.data(), content.size());
162 >        }
163 >        else if (env.get("REQUEST_METHOD") != "HEAD") error(sio, code);
164 >        else sio << "Content-Type: text/html; charset=UTF-8" << crlf << crlf;
165 >
166 >        log << code << ' ' << 0 << " \"" << env.get("HTTP_REFERER") << "\" \""
167 >                << env.get("HTTP_USER_AGENT") << '"';
168 >
169 >        if (debug) cerr << date(true) << ' ' << log.str() << '\n';
170  
171          delete client;
172   }
173 +
174 + void Daemon::headers(istream& sin, Environment& env)
175 + {
176 +        do
177 +        {
178 +                string line;
179 +
180 +                getline(sin, line);
181 +
182 +                if (line.empty()) break;
183 +
184 +                istringstream input(line);
185 +                string name, value;
186 +
187 +                ::getline(input, name, ':');
188 +                getline(input, value);
189 +
190 +                for (char next(sin.peek()); next == ' ' || next == '\t'; next =
191 +                        sin.peek())
192 +                {
193 +                        getline(sin, line);
194 +
195 +                        value += ' ' + line;
196 +                }
197 +
198 +                Matcher matcher("^\\s*(.+)\\s*$");
199 +
200 +                if (name == "Content-Length")
201 +                {
202 +                        if (value == matcher) env.set("CONTENT_LENGTH", matcher[1]);
203 +                }
204 +                else if (name == "Content-Type")
205 +                {
206 +                        if (value == matcher) env.set("CONTENT_TYPE", matcher[1]);
207 +                }
208 +                else if (name == "Referer")
209 +                {
210 +                        if (value == matcher) env.set("HTTP_REFERER", matcher[1]);
211 +                }
212 +                else if (name == "User-Agent")
213 +                {
214 +                        if (value == matcher) env.set("HTTP_USER_AGENT", matcher[1]);
215 +                }
216 +        }
217 +        while (sin.good());
218 + }
219 +
220 + Daemon::Status Daemon::message(istream& sin, Environment& env, ostream& post)
221 + {
222 +        string contentLength(env.get("CONTENT_LENGTH"));
223 +                        
224 +        if (env.get("CONTENT_TYPE") != "application/x-www-form-urlencoded") return
225 +                mediaType;
226 +        if (contentLength.empty()) return lengthRequired;
227 +
228 +        streamsize length(lexical_cast<streamsize>(contentLength));
229 +        char* content(new char[length]);
230 +
231 +        sin.read(content, length);
232 +        post.write(content, length);
233 +
234 +        delete [] content;
235 +
236 +        return ok;
237 + }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines