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 179 by Douglas Thrift, 2004-07-02T21:16:12-07:00 vs.
Revision 184 by Douglas Thrift, 2004-07-13T21:43:09-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  
18        server.Create();
15          server.SetAddress(api::InternetAddress(api::InternetAddress::Any, port));
16  
17          if (fork)
# Line 38 | Line 34 | void Daemon::serve(int port, bool fork,
34  
35          while (true)
36          {
37 <                Client* client (new Client);
42 <
43 <                server.Accept(client->socket, &client->ip);
44 <
37 >                Client* client (new Client(server));
38                  api::Thread thread(etl::BindAll(&Daemon::handle, self, client));
39          }
40   }
# Line 50 | Line 43 | Daemon::Status Daemon::request(istream&
43          ostream& log)
44   {
45          string line;
46 <        Matcher request("^([A-Z]+) .*?(\\?.+)? HTTP/(\\d+)\\.(\\d+)$");
46 >        Matcher request("^([A-Z]+) (.*?)(\\?.+)? HTTP/(\\d+)\\.(\\d+)$");
47  
48          getline(sin, line);
49  
# Line 61 | Line 54 | Daemon::Status Daemon::request(istream&
54  
55          if (line == request)
56          {
57 <                if (lexical_cast<unsigned>(request[3]) > 1) return version;
57 >                if (lexical_cast<unsigned>(request[4]) > 1) return version;
58  
59                  Matcher method("^GET|HEAD|POST$");
60  
61                  if (request[1] != method) return notImplemented;
62  
63                  env.set("REQUEST_METHOD", method);
64 +                env.set("REQUEST_URI", request[2] + request[3]);
65  
66 <                if (!request[2].empty()) env.set("QUERY_STRING", request[2].substr(1));
66 >                if (!request[3].empty()) env.set("QUERY_STRING", request[3].substr(1));
67  
68                  headers(sin, env);
69  
70 +                if (env.get("HTTP_HOST").empty()) return bad;
71                  if (method[0] == "POST") return message(sin, env, post);
72  
73                  return ok;
74          }
75  
76 <        return notFound;
76 >        return bad;
77   }
78  
79   void Daemon::response(ostream& sout, Status status)
# Line 88 | Line 83 | void Daemon::response(ostream& sout, Sta
83                  << "Connection: close" << crlf;
84   }
85  
86 + string Daemon::reason(Status status)
87 + {
88 +        ostringstream sout;
89 +
90 +        switch (status)
91 +        {
92 +        case ok:
93 +                sout << "OK";
94 +                break;
95 +        case found:
96 +                sout << "Found";
97 +                break;
98 +        case seeOther:
99 +                sout << "See Other";
100 +                break;
101 +        case bad:
102 +                sout << "Bad Request";
103 +                break;
104 +        case notFound:
105 +                sout << "Not Found";
106 +                break;
107 +        case lengthRequired:
108 +                sout << "Length Required";
109 +                break;
110 +        case mediaType:
111 +                sout << "Unsupported Media Type";
112 +                break;
113 +        case serverError:
114 +                sout << "Internal Server Error";
115 +                break;
116 +        case notImplemented:
117 +                sout << "Not Implemented";
118 +                break;
119 +        case version:
120 +                sout << "HTTP Version not supported";
121 +        }
122 +
123 +        return sout.str();
124 + }
125 +
126   string Daemon::server()
127   {
128          utsname system;
# Line 97 | Line 132 | string Daemon::server()
132          return string("Smersh/0.9 (") + system.sysname + ')';
133   }
134  
135 < streamsize Daemon::error(ostream& sout, Status status)
135 > string Daemon::server(const Environment& env)
136 > {
137 >        ostringstream server;
138 >        string port(env.get("SERVER_PORT"));
139 >
140 >        server << this->server() << " Server at " << env.get("SERVER_NAME") << " Po"
141 >                << "rt " << (port.empty() ? lexical_cast<string>(this->port) : port);
142 >
143 >        return server.str();
144 > }
145 >
146 > streamsize Daemon::error(ostream& sout, Status status, const Environment& env)
147   {
148          string reason(this->reason(status));
149          ostringstream error;
150  
151          error << "<html><head><title>" << status << ' ' << reason << "</title></hea"
152                  << "d><body><h1>" << reason << "</h1><p>Mistakes were made, deal with t"
153 <                << "hem.</p><hr /><address>" << server() + "</address></body></html>\n";
153 >                << "hem.</p><hr /><address>" << server(env) << "</address></body></html"
154 >                << ">\r\n";
155          sout << "Content-Length: " << error.str().length() << crlf
156                  << "Content-Type: text/html; charset=UTF-8\r\n\r\n" << error.str();
157  
# Line 135 | Line 182 | int Daemon::handle(Client* client)
182          ostringstream log;
183          Status code(request(sio, env, post, log));
184  
185 +        if (env.get("REQUEST_URI") == "/favicon.ico") code = notFound;
186 +
187          response(sio, code);
188  
189          bool head(env.get("REQUEST_METHOD") == "HEAD");
190          streamsize sent(0);
191  
192 <        if (code == ok && !head)
192 >        if (code == ok && env.get("REQUEST_URI") == "/robots.txt")
193          {
194 <                ostringstream output;
195 <                Smersh smersh(post, output, env);
147 <                string content(output.str().substr(40));
194 >                sio << "Content-Length: 28\r\nContent-Type: text/plain; charset=UTF-8\r"
195 >                        << "\n\r\n";
196  
197 <                sio << "Content-Length: " << content.length() << crlf
197 >                if (!head) { sio << "User-agent: *\r\nDisallow: /\r\n"; sent = 28; }
198 >        }
199 >        else if (code == ok && !head)
200 >        {
201 >                ostringstream content;
202 >                Smersh smersh(post, content, env);
203 >
204 >                sio << "Content-Length: " << content.str().length() << crlf
205                          << "Content-Type: text/html; charset=UTF-8\r\n\r\n";
206  
207 <                sio.write(content.data(), content.size());
207 >                sio.write(content.str().data(), content.str().size());
208  
209 <                sent = content.size();
209 >                sent = content.str().size();
210          }
211          else if (head) sio << "Content-Type: text/html; charset=UTF-8\r\n\r\n";
212 <        else sent = error(sio, code);
158 <
159 <        log << code << ' ' << (sent > 0 ? lexical_cast<string>(sent) : string("0"))
160 <                << " \"" << env.get("HTTP_REFERER") << "\" \""
161 <                << env.get("HTTP_USER_AGENT") << '"';
212 >        else sent = error(sio, code, env);
213  
214          ofstream fout(this->log.c_str(), ios_base::app);
215  
216          fout << inet_ntoa(client->ip->sin_addr) << " - - " << date(true) << ' '
217 <                << log.str() << '\n';
217 >                << log.str() << code << ' ' << lexical_cast<string>(sent) << " \""
218 >                << env.get("HTTP_REFERER") << "\" \"" << env.get("HTTP_USER_AGENT")
219 >                << "\"\n";
220          sio << flush;
221  
222          client->socket.ShutdownWrite();
# Line 205 | Line 258 | void Daemon::headers(istream& sin, Envir
258                  {
259                          if (value == matcher) env.set("CONTENT_TYPE", matcher[1]);
260                  }
261 +                else if (name == "Host")
262 +                {
263 +                        Matcher matcher("^\\s*(.+?)(:[0-9]+)?\\s*$");
264 +
265 +                        if (value == matcher)
266 +                        {
267 +                                bool port(matcher.size() > 2);
268 +
269 +                                env.set("HTTP_HOST", matcher[1] + (port ? matcher[2] : ""));
270 +                                env.set("SERVER_NAME", matcher[1]);
271 +
272 +                                if (port) env.set("SERVER_PORT", matcher[2].substr(1));
273 +                        }
274 +                }
275                  else if (name == "Referer")
276                  {
277                          if (value == matcher) env.set("HTTP_REFERER", matcher[1]);
# Line 235 | Line 302 | Daemon::Status Daemon::message(istream&
302  
303          return ok;
304   }
238
239 string Daemon::reason(Status status)
240 {
241        ostringstream sout;
242
243        switch (status)
244        {
245        case ok:
246                sout << "OK";
247                break;
248        case found:
249                sout << "Found";
250                break;
251        case seeOther:
252                sout << "See Other";
253                break;
254        case bad:
255                sout << "Bad Request";
256                break;
257        case notFound:
258                sout << "Not Found";
259                break;
260        case lengthRequired:
261                sout << "Length Required";
262                break;
263        case mediaType:
264                sout << "Unsupported Media Type";
265                break;
266        case serverError:
267                sout << "Internal Server Error";
268                break;
269        case notImplemented:
270                sout << "Not Implemented";
271                break;
272        case version:
273                sout << "HTTP Version not supported";
274        }
275
276        return sout.str();
277 }

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines