diff options
Diffstat (limited to 'src/mongo/util/net/miniwebserver.cpp')
-rw-r--r-- | src/mongo/util/net/miniwebserver.cpp | 212 |
1 files changed, 212 insertions, 0 deletions
diff --git a/src/mongo/util/net/miniwebserver.cpp b/src/mongo/util/net/miniwebserver.cpp new file mode 100644 index 00000000000..f0b58569d22 --- /dev/null +++ b/src/mongo/util/net/miniwebserver.cpp @@ -0,0 +1,212 @@ +// miniwebserver.cpp + +/* Copyright 2009 10gen Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "pch.h" +#include "miniwebserver.h" +#include "../hex.h" + +#include "pcrecpp.h" + +namespace mongo { + + MiniWebServer::MiniWebServer(const string& name, const string &ip, int port) + : Listener(name, ip, port, false) + {} + + string MiniWebServer::parseURL( const char * buf ) { + const char * urlStart = strchr( buf , ' ' ); + if ( ! urlStart ) + return "/"; + + urlStart++; + + const char * end = strchr( urlStart , ' ' ); + if ( ! end ) { + end = strchr( urlStart , '\r' ); + if ( ! end ) { + end = strchr( urlStart , '\n' ); + } + } + + if ( ! end ) + return "/"; + + int diff = (int)(end-urlStart); + if ( diff < 0 || diff > 255 ) + return "/"; + + return string( urlStart , (int)(end-urlStart) ); + } + + void MiniWebServer::parseParams( BSONObj & params , string query ) { + if ( query.size() == 0 ) + return; + + BSONObjBuilder b; + while ( query.size() ) { + + string::size_type amp = query.find( "&" ); + + string cur; + if ( amp == string::npos ) { + cur = query; + query = ""; + } + else { + cur = query.substr( 0 , amp ); + query = query.substr( amp + 1 ); + } + + string::size_type eq = cur.find( "=" ); + if ( eq == string::npos ) + continue; + + b.append( urlDecode(cur.substr(0,eq)) , urlDecode(cur.substr(eq+1) ) ); + } + + params = b.obj(); + } + + string MiniWebServer::parseMethod( const char * headers ) { + const char * end = strchr( headers , ' ' ); + if ( ! end ) + return "GET"; + return string( headers , (int)(end-headers) ); + } + + const char *MiniWebServer::body( const char *buf ) { + const char *ret = strstr( buf, "\r\n\r\n" ); + return ret ? ret + 4 : ret; + } + + bool MiniWebServer::fullReceive( const char *buf ) { + const char *bod = body( buf ); + if ( !bod ) + return false; + const char *lenString = "Content-Length:"; + const char *lengthLoc = strstr( buf, lenString ); + if ( !lengthLoc ) + return true; + lengthLoc += strlen( lenString ); + long len = strtol( lengthLoc, 0, 10 ); + if ( long( strlen( bod ) ) == len ) + return true; + return false; + } + + void MiniWebServer::accepted(Socket sock) { + sock.postFork(); + sock.setTimeout(8); + char buf[4096]; + int len = 0; + while ( 1 ) { + int left = sizeof(buf) - 1 - len; + if( left == 0 ) + break; + int x = sock.unsafe_recv( buf + len , left ); + if ( x <= 0 ) { + sock.close(); + return; + } + len += x; + buf[ len ] = 0; + if ( fullReceive( buf ) ) { + break; + } + } + buf[len] = 0; + + string responseMsg; + int responseCode = 599; + vector<string> headers; + + try { + doRequest(buf, parseURL( buf ), responseMsg, responseCode, headers, sock.remoteAddr() ); + } + catch ( std::exception& e ) { + responseCode = 500; + responseMsg = "error loading page: "; + responseMsg += e.what(); + } + catch ( ... ) { + responseCode = 500; + responseMsg = "unknown error loading page"; + } + + stringstream ss; + ss << "HTTP/1.0 " << responseCode; + if ( responseCode == 200 ) ss << " OK"; + ss << "\r\n"; + if ( headers.empty() ) { + ss << "Content-Type: text/html\r\n"; + } + else { + for ( vector<string>::iterator i = headers.begin(); i != headers.end(); i++ ) { + assert( strncmp("Content-Length", i->c_str(), 14) ); + ss << *i << "\r\n"; + } + } + ss << "Connection: close\r\n"; + ss << "Content-Length: " << responseMsg.size() << "\r\n"; + ss << "\r\n"; + ss << responseMsg; + string response = ss.str(); + + try { + sock.send( response.c_str(), response.size() , "http response" ); + sock.close(); + } + catch ( SocketException& e ) { + log(1) << "couldn't send data to http client: " << e << endl; + } + } + + string MiniWebServer::getHeader( const char * req , string wanted ) { + const char * headers = strchr( req , '\n' ); + if ( ! headers ) + return ""; + pcrecpp::StringPiece input( headers + 1 ); + + string name; + string val; + pcrecpp::RE re("([\\w\\-]+): (.*?)\r?\n"); + while ( re.Consume( &input, &name, &val) ) { + if ( name == wanted ) + return val; + } + return ""; + } + + string MiniWebServer::urlDecode(const char* s) { + stringstream out; + while(*s) { + if (*s == '+') { + out << ' '; + } + else if (*s == '%') { + out << fromHex(s+1); + s+=2; + } + else { + out << *s; + } + s++; + } + return out.str(); + } + +} // namespace mongo |