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 176 by Douglas Thrift, 2004-06-25T20:32:24-07:00 vs.
Revision 253 by Douglas Thrift, 2004-09-13T23:31:24-07:00

# Line 8 | Line 8
8  
9   string Daemon::crlf("\r\n");
10  
11 < void Daemon::serve(int port, bool fork, Daemon* self)
11 > void Daemon::serve(Daemon* self)
12   {
13 <        api::TcpSocket server;
13 >        ext::StackReference<api::TcpSocket> server;
14  
15        server.Create();
15          server.SetAddress(api::InternetAddress(api::InternetAddress::Any, port));
17
18        if (fork)
19        {
20                switch (::fork())
21                {
22                case -1:
23                        cerr << program << ": fork()\n";
24
25                        exit(1);
26                case 0:
27                        break;
28                default:
29                        return;
30                }
31        }
32
16          server.Listen(50);
17  
18          while (true)
19          {
20 <                api::TcpSocket* client(new api::TcpSocket());
38 <
39 <                server.Accept(*client);
40 <
20 >                Client* client(new Client(server));
21                  api::Thread thread(etl::BindAll(&Daemon::handle, self, client));
22          }
23   }
# Line 46 | Line 26 | Daemon::Status Daemon::request(istream&
26          ostream& log)
27   {
28          string line;
29 <        Matcher request("^([A-Z]+) .*?(\\?.+)? HTTP/(\\d+)\\.(\\d+)$");
29 >        Matcher request("^([A-Z]+) (.*?)(\\?.+)? HTTP/(\\d+)\\.(\\d+)$");
30  
31          getline(sin, line);
32  
# Line 57 | Line 37 | Daemon::Status Daemon::request(istream&
37  
38          if (line == request)
39          {
40 <                if (lexical_cast<unsigned>(request[3]) > 1) return version;
40 >                if (lexical_cast<unsigned>(request[4]) > 1) return version;
41  
42                  Matcher method("^GET|HEAD|POST$");
43  
44                  if (request[1] != method) return notImplemented;
45  
46                  env.set("REQUEST_METHOD", method);
47 +                env.set("REQUEST_URI", request[2] + request[3]);
48  
49 <                if (!request[2].empty()) env.set("QUERY_STRING", request[2].substr(1));
49 >                if (!request[3].empty()) env.set("QUERY_STRING", request[3].substr(1));
50  
51                  headers(sin, env);
52  
53 +                if (env.get("HTTP_HOST").empty()) return bad;
54                  if (method[0] == "POST") return message(sin, env, post);
55  
56                  return ok;
57          }
58  
59 <        return notFound;
59 >        return bad;
60   }
61  
62   void Daemon::response(ostream& sout, Status status)
63   {
64 <        sout << "HTTP/1.1 " << status << ' ';
64 >        sout << "HTTP/1.1 " << status << ' ' << reason(status) << crlf << "Date: "
65 >                << date() << crlf << "Server: " << server() << crlf
66 >                << "Connection: close" << crlf;
67 > }
68 >
69 > string Daemon::reason(Status status)
70 > {
71 >        ostringstream sout;
72  
73          switch (status)
74          {
# Line 114 | Line 103 | void Daemon::response(ostream& sout, Sta
103                  sout << "HTTP Version not supported";
104          }
105  
106 <        sout << crlf << "Date: " << date() << crlf << "Server: Smersh/0.9" << crlf
107 <                << "Connection: close" << crlf;
106 >        return sout.str();
107 > }
108 >
109 > string Daemon::server()
110 > {
111 >        utsname system;
112 >
113 >        uname(&system);
114 >
115 >        return string("Smersh/0.9 (") + system.sysname + ')';
116 > }
117 >
118 > string Daemon::server(const Environment& env)
119 > {
120 >        ostringstream server;
121 >        string port(env.get("SERVER_PORT"));
122 >
123 >        server << this->server() << " Server at " << env.get("SERVER_NAME") << " Po"
124 >                << "rt " << (port.empty() ? lexical_cast<string>(this->port) : port);
125 >
126 >        return server.str();
127   }
128  
129 < void Daemon::error(ostream& sout, Status status)
129 > streamsize Daemon::error(ostream& sout, Status status, const Environment& env)
130   {
131 <        sout << crlf;
131 >        string reason(this->reason(status));
132 >        ostringstream error;
133 >
134 >        error << "<html><head><title>" << status << ' ' << reason << "</title></hea"
135 >                << "d><body><h1>" << reason << "</h1><p>Mistakes were made, deal with t"
136 >                << "hem.</p><hr /><address>" << server(env) << "</address></body></html"
137 >                << ">\r\n";
138 >        sout << "Content-Length: " << error.str().length() << crlf
139 >                << "Content-Type: text/html; charset=UTF-8\r\n\r\n" << error.str();
140 >
141 >        return error.str().size();
142   }
143  
144   string Daemon::date(bool log)
# Line 138 | Line 156 | string Daemon::date(bool log)
156          return when;
157   }
158  
159 < int Daemon::handle(api::TcpSocket* client)
159 > int Daemon::handle(Client* client)
160   {
161 <        ios::InputOutputStreamBufAdapter adapter(*client);
144 <        iostream sio(&adapter);
161 >        ios::ToIoStream sio(&client->socket, &client->socket);
162          Environment env;
163          stringstream post;
164          ostringstream log;
165          Status code(request(sio, env, post, log));
166  
167 +        if (env.get("REQUEST_URI") == "/favicon.ico") code = notFound;
168 +
169          response(sio, code);
170  
171 <        if (code == ok)
171 >        bool head(env.get("REQUEST_METHOD") == "HEAD");
172 >        streamsize sent(0);
173 >
174 >        if (code == ok && env.get("REQUEST_URI") == "/robots.txt")
175 >        {
176 >                sio << "Content-Length: 28\r\nContent-Type: text/plain; charset=UTF-8\r"
177 >                        << "\n\r\n";
178 >
179 >                if (!head) { sio << "User-agent: *\r\nDisallow: /\r\n"; sent = 28; }
180 >        }
181 >        else if (code == ok && !head)
182          {
183 <                ostringstream output;
184 <                Smersh smersh(post, output, env);
185 <                string content(output.str().substr(40));
183 >                ostringstream content;
184 >                Smersh smersh(post, content, env);
185 >
186 >                sio << "Content-Length: " << content.str().length() << crlf
187 >                        << "Content-Type: text/html; charset=UTF-8\r\n\r\n";
188  
189 <                sio << "Content-Length: " << content.length() << crlf
159 <                        << "Content-Type: text/html; charset=UTF-8" << crlf << crlf;
189 >                sio.write(content.str().data(), content.str().size());
190  
191 <                sio.write(content.data(), content.size());
191 >                sent = content.str().size();
192          }
193 <        else if (env.get("REQUEST_METHOD") != "HEAD") error(sio, code);
194 <        else sio << "Content-Type: text/html; charset=UTF-8" << crlf << crlf;
193 >        else if (head) sio << "Content-Type: text/html; charset=UTF-8\r\n\r\n";
194 >        else sent = error(sio, code, env);
195 >
196 >        ofstream fout(this->log.c_str(), ios_base::app);
197  
198 <        log << code << ' ' << 0 << " \"" << env.get("HTTP_REFERER") << "\" \""
199 <                << env.get("HTTP_USER_AGENT") << '"';
198 >        fout << inet_ntoa(client->ip->sin_addr) << " - - " << date(true) << ' '
199 >                << log.str() << code << ' ' << lexical_cast<string>(sent) << " \""
200 >                << env.get("HTTP_REFERER") << "\" \"" << env.get("HTTP_USER_AGENT")
201 >                << "\"\n";
202 >        sio << flush;
203  
204 <        if (debug) cerr << date(true) << ' ' << log.str() << '\n';
204 >        client->socket.ShutdownWrite();
205  
206          delete client;
207 +
208 +        return 0;
209   }
210  
211   void Daemon::headers(istream& sin, Environment& env)
# Line 184 | Line 221 | void Daemon::headers(istream& sin, Envir
221                  istringstream input(line);
222                  string name, value;
223  
224 <                ::getline(input, name, ':');
224 >                std::getline(input, name, ':');
225                  getline(input, value);
226  
227                  for (char next(sin.peek()); next == ' ' || next == '\t'; next =
# Line 205 | Line 242 | void Daemon::headers(istream& sin, Envir
242                  {
243                          if (value == matcher) env.set("CONTENT_TYPE", matcher[1]);
244                  }
245 +                else if (name == "Host")
246 +                {
247 +                        Matcher matcher("^\\s*(.+?)(:[0-9]+)?\\s*$");
248 +
249 +                        if (value == matcher)
250 +                        {
251 +                                bool port(matcher.size() > 2);
252 +
253 +                                env.set("HTTP_HOST", matcher[1] + (port ? matcher[2] : ""));
254 +                                env.set("SERVER_NAME", matcher[1]);
255 +
256 +                                if (port) env.set("SERVER_PORT", matcher[2].substr(1));
257 +                        }
258 +                }
259                  else if (name == "Referer")
260                  {
261                          if (value == matcher) env.set("HTTP_REFERER", matcher[1]);
# Line 220 | Line 271 | void Daemon::headers(istream& sin, Envir
271   Daemon::Status Daemon::message(istream& sin, Environment& env, ostream& post)
272   {
273          string contentLength(env.get("CONTENT_LENGTH"));
274 <                        
274 >
275          if (env.get("CONTENT_TYPE") != "application/x-www-form-urlencoded") return
276                  mediaType;
277          if (contentLength.empty()) return lengthRequired;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines