/** * _getOptionArgs * * Returns the address of an OPTIONS struct with all supported options decoded. * Two types of optional parameters are supported, that is, 'queryOptions' and * 'options'. * * query-options :== 'queryOptions' '=' '{' (object (',' object)*))? '}' * options :== 'options' '=' '[' (string (',' string)*)? ']' * object :== '{' (property (',' property)*)? '}' * property :== string ':' value * array :== '[' (value (',' value)*)? ']' * value :== string | number | object | array | 'true' | 'false' * string :== '"' char* '"' * * Example: * * queryOptions={"deep":true, "ignoreCase":false} * options=["dirsOnly", "showHiddenFiles"] * * @note: Strict JSON encoding rules are enforced when decoding parameters. * * @param pGET Address of a variable data type. (php style $_GET variable) * @param piResult Address integer receiving the final result code: * HTTP_V_OK, HTTP_V_BAD_REQUEST or HTTP_V_SERVER_ERROR * * @return On success the address of an OPTIONS struct otherwise NULL **/ static OPTIONS * _getOptionArgs( DATA *pGET, int *piResult ) { OPTIONS *pOptions; DATA *ptQueryOptions, *ptOptions; if( (pOptions = (OPTIONS *)calloc(1, sizeof(OPTIONS))) ) { if( hasProperty( "options", pGET ) ) { if( (ptOptions = jsonDecode( varGetProperty("options", pGET))) ) { pOptions->bShowHiddenFiles = varInArray("showHiddenFiles", ptOptions); pOptions->bDebug = varInArray("debug", ptOptions); destroy( ptOptions ); } else // Ill formatted JSON array { cbtDebug( "options parameter is not a valid JSON object." ); *piResult = HTTP_V_BAD_REQUEST; destroy( pOptions ); return NULL; } } if( hasProperty( "queryOptions", pGET ) ) { if( (ptQueryOptions = jsonDecode( varGetProperty("queryOptions", pGET))) ) { pOptions->bIgnoreCase = (bool)varGet( varGetProperty("ignoreCase", ptQueryOptions) ); pOptions->bDeep = (bool)varGet( varGetProperty("deep", ptQueryOptions) ); destroy( ptQueryOptions ); } else // Ill formatted JSON object { cbtDebug( "queryOptions parameter is not a valid JSON object." ); *piResult = HTTP_V_BAD_REQUEST; destroy( pOptions ); return NULL; } } *piResult = HTTP_V_OK; // Success } else // Out of memory... { *piResult = HTTP_V_SERVER_ERROR; } return pOptions; }
/** * getArguments * * Returns the address of an ARGS struct with all HTTP query string parameters * extracted and decoded. The query string parameters (args) supported are: * * query-string ::= (qs-param ('&' qs-param)*)? * qs-param ::= authToken | basePath | path | query | queryOptions | options | * start | count |sort * authToken ::= 'authToken' '=' json-object * basePath ::= 'basePath' '=' path-rfc3986 * path ::= 'path' '=' path-rfc3986 * query ::= 'query' '=' object * query-options ::= 'queryOptions' '=' object * options ::= 'options' '=' array * start ::= 'start' '=' number * count ::= 'count' '=' number * sort ::= 'sort' '=' array * * @note: All of the above parameters are optional. * * @param piResult Address integer receiving the final result code: * HTTP_V_OK, HTTP_V_BAD_REQUEST or HTTP_V_SERVER_ERROR * * @return On success the address of an ARGS struct otherwise NULL **/ ARGS *getArguments( int *piResult ) { ARGS *pArgs; DATA *pCBTREE = NULL; DATA *ptARGS = NULL, *ptArg; int iResult = HTTP_V_OK; // Assume success if( (pArgs = (ARGS *)calloc(1, sizeof(ARGS))) ) { pCBTREE = cgiGetProperty("_CBTREE"); // Get CBTREE environment variables. switch( cgiGetMethodId() ) { case HTTP_V_DELETE: if( (ptARGS = cgiGetProperty( "_GET" )) ) { if( !hasProperty("path", ptARGS) ) { iResult = HTTP_V_BAD_REQUEST; } } pArgs->pOptions = _getOptionArgs( NULL, &iResult ); break; case HTTP_V_GET: if( (ptARGS = cgiGetProperty( "_GET" )) ) { // Parse the general options, if any.. if( !(pArgs->pOptions = _getOptionArgs( ptARGS, &iResult )) ) { destroyArguments( &pArgs ); return NULL; } } else // No QUERY-STRING { // We need at least an empty options struct. pArgs->pOptions = _getOptionArgs( NULL, &iResult ); } break; case HTTP_V_POST: if( (ptARGS = cgiGetProperty( "_POST" )) ) { if( hasProperty("newValue", ptARGS) && hasProperty("path", ptARGS) ) { ptArg = varGetProperty("newValue", ptARGS); if( isString(ptArg) ) { pArgs->pcNewValue = varGet( ptArg ); } else { iResult = HTTP_V_BAD_REQUEST; } } else // Missing parameter { iResult = HTTP_V_BAD_REQUEST; } } else // _POST is missing { iResult = HTTP_V_BAD_REQUEST; } pArgs->pOptions = _getOptionArgs( NULL, &iResult ); break; } if( iResult == HTTP_V_OK ) { // Get and validate the basePath if any. pArgs->pcBasePath = varGet(varGetProperty("CBTREE_BASEPATH", pCBTREE)); if( !pArgs->pcBasePath ) { if((ptArg = varGetProperty("basePath", ptARGS)) ) { if( isString(ptArg) ) { pArgs->pcBasePath = varGet( ptArg ); } else { iResult = HTTP_V_BAD_REQUEST; } } } // Validate the path if any. if( (ptArg = varGetProperty("path", ptARGS)) ) { if( isString(ptArg) ) { pArgs->pcPath = varGet( ptArg ); } else { iResult = HTTP_V_BAD_REQUEST; } } if( hasProperty( "authToken", ptARGS ) ) { if( (ptArg = jsonDecode(varGetProperty("authToken", ptARGS))) && isObject(ptArg) ) { pArgs->pAuthToken = ptArg; } else { cbtDebug( "authToken parameter is not a valid JSON object" ); iResult = HTTP_V_BAD_REQUEST; } } } if( iResult != HTTP_V_OK ) { destroyArguments( &pArgs ); *piResult = iResult; return NULL; } *piResult = HTTP_V_OK; } else // Out of memory { *piResult = HTTP_V_SERVER_ERROR; } return pArgs; }
Inst::Inst( RC::ConstHandle<IO::Dir> const &extensionDir, std::string const &extensionName, std::string const &jsonDesc, std::vector<std::string> const &pluginDirs, RC::Handle<CG::Manager> const &cgManager, EDK::Callbacks const &callbacks, std::map< std::string, void (*)( void * ) > &implNameToDestructorMap ) : m_name( extensionName ) , m_jsonDesc( jsonDesc ) { try { JSON::Decoder jsonDecode( jsonDesc.data(), jsonDesc.length() ); JSON::Entity jsonEntity; if ( !jsonDecode.getNext( jsonEntity ) ) throw Exception( "missing JSON entity" ); jsonEntity.requireObject(); m_desc = parseDesc( jsonEntity ); if ( jsonDecode.getNext( jsonEntity ) ) throw Exception( "extra JSON entity" ); } catch ( Exception e ) { throw "JSON description: " + e; } /* m_fabricLIBObject = LIB::NakedObject::Create(); m_fabricLIBObject->set( "hostTriple", LIB::ReferencedString::Create( Util::getHostTriple() ) ); m_fabricLIBObject->set( "DependencyGraph", LIBDG::Namespace::Create( dgContext ) ); */ std::vector< std::string > libs; m_desc.libs.appendMatching( Util::getHostTriple(), libs ); std::string libSuffix = "-" + std::string(buildOS) + "-" + std::string(buildArch); for ( size_t i=0; i<libs.size(); ++i ) { std::string resolvedName; SOLibHandle soLibHandle = SOLibOpen( libs[i]+libSuffix, resolvedName, false, pluginDirs ); m_resolvedNameToSOLibHandleMap.insert( ResolvedNameToSOLibHandleMap::value_type( resolvedName, soLibHandle ) ); m_orderedSOLibHandles.push_back( soLibHandle ); } if ( !m_orderedSOLibHandles.empty() ) { void *resolvedFabricEDKInitFunction = 0; for ( size_t i=0; i<m_orderedSOLibHandles.size(); ++i ) { resolvedFabricEDKInitFunction = SOLibResolve( m_orderedSOLibHandles[i], "FabricEDKInit" ); if ( resolvedFabricEDKInitFunction ) break; } if ( !resolvedFabricEDKInitFunction ) throw Exception( "error: extension doesn't implement function FabricEDKInit through macro IMPLEMENT_FABRIC_EDK_ENTRIES" ); ( *( FabricEDKInitPtr )resolvedFabricEDKInitFunction )( callbacks ); } for ( size_t i=0; i<m_orderedSOLibHandles.size(); ++i ) { /* OnLoadFn onLoadFn = (OnLoadFn)SOLibResolve( m_orderedSOLibHandles[i], "FabricOnLoad" ); if ( onLoadFn ) onLoadFn( SDK::Value::Bind( m_fabricLIBObject ) ); */ } /* for ( size_t i=0; i<m_desc.interface.methods.size(); ++i ) { std::string const &methodName = m_desc.interface.methods[i]; Method method = 0; for ( size_t j=0; j<m_orderedSOLibHandles.size(); ++j ) { SOLibHandle soLibHandle = m_orderedSOLibHandles[j]; method = (Method)SOLibResolve( soLibHandle, methodName ); if ( method ) break; } if ( !method ) throw Exception( "method "+_(methodName)+" not found" ); m_methodMap.insert( MethodMap::value_type( methodName, method ) ); } */ std::vector<std::string> codeFiles; m_desc.code.appendMatching( Util::getHostTriple(), codeFiles ); std::string filename; m_code = ""; for ( std::vector<std::string>::const_iterator it=codeFiles.begin(); it!=codeFiles.end(); ++it ) { std::string const &codeEntry = *it; if ( filename.empty() ) filename = codeEntry; std::string code; try { code = extensionDir->getFileContents( codeEntry ); } catch ( Exception e ) { throw _(codeEntry) + ": " + e; } m_code += code + "\n"; } RC::ConstHandle<KL::Source> source = KL::StringSource::Create( filename, m_code ); RC::Handle<KL::Scanner> scanner = KL::Scanner::Create( source ); m_ast = KL::Parse( scanner, m_diagnostics ); if ( !m_diagnostics.containsError() ) m_ast->registerTypes( cgManager, m_diagnostics ); for ( CG::Diagnostics::const_iterator it=m_diagnostics.begin(); it!=m_diagnostics.end(); ++it ) { CG::Location const &location = it->first; CG::Diagnostic const &diagnostic = it->second; FABRIC_LOG( "[%s] %s:%u:%u: %s: %s", extensionName.c_str(), location.getFilename()->c_str(), (unsigned)location.getLine(), (unsigned)location.getColumn(), diagnostic.getLevelDesc(), diagnostic.getDesc().c_str() ); } if ( m_diagnostics.containsError() ) throw Exception( "KL compile failed" ); std::vector< RC::ConstHandle<AST::FunctionBase> > functionBases; m_ast->collectFunctionBases( functionBases ); for ( std::vector< RC::ConstHandle<AST::FunctionBase> >::const_iterator it=functionBases.begin(); it!=functionBases.end(); ++it ) { RC::ConstHandle<AST::FunctionBase> const &functionBase = *it; if ( !functionBase->getBody() ) { std::string symbolName = functionBase->getSymbolName( cgManager ); void *resolvedFunction = 0; for ( size_t i=0; i<m_orderedSOLibHandles.size(); ++i ) { resolvedFunction = SOLibResolve( m_orderedSOLibHandles[i], symbolName ); if ( resolvedFunction ) break; } if ( !resolvedFunction ) throw Exception( "error: symbol " + _(symbolName) + ", prototyped in KL, not found in native code" ); m_externalFunctionMap.insert( ExternalFunctionMap::value_type( symbolName, resolvedFunction ) ); if ( functionBase->isDestructor() ) { RC::ConstHandle<AST::Destructor> destructor = RC::ConstHandle<AST::Destructor>::StaticCast( functionBase ); std::string thisTypeName = destructor->getThisTypeName(); implNameToDestructorMap[thisTypeName] = (void (*)( void * )) resolvedFunction; } } } m_jsConstants = m_desc.jsConstants.concatMatching( Util::getHostTriple() ); }