]> git.mxchange.org Git - flightgear.git/blob - src/Network/httpd.cxx
Changed GLUT support to use an embedded osgViewer too
[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 - http://www.flightgear.org/~curt
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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, 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 <algorithm>            // sort()
35 #include <stdlib.h>             // atoi() atof()
36
37 #include STL_STRING
38
39 #include <simgear/debug/logstream.hxx>
40 #include <simgear/io/iochannel.hxx>
41 #include <simgear/math/sg_types.hxx>
42 #include <simgear/structure/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
53
54 bool FGHttpd::open() {
55     if ( is_enabled() ) {
56         SG_LOG( SG_IO, SG_ALERT, "This shouldn't happen, but the channel " 
57                 << "is already in use, ignoring" );
58         return false;
59     }
60
61     server = new HttpdServer( port );
62     
63     set_hz( 15 );                // default to processing requests @ 15Hz
64     set_enabled( true );
65
66     return true;
67 }
68
69
70 bool FGHttpd::process() {
71     netChannel::poll();
72
73     return true;
74 }
75
76
77 bool FGHttpd::close() {
78     SG_LOG( SG_IO, SG_INFO, "closing FGHttpd" );   
79
80     delete server;
81     set_enabled( false );
82
83     return true;
84 }
85
86
87 class CompareNodes {
88 public:
89     bool operator() (const SGPropertyNode *a, const SGPropertyNode *b) const {
90         int r = strcmp(a->getName(), b->getName());
91         return r ? r < 0 : a->getIndex() < b->getIndex();
92     }
93 };
94
95
96 // Handle http GET requests
97 void HttpdChannel::foundTerminator (void) {
98     
99     closeWhenDone ();
100
101     const string s = buffer.getData();
102
103     if ( s.find( "GET " ) == 0 ) {
104         printf("echo: %s\n", s.c_str());
105
106         string rest = s.substr(4);
107         string request;
108         string tmp;
109
110         string::size_type pos = rest.find( " " );
111         if ( pos != string::npos ) {
112             request = rest.substr( 0, pos );
113         } else {
114             request = "/";
115         }
116
117         SGPropertyNode *node = NULL;
118         pos = request.find( "?" );
119         if ( pos != string::npos ) {
120             // request to update property value
121             string args = request.substr( pos + 1 );
122             request = request.substr( 0, pos );
123             printf("'%s' '%s'\n", request.c_str(), args.c_str());
124             request = urlDecode(request);
125
126             // parse args looking for "value="
127             bool done = false;
128             while ( ! done ) {
129                 string arg;
130                 pos = args.find("&");
131                 if ( pos != string::npos ) {
132                     arg = args.substr( 0, pos );
133                     args = args.substr( pos + 1 );
134                 } else {
135                     arg = args;
136                     done = true;
137                 }
138
139                 printf("  arg = %s\n", arg.c_str() );
140                 string::size_type apos = arg.find("=");
141                 if ( apos != string::npos ) {
142                     string a = arg.substr( 0, apos );
143                     string b = arg.substr( apos + 1 );
144                     printf("    a = %s  b = %s\n", a.c_str(), b.c_str() );
145                     if ( request == "/run.cgi" ) {
146                         // execute a command
147                         if ( a == "value" ) {
148                             SGPropertyNode args;
149                             if ( !globals->get_commands()
150                                  ->execute(urlDecode(b).c_str(), &args) )
151                             {
152                                 SG_LOG( SG_GENERAL, SG_ALERT,
153                                         "Command " << urlDecode(b)
154                                         << " failed.");
155                             }
156
157                         }
158                     } else {
159                         if ( a == "value" ) {
160                             // update a property value
161                             fgSetString( request.c_str(),
162                                          urlDecode(b).c_str() );
163                         }
164                     }
165                 }
166             }
167         } else {
168             request = urlDecode(request);
169         }
170
171         node = globals->get_props()->getNode(request.c_str());
172
173         string response = "";
174         response += "<HTML LANG=\"en\">";
175         response += getTerminator();
176
177         response += "<HEAD>";
178         response += getTerminator();
179
180         response += "<TITLE>FlightGear - ";
181         response += request;
182         response += "</TITLE>";
183         response += getTerminator();
184
185         response += "</HEAD>";
186         response += getTerminator();
187
188         response += "<BODY>";
189         response += getTerminator();
190
191         if (node == NULL) {
192             response += "<H3>Non-existent node requested!</H3>";
193             response += getTerminator();
194
195             response += "<B>";
196             response += request.c_str();
197             response += "</B> does not exist.";
198             response += getTerminator();
199         } else if ( node->nChildren() > 0 ) {
200             // request is a path with children
201             response += "<H3>Contents of \"";
202             response += request;
203             response += "\"</H3>";
204             response += getTerminator();
205
206
207             vector<SGPropertyNode *> children;
208             for (int i = 0; i < node->nChildren(); i++)
209                 children.push_back(node->getChild(i));
210             std::sort(children.begin(), children.end(), CompareNodes());
211
212             vector<SGPropertyNode *>::iterator it, end = children.end();
213             for (it = children.begin(); it != end; ++it) {
214                 SGPropertyNode *child = *it;
215                 string name = child->getDisplayName(true);
216                 string line = "";
217                 if ( child->nChildren() > 0 ) {
218                     line += "<B><A HREF=\"";
219                     line += request;
220                     if ( request.substr(request.length() - 1, 1) != "/" ) {
221                         line += "/";
222                     }
223                     line += urlEncode(name);
224                     line += "\">";
225                     line += name;
226                     line += "</A></B>";
227                     line += "/<BR>";
228                 } else {
229                     string value = node->getStringValue ( name.c_str(), "" );
230                     line += "<B>";
231                     line += name;
232                     line += "</B> <A HREF=\"";
233                     line += request;
234                     if ( request.substr(request.length() - 1, 1) != "/" ) {
235                         line += "/";
236                     }
237                     line += urlEncode(name);
238                     line += "\">(";
239                     line += value;
240                     line += ")</A><BR>";
241                 }
242                 response += line;
243                 response += getTerminator();
244             }
245         } else {
246             // request for an individual data member
247             string value = node->getStringValue();
248             
249             response += "<form method=\"GET\" action=\"";
250             response += urlEncode(request);
251             response += "\">";
252             response += "<B>";
253             response += request;
254             response += "</B> = ";
255             response += "<input type=text name=value size=\"15\" value=\"";
256             response += value;
257             response += "\" maxlength=2047>";
258             response += "<input type=submit value=\"update\" name=\"submit\">";
259             response += "</FORM>";
260         }
261         response += "</BODY>";
262         response += getTerminator();
263
264         response += "</HTML>";
265         response += getTerminator();
266
267         push( "HTTP/1.1 200 OK" );
268         push( getTerminator() );
269         
270         printf("size = %d\n", response.length());
271         char ctmp[256];
272         sprintf(ctmp, "Content-Length: %d", response.length());
273         push( ctmp );
274         push( getTerminator() );
275
276         push( "Connection: close" );
277         push( getTerminator() );
278
279         push( "Content-Type: text/html" );
280         push( getTerminator() );
281         push( getTerminator() );
282                 
283         push( response.c_str() );
284     }
285
286     buffer.remove();
287 }
288
289
290 // encode everything but "a-zA-Z0-9_.-/" (see RFC2396)
291 string HttpdChannel::urlEncode(string s) {
292     string r = "";
293     
294     for ( int i = 0; i < (int)s.length(); i++ ) {
295         if ( isalnum(s[i]) || s[i] == '_' || s[i] == '.'
296                 || s[i] == '-' || s[i] == '/' ) {
297             r += s[i];
298         } else {
299             char buf[16];
300             sprintf(buf, "%%%02X", (unsigned char)s[i]);
301             r += buf;
302         }
303     }
304     return r;
305 }
306
307
308 string HttpdChannel::urlDecode(string s) {
309     string r = "";
310     int max = s.length();
311     int a, b;
312
313     for ( int i = 0; i < max; i++ ) {
314         if ( s[i] == '+' ) {
315             r += ' ';
316         } else if ( s[i] == '%' && i + 2 < max
317                 && isxdigit(s[i + 1])
318                 && isxdigit(s[i + 2]) ) {
319             i++;
320             a = isdigit(s[i]) ? s[i] - '0' : toupper(s[i]) - 'A' + 10;
321             i++;
322             b = isdigit(s[i]) ? s[i] - '0' : toupper(s[i]) - 'A' + 10;
323             r += (char)(a * 16 + b);
324         } else {
325             r += s[i];
326         }
327     }
328     return r;
329 }