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 178 by Douglas Thrift, 2004-06-29T13:15:51-07:00

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines