& headers // if completely empty, content-type: text/html will be added
)
{
//out() << "url [" << url << "]" << endl;
if ( ! allowed( rq , headers ) ){
responseCode = 401;
responseMsg = "not allowed\n";
return;
}
if ( url.size() > 1 ) {
handleRESTRequest( rq , url , responseMsg , responseCode , headers );
return;
}
responseCode = 200;
stringstream ss;
ss << "";
string dbname;
{
stringstream z;
z << "mongodb " << getHostName() << ':' << mongo::port << ' ';
dbname = z.str();
}
ss << dbname << "" << dbname << "
\n
";
doUnlockedStuff(ss);
int n = 2000;
Timer t;
while ( 1 ) {
if ( !dbMutexInfo.isLocked() ) {
{
dblock lk;
ss << "time to get dblock: " << t.millis() << "ms\n";
doLockedStuff(ss);
}
break;
}
sleepmillis(1);
if ( --n < 0 ) {
ss << "\ntimed out getting dblock\n";
break;
}
}
ss << "
";
responseMsg = ss.str();
}
void handleRESTRequest( const char *rq, // the full request
string url,
string& responseMsg,
int& responseCode,
vector& headers // if completely empty, content-type: text/html will be added
) {
string::size_type first = url.find( "/" , 1 );
if ( first == string::npos ) {
responseCode = 400;
return;
}
string method = parseMethod( rq );
string dbname = url.substr( 1 , first - 1 );
string coll = url.substr( first + 1 );
string action = "";
map params;
if ( coll.find( "?" ) != string::npos ) {
parseParams( params , coll.substr( coll.find( "?" ) + 1 ) );
coll = coll.substr( 0 , coll.find( "?" ) );
}
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 & params , int & responseCode , stringstream & out ) {
Timer t;
int skip = _getOption( params["skip"] , 0 );
int num = _getOption( params["limit"] , _getOption( params["count" ] , 1000 ) ); // count is old, limit is new
int one = 0;
if ( params["one"].size() > 0 && tolower( params["one"][0] ) == 't' ) {
num = 1;
one = 1;
}
BSONObjBuilder queryBuilder;
for ( map::iterator i = params.begin(); i != params.end(); i++ ) {
if ( ! i->first.find( "filter_" ) == 0 )
continue;
const char * field = i->first.substr( 7 ).c_str();
const char * val = i->second.c_str();
char * temp;
// TODO: this is how i guess if something is a number. pretty lame right now
double number = strtod( val , &temp );
if ( temp != val )
queryBuilder.append( field , number );
else
queryBuilder.append( field , val );
}
BSONObj query = queryBuilder.obj();
auto_ptr cursor = db.query( ns.c_str() , query, num , skip );
if ( one ) {
if ( cursor->more() ) {
BSONObj obj = cursor->next();
out << obj.jsonString() << "\n";
}
else {
responseCode = 404;
}
return;
}
out << "{\n";
out << " \"offset\" : " << skip << ",\n";
out << " \"rows\": [\n";
int howMany = 0;
while ( cursor->more() ) {
if ( howMany++ )
out << " ,\n";
BSONObj obj = cursor->next();
out << " " << obj.jsonString();
}
out << "\n ]\n\n";
out << " \"total_rows\" : " << howMany << " ,\n";
out << " \"query\" : " << query.jsonString() << " ,\n";
out << " \"millis\" : " << t.millis() << " ,\n";
out << "}\n";
}
// TODO Generate id and revision per couch POST spec
void handlePost( string ns, const char *body, map & 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( string val , int def ) {
if ( val.size() == 0 )
return def;
return atoi( val.c_str() );
}
private:
static DBDirectClient db;
};
DBDirectClient DbWebServer::db;
void webServerThread() {
boost::thread thr(statsThread);
AuthenticationInfo *ai = new AuthenticationInfo();
authInfo.reset(ai);
DbWebServer mini;
int p = port + 1000;
if ( mini.init(p) ) {
registerListenerSocket( mini.socket() );
log() << "web admin interface listening on port " << p << '\n';
mini.run();
}
else {
log() << "warning: web admin interface failed to initialize on port " << p << endl;
}
}
} // namespace mongo