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