/** @file resetapi.cpp web rest api */ /** * Copyright (C) 2008 10gen Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License, version 3, * as published by the Free Software Foundation. * * 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ #include "pch.h" #include "../util/miniwebserver.h" #include "../util/mongoutils/html.h" #include "../util/md5.hpp" #include "instance.h" #include "dbwebserver.h" #include "dbhelpers.h" #include "repl.h" #include "replpair.h" #include "clientcursor.h" #include "background.h" #include "restapi.h" namespace mongo { extern const char *replInfo; bool getInitialSyncCompleted(); using namespace bson; using namespace mongoutils::html; class RESTHandler : public DbWebHandler { public: RESTHandler() : DbWebHandler( "DUMMY REST" , 1000 , true ) {} virtual bool handles( const string& url ) const { return url[0] == '/' && url.find_last_of( '/' ) > 0; } virtual void handle( const char *rq, string url, BSONObj params, string& responseMsg, int& responseCode, vector& headers, const SockAddr &from ) { string::size_type first = url.find( "/" , 1 ); if ( first == string::npos ) { responseCode = 400; return; } string method = MiniWebServer::parseMethod( rq ); string dbname = url.substr( 1 , first - 1 ); string coll = url.substr( first + 1 ); string action = ""; string::size_type last = coll.find_last_of( "/" ); if ( last == string::npos ) { action = coll; coll = "_defaultCollection"; } else { action = coll.substr( last + 1 ); coll = coll.substr( 0 , last ); } for ( string::size_type i=0; i cursor = db.query( ns.c_str() , query, num , skip ); uassert( 13085 , "query failed for dbwebserver" , cursor.get() ); if ( one ) { if ( cursor->more() ) { BSONObj obj = cursor->next(); out << obj.jsonString(Strict,html?1:0) << '\n'; } else { responseCode = 404; } return html != 0; } if( html ) { string title = string("query ") + ns; out << start(title) << p(title) << "
";
            }
            else {
                out << "{\n";
                out << "  \"offset\" : " << skip << ",\n";
                out << "  \"rows\": [\n";
            }

            int howMany = 0;
            while ( cursor->more() ) {
                if ( howMany++ && html == 0 )
                    out << " ,\n";
                BSONObj obj = cursor->next();
                if( html ) {
                    if( out.tellp() > 4 * 1024 * 1024 ) {
                        out << "Stopping output: more than 4MB returned and in html mode\n";
                        break;
                    }
                    out << obj.jsonString(Strict, html?1:0) << "\n\n";
                }
                else {
                    if( out.tellp() > 50 * 1024 * 1024 ) // 50MB limit - we are using ram
                        break;
                    out << "    " << obj.jsonString();
                }
            }

            if( html ) {
                out << "
\n"; if( howMany == 0 ) out << p("Collection is empty"); out << _end(); } else { out << "\n ],\n\n"; out << " \"total_rows\" : " << howMany << " ,\n"; out << " \"query\" : " << query.jsonString() << " ,\n"; out << " \"millis\" : " << t.millis() << '\n'; out << "}\n"; } return html != 0; } // TODO Generate id and revision per couch POST spec void handlePost( string ns, const char *body, BSONObj& params, int & responseCode, stringstream & out ) { try { BSONObj obj = fromjson( body ); db.insert( ns.c_str(), obj ); } catch ( ... ) { responseCode = 400; // Bad Request. Seems reasonable for now. out << "{ \"ok\" : false }"; return; } responseCode = 201; out << "{ \"ok\" : true }"; } int _getOption( BSONElement e , int def ) { if ( e.isNumber() ) return e.numberInt(); if ( e.type() == String ) return atoi( e.valuestr() ); return def; } DBDirectClient db; } restHandler; bool RestAdminAccess::haveAdminUsers() const { readlocktryassert rl("admin.system.users", 10000); Client::Context cx( "admin.system.users", dbpath, NULL, false ); return ! Helpers::isEmpty("admin.system.users", false); } BSONObj RestAdminAccess::getAdminUser( const string& username ) const { Client::GodScope gs; readlocktryassert rl("admin.system.users", 10000); Client::Context cx( "admin.system.users" ); BSONObj user; if ( Helpers::findOne( "admin.system.users" , BSON( "user" << username ) , user ) ) return user.copy(); return BSONObj(); } class LowLevelMongodStatus : public WebStatusPlugin { public: LowLevelMongodStatus() : WebStatusPlugin( "low level" , 5 , "requires read lock" ) {} virtual void init() {} void _gotLock( int millis , stringstream& ss ) { ss << "
\n";
            ss << "time to get readlock: " << millis << "ms\n";

            ss << "# databases: " << dbHolder.size() << '\n';

            if( ClientCursor::numCursors()>500 )
                ss << "# Cursors: " << ClientCursor::numCursors() << '\n';

            ss << "\nreplication: ";
            if( *replInfo )
                ss << "\nreplInfo:  " << replInfo << "\n\n";
            if( replSet ) {
                ss << a("", "see replSetGetStatus link top of page") << "--replSet " << cmdLine._replSet << '\n';
            }
            if ( replAllDead )
                ss << "replication replAllDead=" << replAllDead << "\n";

            else {
                ss << "\nmaster: " << replSettings.master << '\n';
                ss << "slave:  " << replSettings.slave << '\n';
                if ( replPair ) {
                    ss << "replpair:\n";
                    ss << replPair->getInfo();
                }
                bool seemCaughtUp = getInitialSyncCompleted();
                if ( !seemCaughtUp ) ss << "";
                ss <<   "initialSyncCompleted: " << seemCaughtUp;
                if ( !seemCaughtUp ) ss << "";
                ss << '\n';
            }

            BackgroundOperation::dump(ss);
            ss << "
\n"; } virtual void run( stringstream& ss ) { Timer t; readlocktry lk( "" , 300 ); if ( lk.got() ) { _gotLock( t.millis() , ss ); } else { ss << "\ntimed out getting lock\n"; } } } lowLevelMongodStatus; }