1
0
Fork 0
flightgear/src/Network/httpd.cxx
curt 198b88ca9b This is step "1" of probably "many" in the process of separating out the
scene management code and organizing it within simgear.  My strategy is
to identify the code I want to move, and break it's direct flightgear
dependencies.  Then it will be free to move over into the simgear package.

- Moved some property specific code into simgear/props/
- Split out the condition code from fgfs/src/Main/fg_props and put it
  in it's own source file in simgear/props/
- Created a scene subdirectory for scenery, model, and material property
  related code.
- Moved location.[ch]xx into simgear/scene/model/
- The location and condition code had dependencies on flightgear's global
  state (all the globals-> stuff, the flightgear property tree, etc.)  SimGear
  code can't depend on it so that data has to be passed as parameters to the
  functions/methods/constructors.
- This need to pass data as function parameters had a dramatic cascading
  effect throughout the FlightGear code.
2003-05-06 23:54:17 +00:00

311 lines
9.2 KiB
C++

// httpd.cxx -- FGFS http property manager interface / external script
// and control class
//
// Written by Curtis Olson, started June 2001.
//
// Copyright (C) 2001 Curtis L. Olson - curt@flightgear.org
//
// Jpeg Image Support added August 2001
// by Norman Vine - nhv@cape.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
//
// $Id$
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
#include <simgear/compiler.h>
#include <stdlib.h> // atoi() atof()
#include STL_STRING
#include STL_STRSTREAM
#include <simgear/debug/logstream.hxx>
#include <simgear/io/iochannel.hxx>
#include <simgear/math/sg_types.hxx>
#include <simgear/misc/commands.hxx>
#include <simgear/props/props.hxx>
#include <Main/fg_props.hxx>
#include <Main/globals.hxx>
#include "httpd.hxx"
SG_USING_STD(string);
SG_USING_STD(cout);
SG_USING_STD(istrstream);
bool FGHttpd::open() {
if ( is_enabled() ) {
SG_LOG( SG_IO, SG_ALERT, "This shouldn't happen, but the channel "
<< "is already in use, ignoring" );
return false;
}
server = new HttpdServer( port );
set_hz( 15 ); // default to processing requests @ 15Hz
set_enabled( true );
return true;
}
bool FGHttpd::process() {
netChannel::poll();
return true;
}
bool FGHttpd::close() {
delete server;
return true;
}
// Handle http GET requests
void HttpdChannel::foundTerminator (void) {
closeWhenDone ();
const string s = buffer.getData();
if ( s.find( "GET " ) == 0 ) {
printf("echo: %s\n", s.c_str());
string rest = s.substr(4);
string request;
string tmp;
string::size_type pos = rest.find( " " );
if ( pos != string::npos ) {
request = rest.substr( 0, pos );
} else {
request = "/";
}
SGPropertyNode *node = NULL;
pos = request.find( "?" );
if ( pos != string::npos ) {
// request to update property value
string args = request.substr( pos + 1 );
request = request.substr( 0, pos );
printf("'%s' '%s'\n", request.c_str(), args.c_str());
request = urlDecode(request);
// parse args looking for "value="
bool done = false;
while ( ! done ) {
string arg;
pos = args.find("&");
if ( pos != string::npos ) {
arg = args.substr( 0, pos );
args = args.substr( pos + 1 );
} else {
arg = args;
done = true;
}
printf(" arg = %s\n", arg.c_str() );
string::size_type apos = arg.find("=");
if ( apos != string::npos ) {
string a = arg.substr( 0, apos );
string b = arg.substr( apos + 1 );
printf(" a = %s b = %s\n", a.c_str(), b.c_str() );
if ( request == "/run.cgi" ) {
// execute a command
if ( a == "value" ) {
SGPropertyNode args;
if ( !globals->get_commands()
->execute(urlDecode(b).c_str(), &args) )
{
SG_LOG( SG_GENERAL, SG_ALERT,
"Command " << urlDecode(b)
<< " failed.");
}
}
} else {
if ( a == "value" ) {
// update a property value
fgSetString( request.c_str(),
urlDecode(b).c_str() );
}
}
}
}
} else {
request = urlDecode(request);
}
node = globals->get_props()->getNode(request.c_str());
string response = "";
response += "<HTML LANG=\"en\">";
response += getTerminator();
response += "<HEAD>";
response += getTerminator();
response += "<TITLE>FlightGear - ";
response += request;
response += "</TITLE>";
response += getTerminator();
response += "</HEAD>";
response += getTerminator();
response += "<BODY>";
response += getTerminator();
if (node == NULL) {
response += "<H3>Non-existent node requested!</H3>";
response += getTerminator();
response += "<B>";
response += request.c_str();
response += "</B> does not exist.";
response += getTerminator();
} else if ( node->nChildren() > 0 ) {
// request is a path with children
response += "<H3>Contents of \"";
response += request;
response += "\"</H3>";
response += getTerminator();
for (int i = 0; i < node->nChildren(); i++) {
SGPropertyNode *child = node->getChild(i);
string name = child->getDisplayName(true);
string line = "";
if ( child->nChildren() > 0 ) {
line += "<B><A HREF=\"";
line += request;
if ( request.substr(request.length() - 1, 1) != (string)"/" ) {
line += "/";
}
line += urlEncode(name);
line += "\">";
line += name;
line += "</A></B>";
line += "/<BR>";
} else {
string value = node->getStringValue ( name.c_str(), "" );
line += "<B>";
line += name;
line += "</B> <A HREF=\"";
line += request;
if ( request.substr(request.length() - 1, 1) != (string)"/" ) {
line += "/";
}
line += urlEncode(name);
line += "\">(";
line += value;
line += ")</A><BR>";
}
response += line;
response += getTerminator();
}
} else {
// request for an individual data member
string value = node->getStringValue();
response += "<form method=\"GET\" action=\"";
response += urlEncode(request);
response += "\">";
response += "<B>";
response += request;
response += "</B> = ";
response += "<input type=text name=value size=\"15\" value=\"";
response += value;
response += "\" maxlength=2047>";
response += "<input type=submit value=\"update\" name=\"submit\">";
response += "</FORM>";
}
response += "</BODY>";
response += getTerminator();
response += "</HTML>";
response += getTerminator();
push( "HTTP/1.1 200 OK" );
push( getTerminator() );
printf("size = %d\n", response.length());
char ctmp[256];
sprintf(ctmp, "Content-Length: %d", response.length());
push( ctmp );
push( getTerminator() );
push( "Connection: close" );
push( getTerminator() );
push( "Content-Type: text/html" );
push( getTerminator() );
push( getTerminator() );
push( response.c_str() );
}
buffer.remove();
}
// encode everything but "a-zA-Z0-9_.-/" (see RFC2396)
string HttpdChannel::urlEncode(string s) {
string r = "";
for ( int i = 0; i < (int)s.length(); i++ ) {
if ( isalnum(s[i]) || s[i] == '_' || s[i] == '.'
|| s[i] == '-' || s[i] == '/' ) {
r += s[i];
} else {
char buf[16];
sprintf(buf, "%%%02X", (unsigned char)s[i]);
r += buf;
}
}
return r;
}
string HttpdChannel::urlDecode(string s) {
string r = "";
int max = s.length();
int a, b;
for ( int i = 0; i < max; i++ ) {
if ( s[i] == '+' ) {
r += ' ';
} else if ( s[i] == '%' && i + 2 < max
&& isxdigit(s[i + 1])
&& isxdigit(s[i + 2]) ) {
i++;
a = isdigit(s[i]) ? s[i] - '0' : toupper(s[i]) - 'A' + 10;
i++;
b = isdigit(s[i]) ? s[i] - '0' : toupper(s[i]) - 'A' + 10;
r += (char)(a * 16 + b);
} else {
r += s[i];
}
}
return r;
}