@@ -12,7 +12,7 @@ HTTPServer::HTTPServer() {
1212 memset (&serverAddr, 0 , sizeof (serverAddr)); // clear the struct
1313
1414 // Create a resource manager managing the VIRTUAL base path ./
15- resMgr = new ResourceManager (" ./" , true );
15+ resMgr = new ResourceManager (" ./htdocs/ " );
1616
1717 // Instance clientMap, relates Socket Descriptor to pointer to Client object
1818 clientMap = new map<SOCKET, Client*>();
@@ -111,9 +111,9 @@ void HTTPServer::stop() {
111111void HTTPServer::closeSockets () {
112112 // Close all open connections and delete Client's from memory
113113 std::map<int , Client*>::const_iterator it;
114- for (it = clientMap->begin (); it != clientMap->end (); it++ ) {
114+ for (it = clientMap->begin (); it != clientMap->end (); ++it ) {
115115 Client *cl = it->second ;
116- disconnectClient (cl);
116+ disconnectClient (cl, false );
117117 }
118118
119119 // Clear the map
@@ -230,8 +230,10 @@ Client* HTTPServer::getClient(SOCKET clfd) {
230230 * Close the client's socket descriptor and release it from the FD map, client map, and memory
231231 *
232232 * @param cl Pointer to Client object
233+ * @param mapErase When true, remove the client from the client map. Needed if operations on the
234+ * client map are being performed and we don't want to remove the map entry right away
233235 */
234- void HTTPServer::disconnectClient (Client *cl) {
236+ void HTTPServer::disconnectClient (Client *cl, bool mapErase ) {
235237 if (cl == NULL )
236238 return ;
237239
@@ -242,14 +244,13 @@ void HTTPServer::disconnectClient(Client *cl) {
242244 FD_CLR (cl->getSocket (), &fd_master);
243245
244246 // Remove the client from the clientMap
245- clientMap->erase (cl->getSocket ());
247+ if (mapErase)
248+ clientMap->erase (cl->getSocket ());
246249
247250 // Delete the client object from memory
248251 delete cl;
249252}
250253
251- // http://www.yolinux.com/TUTORIALS/Sockets.html#TIPS
252-
253254/* *
254255 * Handle Client
255256 * Recieve data from a client that has indicated (via select()) that it has data waiting. Pass recv'd data to handleRequest()
@@ -301,45 +302,28 @@ void HTTPServer::handleClient(Client *cl) {
301302 * @param req HTTPRequest object filled with raw packet data
302303 */
303304void HTTPServer::handleRequest (Client *cl, HTTPRequest* req) {
304- HTTPResponse* res = NULL ;
305- bool dcClient = false ;
306-
307305 // Parse the request
308- // If there's an error, report it and send the appropriate error in response
306+ // If there's an error, report it and send a server error in response
309307 if (!req->parse ()) {
310308 cout << " [" << cl->getClientIP () << " ] There was an error processing the request of type: " << req->methodIntToStr (req->getMethod ()) << endl;
311309 cout << req->getParseError () << endl;
312- // TODO: Send appropriate HTTP error message
313- disconnectClient (cl);
310+ sendStatusResponse (cl, Status (SERVER_ERROR));
314311 return ;
315312 }
316313
317314 // Send the request to the correct handler function
318315 switch (req->getMethod ()) {
319316 case Method (HEAD):
320- res = handleHead (cl, req);
317+ handleHead (cl, req);
321318 break ;
322319 case Method (GET):
323- res = handleGet (cl, req);
320+ handleGet (cl, req);
324321 break ;
325322 default :
326323 cout << cl->getClientIP () << " : Could not handle or determine request of type " << req->methodIntToStr (req->getMethod ()) << endl;
327- break ;
324+ sendStatusResponse (cl, Status (NOT_IMPLEMENTED));
325+ break ;
328326 }
329-
330- // If a response could not be built, send a 500 (internal server error)
331- if (res == NULL ) {
332- res = new HTTPResponse ();
333- res->setStatus (Status (SERVER_ERROR));
334- std::string body = res->getStatusStr ();
335- res->setData ((byte*)body.c_str (), body.size ());
336- dcClient = true ;
337- }
338-
339- // Send the built response to the client
340- sendResponse (cl, res, dcClient);
341-
342- delete res;
343327}
344328
345329/* *
@@ -349,22 +333,23 @@ void HTTPServer::handleRequest(Client *cl, HTTPRequest* req) {
349333 * @param cl Client requesting the resource
350334 * @param req State of the request
351335 */
352- HTTPResponse* HTTPServer::handleGet (Client *cl, HTTPRequest *req) {
353- HTTPResponse* res = NULL ;
354-
336+ void HTTPServer::handleGet (Client *cl, HTTPRequest *req) {
355337 // Check if the requested resource exists
356338 std::string uri = req->getRequestUri ();
357339 Resource* r = resMgr->getResource (uri);
358340 if (r != NULL ) { // Exists
359-
341+ HTTPResponse* res = new HTTPResponse ();
342+ res->setStatus (Status (OK));
343+ std::stringstream sz;
344+ sz << r->getSize ();
345+ res->addHeader (" Content-Type" , " text/html" );
346+ res->addHeader (" Content-Length" , sz.str ());
347+ res->setData (r->getData (), r->getSize ());
348+ sendResponse (cl, res, true );
349+ delete res;
360350 } else { // Not found
361- res = new HTTPResponse ();
362- res->setStatus (Status (NOT_FOUND));
363- std::string body = res->getStatusStr ();
364- res->setData ((byte*)body.c_str (), body.size ());
351+ sendStatusResponse (cl, Status (NOT_FOUND));
365352 }
366-
367- return res;
368353}
369354
370355/* *
@@ -374,21 +359,60 @@ HTTPResponse* HTTPServer::handleGet(Client *cl, HTTPRequest *req) {
374359 * @param cl Client requesting the resource
375360 * @param req State of the request
376361 */
377- HTTPResponse* HTTPServer::handleHead (Client *cl, HTTPRequest *req) {
378- HTTPResponse* res = NULL ;
362+ void HTTPServer::handleHead (Client *cl, HTTPRequest *req) {
363+ // Check if the requested resource exists
364+ std::string uri = req->getRequestUri ();
365+ Resource* r = resMgr->getResource (uri);
366+ if (r != NULL ) { // Exists
367+ // Only include headers associated with the file. NEVER contains a body
368+ HTTPResponse* res = new HTTPResponse ();
369+ res->setStatus (Status (OK));
370+ std::stringstream sz;
371+ sz << r->getSize ();
372+ res->addHeader (" Content-Type" , " text/html" );
373+ res->addHeader (" Content-Length" , sz.str ());
374+ sendResponse (cl, res, true );
375+ delete res;
376+ } else { // Not found
377+ sendStatusResponse (cl, Status (NOT_FOUND));
378+ }
379+ }
380+
381+ /* *
382+ * Send Status Response
383+ * Send a predefined HTTP status code response to the client consisting of
384+ * only the status code and required headers, then disconnect the client
385+ *
386+ * @param cl Client to send the status code to
387+ * @param status Status code corresponding to the enum in HTTPMessage.h
388+ */
389+ void HTTPServer::sendStatusResponse (Client* cl, int status) {
390+ HTTPResponse* res = new HTTPResponse ();
391+ res->setStatus (Status (status));
392+ std::string body = res->getReason ();
393+ std::stringstream sz;
394+ sz << body.size ();
395+ res->addHeader (" Content-Type" , " text/html" );
396+ res->addHeader (" Content-Length" , sz.str ());
397+ res->setData ((byte*)body.c_str (), body.size ());
398+
399+ sendResponse (cl, res, true );
379400
380- return NULL ;
401+ delete res ;
381402}
382403
383404/* *
384405 * Send Response
385- * Send HTTPResponse packet data to a particular Client
406+ * Send a generic HTTPResponse packet data to a particular Client
386407 *
387408 * @param cl Client to send data to
388409 * @param buf ByteBuffer containing data to be sent
389410 * @param disconnect Should the server disconnect the client after sending (Optional, default = false)
390411 */
391412void HTTPServer::sendResponse (Client* cl, HTTPResponse* res, bool disconnect) {
413+ // Server Header
414+ res->addHeader (" Server" , " httpserver/1.0" );
415+
392416 // Time stamp the response with the Date header
393417 string tstr;
394418 char tbuf[36 ];
@@ -429,6 +453,10 @@ void HTTPServer::sendResponse(Client* cl, HTTPResponse* res, bool disconnect) {
429453 }
430454
431455 cout << " [" << cl->getClientIP () << " ] was sent " << totalSent << " bytes" << endl;
456+ for (unsigned int i = 0 ; i < totalSent; i++) {
457+ cout << pData[i];
458+ }
459+ cout << endl;
432460
433461 if (disconnect)
434462 disconnectClient (cl);
0 commit comments