diff --git a/src/osgPlugins/net/ReaderWriterNET.cpp b/src/osgPlugins/net/ReaderWriterNET.cpp index 066cefc3b..3dc98577f 100644 --- a/src/osgPlugins/net/ReaderWriterNET.cpp +++ b/src/osgPlugins/net/ReaderWriterNET.cpp @@ -1,7 +1,8 @@ -#include - #include -#include +#include + +#include + #include #include @@ -13,14 +14,27 @@ #include "sockinet.h" -extern bool goGetTheFile(const std::string &host, const std::string & file, const std::string &saveDir ); + /* + * Semantics: + * Two methods for using the .net loader. + * 1) Add a hostname prefix and a '.net' suffix on a model when passing + * to osgDB::readNodeFile() + * e.g: osgDB::readNodeFile( "openscenegraph.org:cow.osg.net" ); + * + * 2) Explicitely load the .net plugin and pass the plugin options including + * hostname= + * + * Method #1 takes precedence. SO, if the hostname option is passed the + * plugin, but the name also contains a hostname prefix, the hostname + * prefix on the file name will override the option + */ class NetReader : public osgDB::ReaderWriter { public: NetReader() {} - virtual const char* className() { return "Network Reader"; } + virtual const char* className() { return "HTTP Protocol Model Reader"; } virtual bool acceptsExtension(const std::string& extension) { @@ -30,39 +44,144 @@ class NetReader : public osgDB::ReaderWriter virtual ReadResult readObject(const std::string& fileName, const Options* opt) { return readNode(fileName,opt); } - virtual ReadResult readNode(const std::string& fileName, const Options* ) + virtual ReadResult readNode(const std::string& inFileName, const Options *options ) { - std::string ext = osgDB::getFileExtension(fileName); + std::string hostname; + std::string server_prefix; + int port = 80; + + if (options) + { + std::istringstream iss(options->getOptionString()); + std::string opt; + while (iss >> opt) + { + int index = opt.find( "=" ); + if( opt.substr( 0, index ) == "hostname" || + opt.substr( 0, index ) == "HOSTNAME" ) + { + hostname = opt.substr( index+1 ); + } + else if( opt.substr( 0, index ) == "port" || + opt.substr( 0, index ) == "PORT" ) + { + port = atoi( opt.substr(index+1).c_str() ); + } + else if( opt.substr( 0, index ) == "server_prefix" || + opt.substr( 0, index ) == "server_prefix" ) + { + server_prefix = opt.substr(index+1); + } + } + } + + /* * we accept all extensions + std::string ext = osgDB::getFileExtension(inFileName); if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; + */ - int index = fileName.find(":"); - if( index == -1 ) - return ReadResult::FILE_NOT_HANDLED; + std::string fileName; + int index = inFileName.find(":"); + // If we haven't been given a hostname as an option + // and it hasn't been prefixed to the name, we fail + if( index != -1 ) + { + hostname = inFileName.substr( 0, index); + // need to strip the inFileName of the hostname prefix + fileName = inFileName.substr( index+1 ); + } + else + { + if( hostname.empty() ) + return ReadResult::FILE_NOT_HANDLED; + else + fileName = inFileName; + } - std::string host = fileName.substr( 0, index); - int rindex = fileName.rfind( "." ); - std::string file = fileName.substr( index+1, rindex-index-1 ); + // Let's also strip the possible .net extension + if( osgDB::getFileExtension( fileName ) == "net" ) + { + int rindex = fileName.rfind( "." ); + fileName = fileName.substr( 0, rindex ); + } iosockinet sio (sockbuf::sock_stream); - sio->connect( host.c_str(), 80 ); - - sio << "GET /" << file << " HTTP/1.1\n" << "Host:\n\n"; + try { + sio->connect( hostname.c_str(), port ); + } + catch( sockerr e ) + { + osg::notify(osg::WARN) << "osgPlugin .net reader: Unable to connect to host " << hostname << std::endl; + return ReadResult::FILE_NOT_FOUND; + } + + if( !server_prefix.empty() ) + fileName = server_prefix + '/' + fileName; + + sio << "GET /" << fileName << " HTTP/1.1\n" << "Host:\n\n"; sio.flush(); char linebuff[256]; do { sio.getline( linebuff, sizeof( linebuff )); + + std::istringstream iss(linebuff); + std::string directive; + iss >> directive; + if( directive.substr(0,4) == "HTTP" ) + { + iss >> directive; + // Code 200. We be ok. + if( directive == "200" ) + ; + // Code 400 Bad Request + else if( directive == "400" ) + { + osg::notify(osg::WARN) << + "osgPluing .net: http server response 400 - Bad Request" << std::endl; + return ReadResult::FILE_NOT_FOUND; + } + // Code 401 Bad Request + else if( directive == "401" ) + { + osg::notify(osg::WARN) << + "osgPluing .net: http server response 401 - Unauthorized Access" << std::endl; + return ReadResult::FILE_NOT_FOUND; + } + // Code 403 Bad Request + else if( directive == "403" ) + { + osg::notify(osg::WARN) << + "osgPluing .net: http server response 403 - Access Forbidden" << std::endl; + return ReadResult::FILE_NOT_FOUND; + } + // Code 404 File not found + else if( directive == "404" ) + { + osg::notify(osg::WARN) << + "osgPluing .net: http server response 404 - File Not Found" << std::endl; + return ReadResult::FILE_NOT_FOUND; + } + // Code 405 Method not allowed + else if( directive == "405" ) + { + osg::notify(osg::WARN) << + "osgPluing .net: http server response 405 - Method Not Allowed" << std::endl; + return ReadResult::FILE_NOT_FOUND; + } + // There's more.... + } + } while( linebuff[0] != '\r' ); - + + // Invoke the reader corresponding to the extension osgDB::ReaderWriter *reader = - osgDB::Registry::instance()->getReaderWriterForExtension( osgDB::getFileExtension(file)); + osgDB::Registry::instance()->getReaderWriterForExtension( osgDB::getFileExtension(fileName)); ReadResult readResult = ReadResult::FILE_NOT_HANDLED; - if( reader == 0L ) - return ReadResult::FILE_NOT_HANDLED; - else + if( reader != 0L ) readResult = reader->readNode( sio ); return readResult; diff --git a/src/osgPlugins/net/sockinet.h b/src/osgPlugins/net/sockinet.h index dd97640c5..db94c46db 100644 --- a/src/osgPlugins/net/sockinet.h +++ b/src/osgPlugins/net/sockinet.h @@ -126,15 +126,15 @@ public: class iosockinet: public iosockstream { -public: - iosockinet (const sockbuf::sockdesc& sd); - iosockinet (const sockinetbuf& sb); - iosockinet (sockbuf::type ty=sockbuf::sock_stream, - int proto=0); - ~iosockinet (); + public: + iosockinet (const sockbuf::sockdesc& sd); + iosockinet (const sockinetbuf& sb); + iosockinet (sockbuf::type ty=sockbuf::sock_stream, + int proto=0); + ~iosockinet (); - sockinetbuf* rdbuf () { return (sockinetbuf*)ios::rdbuf (); } - sockinetbuf* operator -> () { return rdbuf (); } + sockinetbuf* rdbuf () { return (sockinetbuf*)ios::rdbuf (); } + sockinetbuf* operator -> () { return rdbuf (); } }; #endif // _SOCKINET_H