#undef assert
#define assert MONGO_assert
namespace mongo {
using namespace mongoutils::html;
using namespace bson;
time_t started = time(0);
struct Timing {
Timing() {
start = timeLocked = 0;
}
unsigned long long start, timeLocked;
};
bool execCommand( Command * c ,
Client& client , int queryOptions ,
const char *ns, BSONObj& cmdObj ,
BSONObjBuilder& result,
bool fromRepl );
class DbWebServer : public MiniWebServer {
public:
DbWebServer(const string& ip, int port) : MiniWebServer(ip, port) {
WebStatusPlugin::initAll();
}
private:
void doUnlockedStuff(stringstream& ss) {
/* this is in the header already ss << "port: " << port << '\n'; */
ss << "";
ss << mongodVersion() << '\n';
ss << "git hash: " << gitVersion() << '\n';
ss << "sys info: " << sysInfo() << '\n';
ss << "uptime: " << time(0)-started << " seconds\n";
ss << "
";
}
private:
bool allowed( const char * rq , vector& headers, const SockAddr &from ) {
if ( from.isLocalHost() )
return true;
if ( ! webHaveAdminUsers() )
return true;
string auth = getHeader( rq , "Authorization" );
if ( auth.size() > 0 && auth.find( "Digest " ) == 0 ){
auth = auth.substr( 7 ) + ", ";
map parms;
pcrecpp::StringPiece input( auth );
string name, val;
pcrecpp::RE re("(\\w+)=\"?(.*?)\"?, ");
while ( re.Consume( &input, &name, &val) ){
parms[name] = val;
}
BSONObj user = webGetAdminUser( parms["username"] );
if ( ! user.isEmpty() ){
string ha1 = user["pwd"].str();
string ha2 = md5simpledigest( (string)"GET" + ":" + parms["uri"] );
stringstream r;
r << ha1 << ':' << parms["nonce"];
if ( parms["nc"].size() && parms["cnonce"].size() && parms["qop"].size() ){
r << ':';
r << parms["nc"];
r << ':';
r << parms["cnonce"];
r << ':';
r << parms["qop"];
}
r << ':';
r << ha2;
string r1 = md5simpledigest( r.str() );
if ( r1 == parms["response"] )
return true;
}
}
stringstream authHeader;
authHeader
<< "WWW-Authenticate: "
<< "Digest realm=\"mongo\", "
<< "nonce=\"abc\", "
<< "algorithm=MD5, qop=\"auth\" "
;
headers.push_back( authHeader.str() );
return 0;
}
virtual void doRequest(
const char *rq, // the full request
string url,
// set these and return them:
string& responseMsg,
int& responseCode,
vector& headers, // if completely empty, content-type: text/html will be added
const SockAddr &from
)
{
if ( url.size() > 1 ) {
if ( ! allowed( rq , headers, from ) ) {
responseCode = 401;
headers.push_back( "Content-Type: text/plain" );
responseMsg = "not allowed\n";
return;
}
{
DbWebHandler * handler = DbWebHandler::findHandler( url );
if ( handler ){
if ( handler->requiresREST( url ) && ! cmdLine.rest )
_rejectREST( responseMsg , responseCode , headers );
else
handler->handle( rq , url , responseMsg , responseCode , headers , from );
return;
}
}
if ( ! cmdLine.rest ) {
_rejectREST( responseMsg , responseCode , headers );
return;
}
responseCode = 404;
headers.push_back( "Content-Type: text/html" );
responseMsg = "unknown url\n";
return;
}
// generate home page
if ( ! allowed( rq , headers, from ) ){
responseCode = 401;
responseMsg = "not allowed\n";
return;
}
responseCode = 200;
stringstream ss;
string dbname;
{
stringstream z;
z << "mongod " << prettyHostName();
dbname = z.str();
}
ss << start(dbname) << h2(dbname);
ss << "List all commands | \n";
ss << "Replica set status
\n";
//ss << "_status";
{
const map *m = Command::webCommands();
if( m ) {
ss << a("", "These read-only context-less commands can be executed from the web interface. Results are json format, unless ?text is appended in which case the result is output as text for easier human viewing", "Commands") << ": ";
for( map::const_iterator i = m->begin(); i != m->end(); i++ ) {
stringstream h;
i->second->help(h);
string help = h.str();
ss << "first << "?text\"";
if( help != "no help defined" )
ss << " title=\"" << help << '"';
ss << ">" << i->first << " ";
}
ss << '\n';
}
}
ss << '\n';
/*
ss << "HTTP admin port:" << _port << "\n";
*/
doUnlockedStuff(ss);
WebStatusPlugin::runAll( ss );
ss << "