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 178 by Douglas Thrift, 2004-06-29T13:15:51-07:00 vs.
Revision 182 by Douglas Thrift, 2004-07-03T06:52:04-07:00

# Line 4 | Line 4
4   //
5   // $Id$
6  
7 #include <arpa/inet.h>
8 #include <sys/utsname.h>
9
7   #include "Daemon.hpp"
8  
9   string Daemon::crlf("\r\n");
10  
11 < void Daemon::serve(int port, bool fork, Daemon* self)
11 > void Daemon::serve(bool fork, Daemon* self)
12   {
13          api::TcpSocket server;
14  
# Line 20 | 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 29 | 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 37 | 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 49 | 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  
# Line 60 | Line 58 | Daemon::Status Daemon::request(istream&
58  
59          if (line == request)
60          {
61 <                if (lexical_cast<unsigned>(request[3]) > 1) return version;
61 >                if (lexical_cast<unsigned>(request[4]) > 1) return version;
62  
63                  Matcher method("^GET|HEAD|POST$");
64  
65                  if (request[1] != method) return notImplemented;
66  
67                  env.set("REQUEST_METHOD", method);
68 +                env.set("REQUEST_URI", request[2] + request[3]);
69  
70 <                if (!request[2].empty()) env.set("QUERY_STRING", request[2].substr(1));
70 >                if (!request[3].empty()) env.set("QUERY_STRING", request[3].substr(1));
71  
72                  headers(sin, env);
73  
74 +                if (env.get("HTTP_HOST").empty()) return bad;
75                  if (method[0] == "POST") return message(sin, env, post);
76  
77                  return ok;
78          }
79  
80 <        return notFound;
80 >        return bad;
81   }
82  
83   void Daemon::response(ostream& sout, Status status)
# Line 87 | Line 87 | void Daemon::response(ostream& sout, Sta
87                  << "Connection: close" << crlf;
88   }
89  
90 + string Daemon::reason(Status status)
91 + {
92 +        ostringstream sout;
93 +
94 +        switch (status)
95 +        {
96 +        case ok:
97 +                sout << "OK";
98 +                break;
99 +        case found:
100 +                sout << "Found";
101 +                break;
102 +        case seeOther:
103 +                sout << "See Other";
104 +                break;
105 +        case bad:
106 +                sout << "Bad Request";
107 +                break;
108 +        case notFound:
109 +                sout << "Not Found";
110 +                break;
111 +        case lengthRequired:
112 +                sout << "Length Required";
113 +                break;
114 +        case mediaType:
115 +                sout << "Unsupported Media Type";
116 +                break;
117 +        case serverError:
118 +                sout << "Internal Server Error";
119 +                break;
120 +        case notImplemented:
121 +                sout << "Not Implemented";
122 +                break;
123 +        case version:
124 +                sout << "HTTP Version not supported";
125 +        }
126 +
127 +        return sout.str();
128 + }
129 +
130   string Daemon::server()
131   {
132          utsname system;
# Line 96 | Line 136 | string Daemon::server()
136          return string("Smersh/0.9 (") + system.sysname + ')';
137   }
138  
139 < streamsize Daemon::error(ostream& sout, Status status)
139 > string Daemon::server(const Environment& env)
140 > {
141 >        ostringstream server;
142 >        string port(env.get("SERVER_PORT"));
143 >
144 >        server << this->server() << " Server at " << env.get("SERVER_NAME") << " Po"
145 >                << "rt " << (port.empty() ? lexical_cast<string>(this->port) : port);
146 >
147 >        return server.str();
148 > }
149 >
150 > streamsize Daemon::error(ostream& sout, Status status, const Environment& env)
151   {
152          string reason(this->reason(status));
153          ostringstream error;
154  
155          error << "<html><head><title>" << status << ' ' << reason << "</title></hea"
156                  << "d><body><h1>" << reason << "</h1><p>Mistakes were made, deal with t"
157 <                << "hem.</p><hr /><address>" << server() + "</address></body></html>\n";
157 >                << "hem.</p><hr /><address>" << server(env) << "</address></body></html"
158 >                << ">\r\n";
159          sout << "Content-Length: " << error.str().length() << crlf
160                  << "Content-Type: text/html; charset=UTF-8\r\n\r\n" << error.str();
161  
# Line 125 | Line 177 | string Daemon::date(bool log)
177          return when;
178   }
179  
180 < string Daemon::ip(const api::TcpSocket& socket)
129 < {
130 <        api::InternetAddress address(socket.GetAddress());
131 <
132 <        return inet_ntoa(address->sin_addr);
133 < }
134 <
135 < int Daemon::handle(api::TcpSocket* client)
180 > int Daemon::handle(Client* client)
181   {
182 <        ios::InputOutputStreamBufAdapter adapter(*client);
182 >        ios::InputOutputStreamBufAdapter adapter(client->socket);
183          iostream sio(&adapter);
184          Environment env;
185          stringstream post;
186          ostringstream log;
187          Status code(request(sio, env, post, log));
188  
189 +        if (env.get("REQUEST_URI") == "/favicon.ico") code = notFound;
190 +
191          response(sio, code);
192  
193          bool head(env.get("REQUEST_METHOD") == "HEAD");
194          streamsize sent(0);
195  
196 <        if (code == ok && !head)
196 >        if (code == ok && env.get("REQUEST_URI") == "/robots.txt")
197 >        {
198 >                sio << "Content-Length: 28\r\nContent-Type: text/plain; charset=UTF-8\r"
199 >                        << "\n\r\n";
200 >
201 >                if (!head) { sio << "User-agent: *\r\nDisallow: /\r\n"; sent = 28; }
202 >        }
203 >        else if (code == ok && !head)
204          {
205 <                ostringstream output;
206 <                Smersh smersh(post, output, env);
153 <                string content(output.str().substr(40));
205 >                ostringstream content;
206 >                Smersh smersh(post, content, env);
207  
208 <                sio << "Content-Length: " << content.length() << crlf
208 >                sio << "Content-Length: " << content.str().length() << crlf
209                          << "Content-Type: text/html; charset=UTF-8\r\n\r\n";
210  
211 <                sio.write(content.data(), content.size());
211 >                sio.write(content.str().data(), content.str().size());
212  
213 <                sent = content.size();
213 >                sent = content.str().size();
214          }
215          else if (head) sio << "Content-Type: text/html; charset=UTF-8\r\n\r\n";
216 <        else sent = error(sio, code);
164 <
165 <        log << code << ' ' << (sent > 0 ? lexical_cast<string>(sent) : string("0"))
166 <                << " \"" << env.get("HTTP_REFERER") << "\" \""
167 <                << env.get("HTTP_USER_AGENT") << '"';
216 >        else sent = error(sio, code, env);
217  
218          ofstream fout(this->log.c_str(), ios_base::app);
219  
220 <        fout << ip(*client) << " - - " << date(true) << ' ' << log.str() << '\n';
220 >        fout << inet_ntoa(client->ip->sin_addr) << " - - " << date(true) << ' '
221 >                << log.str() << code << ' ' << lexical_cast<string>(sent) << " \""
222 >                << env.get("HTTP_REFERER") << "\" \"" << env.get("HTTP_USER_AGENT")
223 >                << "\"\n";
224          sio << flush;
225  
226 <        client->ShutdownWrite();
226 >        client->socket.ShutdownWrite();
227  
228          delete client;
229   }
# Line 210 | Line 262 | void Daemon::headers(istream& sin, Envir
262                  {
263                          if (value == matcher) env.set("CONTENT_TYPE", matcher[1]);
264                  }
265 +                else if (name == "Host")
266 +                {
267 +                        Matcher matcher("^\\s*(.+?)(:[0-9]+)?\\s*$");
268 +
269 +                        if (value == matcher)
270 +                        {
271 +                                bool port(matcher.size() > 2);
272 +
273 +                                env.set("HTTP_HOST", matcher[1] + (port ? matcher[2] : ""));
274 +                                env.set("SERVER_NAME", matcher[1]);
275 +
276 +                                if (port) env.set("SERVER_PORT", matcher[2].substr(1));
277 +                        }
278 +                }
279                  else if (name == "Referer")
280                  {
281                          if (value == matcher) env.set("HTTP_REFERER", matcher[1]);
# Line 240 | Line 306 | Daemon::Status Daemon::message(istream&
306  
307          return ok;
308   }
243
244 string Daemon::reason(Status status)
245 {
246        ostringstream sout;
247
248        switch (status)
249        {
250        case ok:
251                sout << "OK";
252                break;
253        case found:
254                sout << "Found";
255                break;
256        case seeOther:
257                sout << "See Other";
258                break;
259        case bad:
260                sout << "Bad Request";
261                break;
262        case notFound:
263                sout << "Not Found";
264                break;
265        case lengthRequired:
266                sout << "Length Required";
267                break;
268        case mediaType:
269                sout << "Unsupported Media Type";
270                break;
271        case serverError:
272                sout << "Internal Server Error";
273                break;
274        case notImplemented:
275                sout << "Not Implemented";
276                break;
277        case version:
278                sout << "HTTP Version not supported";
279        }
280
281        return sout.str();
282 }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines