@@ -9,7 +9,7 @@ HTTPServer::HTTPServer() {
99 memset (&serverAddr, 0 , sizeof (serverAddr)); // clear the struct
1010 keepRunning = false ;
1111
12- // Create a resource manager managing the base path ./
12+ // Create a resource manager managing the VIRTUAL base path ./
1313 resMgr = new ResourceManager (" ./" , true );
1414
1515 // Instance clientMap, relates Socket Descriptor to pointer to Client object
@@ -41,7 +41,7 @@ bool HTTPServer::initSocket(int port) {
4141 // Create a handle for the listening socket, TCP
4242 listenSocket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
4343 if (listenSocket == INVALID_SOCKET) {
44- printf ( " Could not create socket!\n " ) ;
44+ cout << " Could not create socket!" << endl ;
4545 return false ;
4646 }
4747
@@ -52,14 +52,14 @@ bool HTTPServer::initSocket(int port) {
5252
5353 // Bind: Assign the address to the socket
5454 if (bind (listenSocket, (sockaddr*)&serverAddr, sizeof (serverAddr)) != 0 ) {
55- printf ( " Failed to bind to the address!\n " ) ;
55+ cout << " Failed to bind to the address!" << endl ;
5656 return false ;
5757 }
5858
5959 // Listen: Put the socket in a listening state, ready to accept connections
6060 // Accept a backlog of the OS Maximum connections in the queue
6161 if (listen (listenSocket, SOMAXCONN) != 0 ) {
62- printf ( " Failed to put the socket in a listening state\n " ) ;
62+ cout << " Failed to put the socket in a listening state" << endl ;
6363 return false ;
6464 }
6565
@@ -93,28 +93,68 @@ void HTTPServer::closeSockets() {
9393 listenSocket = INVALID_SOCKET;
9494}
9595
96+ /* *
97+ * Accept Connection
98+ * When a new connection is detected in runServer() this function is called. This attempts to accept the pending connection, instance a Client object, and add to the client Map
99+ */
100+ void HTTPServer::acceptConnection () {
101+ // Setup new client with prelim address info
102+ sockaddr_in clientAddr;
103+ int clientAddrLen = sizeof (clientAddr);
104+ SOCKET clfd = INVALID_SOCKET;
105+
106+ // Accept the pending connection and retrive the client descriptor
107+ clfd = accept (listenSocket, (sockaddr*)&clientAddr, (socklen_t *)&clientAddrLen);
108+ if (clfd == INVALID_SOCKET)
109+ return ;
110+
111+ // Instance Client object
112+ Client *cl = new Client (clfd, clientAddr);
113+
114+ // Add to the master FD set
115+ FD_SET (clfd, &fd_master);
116+
117+ // If the new client's handle is greater than the max, set the new max
118+ if (clfd > fdmax)
119+ fdmax = clfd;
120+
121+ // Add the client object to the client map
122+ clientMap->insert (std::pair<int , Client*>(clfd, cl));
123+
124+ // Print the client's IP on connect
125+ cout << " [" << cl->getClientIP () << " ] connected" << endl;
126+ }
127+
128+ /* *
129+ * Run Server
130+ * Main server loop where the socket is initialized and the loop is started, checking for new messages or clients to be read with select()
131+ * and handling them appropriately
132+ */
96133void HTTPServer::runServer (int port) {
97134 // Initialize the socket and put it into a listening state
98135 if (!initSocket (port)) {
99- printf ( " Failed to start server.\n " ) ;
136+ cout << " Failed to start server." << endl ;
100137 return ;
101138 }
139+
140+ cout << " Server started. Listening on port " << port << " ..." << endl;
102141
103142 // Processing loop
104143 while (keepRunning) {
144+ usleep (1000 );
145+
105146 // Copy master set into fd_read for processing
106147 fd_read = fd_master;
107148
108149 // Populate read_fd set with client descriptors that are ready to be read
109- int selret = select (fdmax+1 , &fd_read, NULL , NULL , NULL );
110- if (selret < 0 ) {
150+ if (select (fdmax+1 , &fd_read, NULL , NULL , NULL ) < 0 ) {
111151 // printf("select failed!");
112152 continue ;
113153 }
114154
115155 // Loop through all descriptors in the read_fd set and check to see if data needs to be processed
116156 for (int i = 0 ; i <= fdmax; i++) {
117- // If i isn't within the set of descriptors to be read, skip it
157+ // Socket i isn't ready to be read (not in the read set), continue
118158 if (!FD_ISSET (i, &fd_read))
119159 continue ;
120160
@@ -132,38 +172,6 @@ void HTTPServer::runServer(int port) {
132172 closeSockets ();
133173}
134174
135- /* *
136- * Accept Connection
137- * When a new connection is detected in runServer() this function is called. This attempts to accept the pending connection, instance a Client object, and add to the client Map
138- */
139- void HTTPServer::acceptConnection () {
140- // Setup new client with prelim address info
141- sockaddr_in clientAddr;
142- int clientAddrLen = sizeof (clientAddr);
143- SOCKET clfd = INVALID_SOCKET;
144-
145- // Accept the pending connection and retrive the client descriptor
146- clfd = accept (listenSocket, (sockaddr*)&clientAddr, (socklen_t *)&clientAddrLen);
147- if (clfd == INVALID_SOCKET)
148- return ;
149-
150- // Instance Client object
151- Client *cl = new Client (clfd, clientAddr);
152-
153- // Add to the master FD set
154- FD_SET (clfd, &fd_master);
155-
156- // If the new client's handle is greater than the max, set the new max
157- if (clfd > fdmax)
158- fdmax = clfd;
159-
160- // Add the client object to the client map
161- clientMap->insert (std::pair<int , Client*>(clfd, cl));
162-
163- // Print the client's IP on connect
164- printf (" %s has connected\n " , cl->getClientIP ());
165- }
166-
167175/* *
168176 * Get Client
169177 * Lookup client based on the socket descriptor number in the clientMap
@@ -208,12 +216,20 @@ void HTTPServer::disconnectClient(Client *cl) {
208216
209217// http://www.yolinux.com/TUTORIALS/Sockets.html#TIPS
210218
219+ /* *
220+ * Handle Client
221+ * Recieve data from a client that has indicated (via select()) that it has data waiting. Pass recv'd data to handleRequest()
222+ * Also detect any errors in the state of the socket
223+ *
224+ * @param cl Pointer to Client that sent the data
225+ */
211226void HTTPServer::handleClient (Client *cl) {
212227 if (cl == NULL )
213228 return ;
214229
230+ HTTPRequest* req;
215231 size_t dataLen = 1300 ;
216- char * pData = new char [dataLen];
232+ char * pData = new char [dataLen];
217233
218234 // Receive data on the wire into pData
219235 /* TODO: Figure out what flags need to be set */
@@ -223,56 +239,45 @@ void HTTPServer::handleClient(Client *cl) {
223239 // Determine state of the client socket and act on it
224240 if (lenRecv == 0 ) {
225241 // Client closed the connection
226- printf ( " Client[%s ] has opted to close the connection\n " , cl-> getClientIP ()) ;
242+ cout << " [ " << cl-> getClientIP () << " ] has opted to close the connection" << endl ;
227243 disconnectClient (cl);
228244 } else if (lenRecv < 0 ) {
229245 // Something went wrong with the connection
230246 // TODO: check perror() for the specific error message
231247 disconnectClient (cl);
232248 } else {
233- // Print the data the client sent (in ascii)
234- printf (" %s: \n " , cl->getClientIP ());
235- ascii_print (pData, (int )lenRecv);
249+ // Data received
250+ cout << " [" << cl->getClientIP () << " ] " << lenRecv << " bytes received" << endl;
236251
237- // Add the packet data to a string and pass to processRequest to serve the request
238- string r ;
239- r. append (pData );
240- handleRequest (cl, r) ;
252+ // Place the data in an HTTPRequest and pass it to handleRequest for processing
253+ req = new HTTPRequest ((byte*)pData, lenRecv) ;
254+ handleRequest (cl, req );
255+ delete req ;
241256 }
242257
243258 delete [] pData;
244259}
245260
246- void HTTPServer::sendResponse (Client *cl, HTTPResponse *res) {
247- size_t dataLen = 0 ;
248- char *sData = NULL ;
249- std::string strResp;
250-
251- // Get the string response, allocate memory for the response
252- strResp = res->generateResponse ();
253- dataLen = strlen (strResp.c_str ());
254- sData = new char [dataLen];
255-
256- // Send the data over the wire
257- send (cl->getSocket (), sData , dataLen, 0 );
258-
259- // Delete the allocated space for the response
260- if (sData != NULL )
261- delete sData ;
262- }
263-
264- void HTTPServer::handleRequest (Client *cl, string requestStr) {
265- // Create an HTTPRequest object to consume the requestStr
266- HTTPRequest *req = new HTTPRequest (requestStr);
267- if (req == NULL )
268- return ;
269-
270- HTTPResponse *res = NULL ;
271-
272- // If there was a parse error, report it and send the appropriate error in response
273- if (req->hasParseError ()) {
274- printf (" [%s] There was an error processing the request of type: %i\n " , cl->getClientIP (), req->getMethod ());
275- return ;
261+ /* *
262+ * Handle Request
263+ * Process an incoming request from a Client. Send request off to appropriate handler function
264+ * that corresponds to an HTTP operation (GET, HEAD etc) :)
265+ *
266+ * @param cl Client object where request originated from
267+ * @param req HTTPRequest object filled with raw packet data
268+ */
269+ void HTTPServer::handleRequest (Client *cl, HTTPRequest* req) {
270+ HTTPResponse* res = NULL ;
271+ bool dcClient = false ;
272+
273+ // Parse the request
274+ // If there's an error, report it and send the appropriate error in response
275+ if (!req->parse ()) {
276+ cout << " [" << cl->getClientIP () << " ] There was an error processing the request of type: " << req->methodIntToStr (req->getMethod ()) << endl;
277+ cout << req->getParseError () << endl;
278+ // TODO: Send appropriate HTTP error message
279+ disconnectClient (cl);
280+ return ;
276281 }
277282
278283 // Send the request to the correct handler function
@@ -284,26 +289,97 @@ void HTTPServer::handleRequest(Client *cl, string requestStr) {
284289 res = handleGet (cl, req);
285290 break ;
286291 default :
287- printf ( " [%s] Could not handle or determine request of type: %i \n " , cl-> getClientIP (), req->getMethod ());
292+ cout << cl-> getClientIP () << " : Could not handle or determine request of type " << req-> methodIntToStr ( req->getMethod ()) << endl ;
288293 break ;
289294 }
290-
291- // Send the built response to the client
292- if (res != NULL )
293- sendResponse (cl, res);
294-
295- // Free memory consumed by req and response object
296- delete req;
297- if (res != NULL )
298- delete res;
295+
296+ // If a response could not be built, send a 500 (internal server error)
297+ if (res == NULL ) {
298+ res = new HTTPResponse ();
299+ res->setStatus (Status (SERVER_ERROR));
300+ std::string body = res->getStatusStr ();
301+ res->setData ((byte*)body.c_str (), body.size ());
302+ dcClient = true ;
303+ }
304+
305+ // Send the built response to the client
306+ sendResponse (cl, res, dcClient);
307+
308+ delete res;
299309}
300310
311+ /* *
312+ * Handle Get
313+ * Process a GET request to provide the client with an appropriate response
314+ *
315+ * @param cl Client requesting the resource
316+ * @param req State of the request
317+ */
301318HTTPResponse* HTTPServer::handleGet (Client *cl, HTTPRequest *req) {
302-
303- return NULL ;
319+ HTTPResponse* res = NULL ;
320+
321+ // Check if the requested resource exists
322+ std::string uri = req->getRequestUri ();
323+ Resource* r = resMgr->getResource (uri);
324+ if (r != NULL ) { // Exists
325+
326+ } else { // Not found
327+ res = new HTTPResponse ();
328+ res->setStatus (Status (NOT_FOUND));
329+ std::string body = res->getStatusStr ();
330+ res->setData ((byte*)body.c_str (), body.size ());
331+ }
332+
333+ return res;
304334}
305335
336+ /* *
337+ * Handle Head
338+ * Process a HEAD request to provide the client with an appropriate response
339+ *
340+ * @param cl Client requesting the resource
341+ * @param req State of the request
342+ */
306343HTTPResponse* HTTPServer::handleHead (Client *cl, HTTPRequest *req) {
344+ HTTPResponse* res = NULL ;
345+
307346 return NULL ;
308347}
309348
349+ /* *
350+ * Send Response
351+ * Send HTTPResponse packet data to a particular Client
352+ *
353+ * @param cl Client to send data to
354+ * @param buf ByteBuffer containing data to be sent
355+ * @param disconnect Should the server disconnect the client after sending (Optional, default = false)
356+ */
357+ void HTTPServer::sendResponse (Client* cl, HTTPResponse* res, bool disconnect) {
358+ // Get raw data by creating the response (pData will be cleaned up by the response obj)
359+ byte* pData = res->create ();
360+
361+ // Retrieve sizes
362+ size_t totalSent = 0 , bytesLeft = res->size (), dataLen = res->size ();
363+ ssize_t n = 0 ;
364+
365+ // Solution to deal with partials sends...loop till totalSent matches dataLen
366+ while (totalSent < dataLen) {
367+ n = send (cl->getSocket (), pData+totalSent, bytesLeft, 0 );
368+
369+ // Client closed the connection
370+ if (n < 0 ) {
371+ cout << " [" << cl->getClientIP () << " ] has disconnected." << endl;
372+ disconnectClient (cl);
373+ break ;
374+ }
375+
376+ // Adjust byte count after a successful send
377+ totalSent += n;
378+ bytesLeft -= n;
379+ }
380+
381+ if (disconnect)
382+ disconnectClient (cl);
383+ }
384+
385+
0 commit comments