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 175 by Douglas Thrift, 2004-06-25T01:10:49-07:00 vs.
Revision 180 by Douglas Thrift, 2004-07-03T04:12:01-07:00

# Line 17 | Line 17 | void Daemon::serve(int port, bool fork,
17  
18          if (fork)
19          {
20 <                switch (::fork())
20 >                switch (pid_t pid = ::fork())
21                  {
22                  case -1:
23                          cerr << program << ": fork()\n";
# Line 26 | Line 26 | void Daemon::serve(int port, bool fork,
26                  case 0:
27                          break;
28                  default:
29 +                        cout << pid << '\n';
30                          return;
31                  }
32          }
# Line 34 | Line 35 | void Daemon::serve(int port, bool fork,
35  
36          while (true)
37          {
38 <                api::TcpSocket* client(new api::TcpSocket());
38 >                Client* client (new Client);
39  
40 <                server.Accept(*client);
40 >                server.Accept(client->socket, &client->ip);
41  
42                  api::Thread thread(etl::BindAll(&Daemon::handle, self, client));
43          }
# Line 46 | Line 47 | Daemon::Status Daemon::request(istream&
47          ostream& log)
48   {
49          string line;
50 <        Matcher request("^([A-Z]+) .*(\\?.+)? HTTP/(\\d+)\\.(\\d+)$");
50 >        Matcher request("^([A-Z]+) (.*?)(\\?.+)? HTTP/(\\d+)\\.(\\d+)$");
51  
52          getline(sin, line);
53  
54          log << '"' << line << "\" ";
55  
56 +        env.put("HTTP_REFERER=-");
57 +        env.put("HTTP_USER_AGENT=-");
58 +
59          if (line == request)
60          {
61 <                if (lexical_cast<unsigned>(request[request.size() > 4 ? 3 : 2]) > 1)
58 <                        return version;
59 <
60 <                Matcher matcher;
61 <
62 <                if (request[1] != matcher("^GET|HEAD|POST$")) return notImplemented;
63 <
64 <                env.set("REQUEST_METHOD", matcher[0]);
65 <
66 <                if (request.size() > 4) env.set("QUERY_STRING", request[2].substr(1));
61 >                if (lexical_cast<unsigned>(request[4]) > 1) return version;
62  
63 <                do
69 <                {
70 <                        getline(sin, line);
71 <
72 <                        if (line.empty()) break;
63 >                Matcher method("^GET|HEAD|POST$");
64  
65 <                        istringstream input(line);
75 <                        string name, value;
65 >                if (request[1] != method) return notImplemented;
66  
67 <                        ::getline(input, name, ':');
68 <                        getline(input, value);
67 >                env.set("REQUEST_METHOD", method);
68 >                env.set("REQUEST_URI", request[2] + request[3]);
69  
70 <                        for (char next(sin.peek()); next == ' ' || next == '\t'; next =
81 <                                sin.peek())
82 <                        {
83 <                                getline(sin, line);
84 <
85 <                                value += ' ' + line;
86 <                        }
87 <
88 <                        matcher("^\\s*?(.+)\\s*?$");
89 <
90 <                        if (name == "Content-Length")
91 <                        {
92 <                                if (value == matcher) env.set("CONTENT_LENGTH", matcher[1]);
93 <                        }
94 <                        else if (name == "Content-Type")
95 <                        {
96 <                                if (value == matcher) env.set("CONTENT_TYPE", matcher[1]);
97 <                        }
98 <                        else if (name == "Referer")
99 <                        {
100 <                                if (value == matcher) env.set("HTTP_REFERER", matcher[1]);
101 <                        }
102 <                        else if (name == "User-Agent")
103 <                        {
104 <                                if (value == matcher) env.set("HTTP_USER_AGENT", matcher[1]);
105 <                        }
106 <
107 <                        cerr << name << ':' << value << '\n';
108 <                }
109 <                while (sin.good());
110 <
111 <                if (request[0] == "POST")
112 <                {
113 <                        string contentLength(env.get("CONTENT_LENGTH"));
114 <                        
115 <                        if (env.get("CONTENT_TYPE") != "application/x-www-form-urlencoded")
116 <                                return mediaType;
117 <                        if (contentLength.empty()) return lengthRequired;
70 >                if (!request[3].empty()) env.set("QUERY_STRING", request[3].substr(1));
71  
72 <                        streamsize length(lexical_cast<streamsize>(contentLength));
120 <                        char* content(new char[length]);
72 >                headers(sin, env);
73  
74 <                        sin.read(content, length);
123 <                        post.write(content, length);
124 <
125 <                        delete [] content;
126 <                }
74 >                if (method[0] == "POST") return message(sin, env, post);
75  
76                  return ok;
77          }
78  
79 <        return notFound;
79 >        return bad;
80   }
81  
82 < void Daemon::status(ostream& sout, Status status)
82 > void Daemon::response(ostream& sout, Status status)
83   {
84 <        sout << "HTTP/1.1 " << status << ' ';
84 >        sout << "HTTP/1.1 " << status << ' ' << reason(status) << crlf << "Date: "
85 >                << date() << crlf << "Server: " << server() << crlf
86 >                << "Connection: close" << crlf;
87 > }
88 >
89 > string Daemon::reason(Status status)
90 > {
91 >        ostringstream sout;
92  
93          switch (status)
94          {
# Line 158 | Line 113 | void Daemon::status(ostream& sout, Statu
113          case mediaType:
114                  sout << "Unsupported Media Type";
115                  break;
116 <        case error:
116 >        case serverError:
117                  sout << "Internal Server Error";
118                  break;
119          case notImplemented:
# Line 168 | Line 123 | void Daemon::status(ostream& sout, Statu
123                  sout << "HTTP Version not supported";
124          }
125  
126 <        sout << crlf;
126 >        return sout.str();
127   }
128  
129 < int Daemon::handle(api::TcpSocket* client)
129 > string Daemon::server()
130   {
131 <        ios::InputOutputStreamBufAdapter adapter(*client);
131 >        utsname system;
132 >
133 >        uname(&system);
134 >
135 >        return string("Smersh/0.9 (") + system.sysname + ')';
136 > }
137 >
138 > streamsize Daemon::error(ostream& sout, Status status)
139 > {
140 >        string reason(this->reason(status));
141 >        ostringstream error;
142 >
143 >        error << "<html><head><title>" << status << ' ' << reason << "</title></hea"
144 >                << "d><body><h1>" << reason << "</h1><p>Mistakes were made, deal with t"
145 >                << "hem.</p><hr /><address>" << server() + "</address></body></html>\n";
146 >        sout << "Content-Length: " << error.str().length() << crlf
147 >                << "Content-Type: text/html; charset=UTF-8\r\n\r\n" << error.str();
148 >
149 >        return error.str().size();
150 > }
151 >
152 > string Daemon::date(bool log)
153 > {
154 >        time_t now(time(NULL));
155 >        tm time;
156 >
157 >        if (log) localtime_r(&now, &time); else gmtime_r(&now, &time);
158 >
159 >        const char* format(log ? "[%m/%d/%Y:%T %z]" : "%a, %d %b %Y %T GMT");
160 >        char when[log ? 29 : 30];
161 >
162 >        strftime(when, log ? 29 : 30, format, &time);
163 >
164 >        return when;
165 > }
166 >
167 > int Daemon::handle(Client* client)
168 > {
169 >        ios::InputOutputStreamBufAdapter adapter(client->socket);
170          iostream sio(&adapter);
171          Environment env;
172          stringstream post;
173          ostringstream log;
174          Status code(request(sio, env, post, log));
175  
176 <        status(sio, code);
176 >        if (env.get("REQUEST_URI") == "/favicon.ico") code = notFound;
177 >
178 >        response(sio, code);
179 >
180 >        bool head(env.get("REQUEST_METHOD") == "HEAD");
181 >        streamsize sent(0);
182 >
183 >        if (code == ok && !head)
184 >        {
185 >                ostringstream content;
186 >
187 >                if (env.get("REQUEST_URI") == "/robots.txt")
188 >                {
189 >                        content << string(40, '#') << "User-agent: *\r\nDisallow: /\r\n";
190 >                }
191 >                else Smersh smersh(post, content, env);
192 >
193 >                sio << "Content-Length: " << content.str().substr(40).length() << crlf
194 >                        << "Content-Type: text/html; charset=UTF-8\r\n\r\n";
195 >
196 >                sio.write(content.str().substr(40).data(), content.str().size() - 40);
197 >
198 >                sent = content.str().size() - 40;
199 >        }
200 >        else if (head) sio << "Content-Type: text/html; charset=UTF-8\r\n\r\n";
201 >        else sent = error(sio, code);
202 >
203 >        ofstream fout(this->log.c_str(), ios_base::app);
204  
205 <        log << code << ' ' << 0 << " \"" << env.get("HTTP_REFERER") << "\" \""
206 <                << env.get("HTTP_USER_AGENT") << '"';
205 >        fout << inet_ntoa(client->ip->sin_addr) << " - - " << date(true) << ' '
206 >                << log.str() << code << ' ' << lexical_cast<string>(sent) << " \""
207 >                << env.get("HTTP_REFERER") << "\" \"" << env.get("HTTP_USER_AGENT")
208 >                << "\"\n";
209 >        sio << flush;
210  
211 <        if (debug) cerr << "log = " << log.str() << '\n';
211 >        client->socket.ShutdownWrite();
212  
213          delete client;
214   }
215 +
216 + void Daemon::headers(istream& sin, Environment& env)
217 + {
218 +        do
219 +        {
220 +                string line;
221 +
222 +                getline(sin, line);
223 +
224 +                if (line.empty()) break;
225 +
226 +                istringstream input(line);
227 +                string name, value;
228 +
229 +                std::getline(input, name, ':');
230 +                getline(input, value);
231 +
232 +                for (char next(sin.peek()); next == ' ' || next == '\t'; next =
233 +                        sin.peek())
234 +                {
235 +                        getline(sin, line);
236 +
237 +                        value += ' ' + line;
238 +                }
239 +
240 +                Matcher matcher("^\\s*(.+)\\s*$");
241 +
242 +                if (name == "Content-Length")
243 +                {
244 +                        if (value == matcher) env.set("CONTENT_LENGTH", matcher[1]);
245 +                }
246 +                else if (name == "Content-Type")
247 +                {
248 +                        if (value == matcher) env.set("CONTENT_TYPE", matcher[1]);
249 +                }
250 +                else if (name == "Referer")
251 +                {
252 +                        if (value == matcher) env.set("HTTP_REFERER", matcher[1]);
253 +                }
254 +                else if (name == "User-Agent")
255 +                {
256 +                        if (value == matcher) env.set("HTTP_USER_AGENT", matcher[1]);
257 +                }
258 +        }
259 +        while (sin.good());
260 + }
261 +
262 + Daemon::Status Daemon::message(istream& sin, Environment& env, ostream& post)
263 + {
264 +        string contentLength(env.get("CONTENT_LENGTH"));
265 +
266 +        if (env.get("CONTENT_TYPE") != "application/x-www-form-urlencoded") return
267 +                mediaType;
268 +        if (contentLength.empty()) return lengthRequired;
269 +
270 +        streamsize length(lexical_cast<streamsize>(contentLength));
271 +        char* content(new char[length]);
272 +
273 +        sin.read(content, length);
274 +        post.write(content, length);
275 +
276 +        delete [] content;
277 +
278 +        return ok;
279 + }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines