Skip to content

Commit 5bc46e5

Browse files
committed
Simplified resource manager. Fixed parsing bugs in HTTPmessage and request. Proplery serves GET and HEAD requests
1 parent 6e0a92a commit 5bc46e5

File tree

12 files changed

+235
-384
lines changed

12 files changed

+235
-384
lines changed

HTTPMessage.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,7 @@ void HTTPMessage::parseHeaders() {
185185
bool HTTPMessage::parseBody() {
186186
// Content-Length should exist (size of the Body data) if there is body data
187187
string hlenstr = "";
188-
int contentLen = 0;
188+
unsigned int contentLen = 0;
189189
hlenstr = getHeaderValue("Content-Length");
190190

191191
// No body data to read:

HTTPResponse.cpp

Lines changed: 32 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -40,39 +40,53 @@ void HTTPResponse::init() {
4040
}
4141

4242
/**
43-
* Get the status string representation of the Response's set status code.
44-
* To be read by humans, non standard representation
45-
*
43+
* Determine the status code based on the parsed Responses reason string
44+
* The reason string is non standard so this method needs to change in order to handle
45+
* responses with different kinds of strings
4646
*/
47-
string HTTPResponse::getStatusStr() {
48-
// Place the status code as part of the human representation.
49-
stringstream ret;
50-
ret << status << " - ";
51-
47+
void HTTPResponse::determineStatusCode() {
48+
if(reason.find("Continue") != string::npos) {
49+
status = Status(CONTINUE);
50+
} else if(reason.find("OK") != string::npos) {
51+
status = Status(OK);
52+
} else if(reason.find("Bad Request") != string::npos) {
53+
status = Status(BAD_REQUEST);
54+
} else if(reason.find("Not Found") != string::npos) {
55+
status = Status(NOT_FOUND);
56+
} else if(reason.find("Server Error") != string::npos) {
57+
status = Status(SERVER_ERROR);
58+
} else if(reason.find("Not Implemented") != string::npos) {
59+
status = Status(NOT_IMPLEMENTED);
60+
} else {
61+
}
62+
}
63+
64+
/**
65+
* Determine the reason string based on the Response's status code
66+
*/
67+
void HTTPResponse::determineReasonStr() {
5268
switch(status) {
5369
case Status(CONTINUE):
54-
ret << "Continue";
70+
reason = "Continue";
5571
break;
5672
case Status(OK):
57-
ret << "OK";
73+
reason = "OK";
5874
break;
5975
case Status(BAD_REQUEST):
60-
ret << "Bad Request";
76+
reason = "Bad Request";
6177
break;
6278
case Status(NOT_FOUND):
63-
ret << "Not Found";
79+
reason = "Not Found";
6480
break;
6581
case Status(SERVER_ERROR):
66-
ret << "Internal Server Error";
82+
reason = "Internal Server Error";
6783
break;
6884
case Status(NOT_IMPLEMENTED):
69-
ret << "Method not implemented";
85+
reason = "Method not implemented";
7086
break;
7187
default:
7288
break;
7389
}
74-
75-
return ret.str();
7690
}
7791

7892
/**
@@ -97,7 +111,7 @@ byte* HTTPResponse::create(bool freshCreate) {
97111

98112
// Insert the status line: <version> <status code> <reason>\r\n
99113
stringstream sline;
100-
sline << version << " " << status << " " << getStatusStr();
114+
sline << version << " " << status << " " << reason;
101115
putLine(sline.str());
102116

103117
// Put all headers
@@ -131,7 +145,7 @@ bool HTTPResponse::parse() {
131145
// Get elements from the status line: <version> <status code> <reason>\r\n
132146
version = getStrElement();
133147
statusstr = getStrElement();
134-
status = atoi(statusstr.c_str());
148+
determineStatusCode();
135149
reason = getLine(); // Pull till \r\n termination
136150

137151
// Validate the HTTP version. If there is a mismatch, discontinue parsing

HTTPResponse.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,14 +21,17 @@
2121

2222
#include <ctime>
2323

24-
#include "ByteBuffer.h"
24+
#include "HTTPMessage.h"
2525

2626
class HTTPResponse : public HTTPMessage {
2727
private:
2828
// Response variables
2929
int status;
3030
string reason;
3131

32+
void determineReasonStr();
33+
void determineStatusCode();
34+
3235
protected:
3336
virtual void init();
3437

@@ -43,12 +46,11 @@ class HTTPResponse : public HTTPMessage {
4346

4447
// Accessors & Mutators
4548

46-
string getStatusStr();
4749
void setStatus (int scode) {
4850
status = scode;
51+
determineReasonStr();
4952
}
5053

51-
// Return's parsed reason string
5254
string getReason() {
5355
return reason;
5456
}

HTTPServer.cpp

Lines changed: 72 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -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() {
111111
void 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
*/
303304
void 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
*/
391412
void 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);

HTTPServer.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,16 @@ class HTTPServer {
4444
// Private methods
4545
void acceptConnection();
4646
Client *getClient(SOCKET clfd);
47-
void disconnectClient(Client* cl);
47+
void closeSockets();
48+
void disconnectClient(Client* cl, bool mapErase = true);
4849
void handleClient(Client* cl);
50+
void sendStatusResponse(Client* cl, int status);
4951
void sendResponse(Client* cl, HTTPResponse* res, bool disconnect = false);
5052

5153
// Request handlers
5254
void handleRequest(Client* cl, HTTPRequest* req);
53-
HTTPResponse* handleHead(Client* cl, HTTPRequest *req);
54-
HTTPResponse* handleGet(Client* cl, HTTPRequest *req);
55-
void closeSockets();
55+
void handleHead(Client* cl, HTTPRequest *req);
56+
void handleGet(Client* cl, HTTPRequest *req);
5657

5758
public:
5859
HTTPServer();

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ HTTPResponse.o: HTTPResponse.cpp
3232
HTTPServer.o: HTTPServer.cpp
3333
$(CC) $(FLAGS) -c HTTPServer.cpp -o $@
3434

35-
main.o: Testers.h main.cpp
35+
main.o: main.cpp
3636
$(CC) $(FLAGS) -c main.cpp -o $@
3737

3838
Resource.o: Resource.cpp

Resource.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
#include "Resource.h"
22

3-
Resource::Resource(std::string rel, std::string disk, bool memoryResident) {
4-
relLoc = rel;
5-
diskLoc = disk;
6-
inMemory = memoryResident;
3+
Resource::Resource(std::string loc) {
4+
location = loc;
5+
encoding = "";
6+
language = "";
7+
md5 = "";
8+
size = 0;
79
data = NULL;
810
}
911

0 commit comments

Comments
 (0)