]> git.mxchange.org Git - flightgear.git/blob - src/Network/httpd.cxx
Moved random ground cover object management code (userdata.[ch]xx) over
[flightgear.git] / src / Network / httpd.cxx
1 // httpd.cxx -- FGFS http property manager interface / external script
2 //              and control class
3 //
4 // Written by Curtis Olson, started June 2001.
5 //
6 // Copyright (C) 2001  Curtis L. Olson - curt@flightgear.org
7 //
8 // Jpeg Image Support added August 2001
9 //  by Norman Vine - nhv@cape.com
10 //
11 // This program is free software; you can redistribute it and/or
12 // modify it under the terms of the GNU General Public License as
13 // published by the Free Software Foundation; either version 2 of the
14 // License, or (at your option) any later version.
15 //
16 // This program is distributed in the hope that it will be useful, but
17 // WITHOUT ANY WARRANTY; without even the implied warranty of
18 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 // General Public License for more details.
20 //
21 // You should have received a copy of the GNU General Public License
22 // along with this program; if not, write to the Free Software
23 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 //
25 // $Id$
26
27
28 #ifdef HAVE_CONFIG_H
29 #  include <config.h>
30 #endif
31
32 #include <simgear/compiler.h>
33
34 #include <stdlib.h>             // atoi() atof()
35
36 #include STL_STRING
37 #include STL_STRSTREAM
38
39 #include <simgear/debug/logstream.hxx>
40 #include <simgear/io/iochannel.hxx>
41 #include <simgear/math/sg_types.hxx>
42 #include <simgear/misc/commands.hxx>
43 #include <simgear/props/props.hxx>
44
45 #include <Main/fg_props.hxx>
46 #include <Main/globals.hxx>
47
48 #include "httpd.hxx"
49
50 SG_USING_STD(string);
51 SG_USING_STD(cout);
52 SG_USING_STD(istrstream);
53
54
55 bool FGHttpd::open() {
56     if ( is_enabled() ) {
57         SG_LOG( SG_IO, SG_ALERT, "This shouldn't happen, but the channel " 
58                 << "is already in use, ignoring" );
59         return false;
60     }
61
62     server = new HttpdServer( port );
63     
64     set_hz( 15 );                // default to processing requests @ 15Hz
65     set_enabled( true );
66
67     return true;
68 }
69
70
71 bool FGHttpd::process() {
72     netChannel::poll();
73
74     return true;
75 }
76
77
78 bool FGHttpd::close() {
79     delete server;
80
81     return true;
82 }
83
84
85 // Handle http GET requests
86 void HttpdChannel::foundTerminator (void) {
87     
88     closeWhenDone ();
89
90     const string s = buffer.getData();
91
92     if ( s.find( "GET " ) == 0 ) {
93         printf("echo: %s\n", s.c_str());
94
95         string rest = s.substr(4);
96         string request;
97         string tmp;
98
99         string::size_type pos = rest.find( " " );
100         if ( pos != string::npos ) {
101             request = rest.substr( 0, pos );
102         } else {
103             request = "/";
104         }
105
106         SGPropertyNode *node = NULL;
107         pos = request.find( "?" );
108         if ( pos != string::npos ) {
109             // request to update property value
110             string args = request.substr( pos + 1 );
111             request = request.substr( 0, pos );
112             printf("'%s' '%s'\n", request.c_str(), args.c_str());
113             request = urlDecode(request);
114
115             // parse args looking for "value="
116             bool done = false;
117             while ( ! done ) {
118                 string arg;
119                 pos = args.find("&");
120                 if ( pos != string::npos ) {
121                     arg = args.substr( 0, pos );
122                     args = args.substr( pos + 1 );
123                 } else {
124                     arg = args;
125                     done = true;
126                 }
127
128                 printf("  arg = %s\n", arg.c_str() );
129                 string::size_type apos = arg.find("=");
130                 if ( apos != string::npos ) {
131                     string a = arg.substr( 0, apos );
132                     string b = arg.substr( apos + 1 );
133                     printf("    a = %s  b = %s\n", a.c_str(), b.c_str() );
134                     if ( request == "/run.cgi" ) {
135                         // execute a command
136                         if ( a == "value" ) {
137                             SGPropertyNode args;
138                             if ( !globals->get_commands()
139                                  ->execute(urlDecode(b).c_str(), &args) )
140                             {
141                                 SG_LOG( SG_GENERAL, SG_ALERT,
142                                         "Command " << urlDecode(b)
143                                         << " failed.");
144                             }
145
146                         }
147                     } else {
148                         if ( a == "value" ) {
149                             // update a property value
150                             fgSetString( request.c_str(),
151                                          urlDecode(b).c_str() );
152                         }
153                     }
154                 }
155             }
156         } else {
157             request = urlDecode(request);
158         }
159
160         node = globals->get_props()->getNode(request.c_str());
161
162         string response = "";
163         response += "<HTML LANG=\"en\">";
164         response += getTerminator();
165
166         response += "<HEAD>";
167         response += getTerminator();
168
169         response += "<TITLE>FlightGear - ";
170         response += request;
171         response += "</TITLE>";
172         response += getTerminator();
173
174         response += "</HEAD>";
175         response += getTerminator();
176
177         response += "<BODY>";
178         response += getTerminator();
179
180         if (node == NULL) {
181             response += "<H3>Non-existent node requested!</H3>";
182             response += getTerminator();
183
184             response += "<B>";
185             response += request.c_str();
186             response += "</B> does not exist.";
187             response += getTerminator();
188         } else if ( node->nChildren() > 0 ) {
189             // request is a path with children
190             response += "<H3>Contents of \"";
191             response += request;
192             response += "\"</H3>";
193             response += getTerminator();
194
195             for (int i = 0; i < node->nChildren(); i++) {
196                 SGPropertyNode *child = node->getChild(i);
197                 string name = child->getDisplayName(true);
198                 string line = "";
199                 if ( child->nChildren() > 0 ) {
200                     line += "<B><A HREF=\"";
201                     line += request;
202                     if ( request.substr(request.length() - 1, 1) != (string)"/" ) {
203                         line += "/";
204                     }
205                     line += urlEncode(name);
206                     line += "\">";
207                     line += name;
208                     line += "</A></B>";
209                     line += "/<BR>";
210                 } else {
211                     string value = node->getStringValue ( name.c_str(), "" );
212                     line += "<B>";
213                     line += name;
214                     line += "</B> <A HREF=\"";
215                     line += request;
216                     if ( request.substr(request.length() - 1, 1) != (string)"/" ) {
217                         line += "/";
218                     }
219                     line += urlEncode(name);
220                     line += "\">(";
221                     line += value;
222                     line += ")</A><BR>";
223                 }
224                 response += line;
225                 response += getTerminator();
226             }
227         } else {
228             // request for an individual data member
229             string value = node->getStringValue();
230             
231             response += "<form method=\"GET\" action=\"";
232             response += urlEncode(request);
233             response += "\">";
234             response += "<B>";
235             response += request;
236             response += "</B> = ";
237             response += "<input type=text name=value size=\"15\" value=\"";
238             response += value;
239             response += "\" maxlength=2047>";
240             response += "<input type=submit value=\"update\" name=\"submit\">";
241             response += "</FORM>";
242         }
243         response += "</BODY>";
244         response += getTerminator();
245
246         response += "</HTML>";
247         response += getTerminator();
248
249         push( "HTTP/1.1 200 OK" );
250         push( getTerminator() );
251         
252         printf("size = %d\n", response.length());
253         char ctmp[256];
254         sprintf(ctmp, "Content-Length: %d", response.length());
255         push( ctmp );
256         push( getTerminator() );
257
258         push( "Connection: close" );
259         push( getTerminator() );
260
261         push( "Content-Type: text/html" );
262         push( getTerminator() );
263         push( getTerminator() );
264                 
265         push( response.c_str() );
266     }
267
268     buffer.remove();
269 }
270
271
272 // encode everything but "a-zA-Z0-9_.-/" (see RFC2396)
273 string HttpdChannel::urlEncode(string s) {
274     string r = "";
275     
276     for ( int i = 0; i < (int)s.length(); i++ ) {
277         if ( isalnum(s[i]) || s[i] == '_' || s[i] == '.'
278                 || s[i] == '-' || s[i] == '/' ) {
279             r += s[i];
280         } else {
281             char buf[16];
282             sprintf(buf, "%%%02X", (unsigned char)s[i]);
283             r += buf;
284         }
285     }
286     return r;
287 }
288
289
290 string HttpdChannel::urlDecode(string s) {
291     string r = "";
292     int max = s.length();
293     int a, b;
294
295     for ( int i = 0; i < max; i++ ) {
296         if ( s[i] == '+' ) {
297             r += ' ';
298         } else if ( s[i] == '%' && i + 2 < max
299                 && isxdigit(s[i + 1])
300                 && isxdigit(s[i + 2]) ) {
301             i++;
302             a = isdigit(s[i]) ? s[i] - '0' : toupper(s[i]) - 'A' + 10;
303             i++;
304             b = isdigit(s[i]) ? s[i] - '0' : toupper(s[i]) - 'A' + 10;
305             r += (char)(a * 16 + b);
306         } else {
307             r += s[i];
308         }
309     }
310     return r;
311 }