ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/repos/Smersh/Daemon.cpp
Revision: 176
Committed: 2004-06-25T20:32:24-07:00 (20 years, 11 months ago) by Douglas Thrift
File size: 4611 byte(s)
Log Message:
Almost working, needs error display, and a working api::TcpSocket::Close().

File Contents

# User Rev Content
1 Douglas Thrift 164 // Smersh
2     //
3     // Douglas Thrift
4     //
5     // $Id$
6    
7     #include "Daemon.hpp"
8    
9 Douglas Thrift 175 string Daemon::crlf("\r\n");
10    
11 Douglas Thrift 173 void Daemon::serve(int port, bool fork, Daemon* self)
12 Douglas Thrift 164 {
13 Douglas Thrift 174 api::TcpSocket server;
14 Douglas Thrift 172
15 Douglas Thrift 174 server.Create();
16     server.SetAddress(api::InternetAddress(api::InternetAddress::Any, port));
17    
18 Douglas Thrift 172 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    
33 Douglas Thrift 174 server.Listen(50);
34 Douglas Thrift 173
35     while (true)
36     {
37 Douglas Thrift 174 api::TcpSocket* client(new api::TcpSocket());
38 Douglas Thrift 173
39 Douglas Thrift 174 server.Accept(*client);
40    
41     api::Thread thread(etl::BindAll(&Daemon::handle, self, client));
42 Douglas Thrift 173 }
43 Douglas Thrift 164 }
44    
45 Douglas Thrift 175 Daemon::Status Daemon::request(istream& sin, Environment& env, ostream& post,
46     ostream& log)
47     {
48     string line;
49 Douglas Thrift 176 Matcher request("^([A-Z]+) .*?(\\?.+)? HTTP/(\\d+)\\.(\\d+)$");
50 Douglas Thrift 175
51     getline(sin, line);
52    
53     log << '"' << line << "\" ";
54    
55 Douglas Thrift 176 env.put("HTTP_REFERER=-");
56     env.put("HTTP_USER_AGENT=-");
57    
58 Douglas Thrift 175 if (line == request)
59     {
60 Douglas Thrift 176 if (lexical_cast<unsigned>(request[3]) > 1) return version;
61 Douglas Thrift 175
62 Douglas Thrift 176 Matcher method("^GET|HEAD|POST$");
63 Douglas Thrift 175
64 Douglas Thrift 176 if (request[1] != method) return notImplemented;
65 Douglas Thrift 175
66 Douglas Thrift 176 env.set("REQUEST_METHOD", method);
67 Douglas Thrift 175
68 Douglas Thrift 176 if (!request[2].empty()) env.set("QUERY_STRING", request[2].substr(1));
69 Douglas Thrift 175
70 Douglas Thrift 176 headers(sin, env);
71 Douglas Thrift 175
72 Douglas Thrift 176 if (method[0] == "POST") return message(sin, env, post);
73 Douglas Thrift 175
74     return ok;
75     }
76    
77     return notFound;
78     }
79    
80 Douglas Thrift 176 void Daemon::response(ostream& sout, Status status)
81 Douglas Thrift 175 {
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 Douglas Thrift 176 case serverError:
108 Douglas Thrift 175 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 Douglas Thrift 176 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 Douglas Thrift 175 sout << crlf;
124     }
125    
126 Douglas Thrift 176 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 Douglas Thrift 174 int Daemon::handle(api::TcpSocket* client)
142 Douglas Thrift 164 {
143 Douglas Thrift 174 ios::InputOutputStreamBufAdapter adapter(*client);
144 Douglas Thrift 175 iostream sio(&adapter);
145     Environment env;
146     stringstream post;
147     ostringstream log;
148     Status code(request(sio, env, post, log));
149 Douglas Thrift 174
150 Douglas Thrift 176 response(sio, code);
151 Douglas Thrift 174
152 Douglas Thrift 176 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 Douglas Thrift 175 log << code << ' ' << 0 << " \"" << env.get("HTTP_REFERER") << "\" \""
167     << env.get("HTTP_USER_AGENT") << '"';
168    
169 Douglas Thrift 176 if (debug) cerr << date(true) << ' ' << log.str() << '\n';
170 Douglas Thrift 175
171 Douglas Thrift 174 delete client;
172 Douglas Thrift 164 }
173 Douglas Thrift 176
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     }

Properties

Name Value
svn:eol-style native
svn:keywords Id