Skip to content

Commit e477e44

Browse files
committed
Moved HTTP requests parsing/headers construction to BasicHTTP.
Moved file/executables handling to dedicated modules (Static/Exec).
1 parent ee29878 commit e477e44

File tree

7 files changed

+305
-164
lines changed

7 files changed

+305
-164
lines changed

src/BasicHTTP.cpp

Lines changed: 69 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,80 @@
11
#include "BasicHTTP.h"
22

33
/*
4-
* BasicHTTP - implements a simple way to create serializable HTTP reponses that can be returned by router
4+
* BasicHTTP - implements a simple way to create serializable HTTP reponses that can be returned by worker
55
*/
66

77
BasicHTTP::BasicHTTP() {
8-
8+
this->logger = new Logger("BasicHTTP");
99
}
1010

1111
BasicHTTP::~BasicHTTP() {
12+
delete(this->logger);
13+
}
14+
15+
bool is_valid(BasicHTTP::request req, std::string http_ver) {
16+
// if all tests pass, return true
17+
return (
18+
(http_ver == "HTTP/1.0" || http_ver == "HTTP/1.1")
19+
&& req.method == "GET" // || POST
20+
&& req.uri.length() > 0
21+
);
1222
}
1323

24+
BasicHTTP::request BasicHTTP::parse_request(std::string req_str) {
25+
request req;
26+
// From http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html#sec5
27+
// Request-Line = Method SP Request-URI SP HTTP-Version CRLF
28+
size_t pos = 0, prev_pos = 0;
29+
30+
// first read the method
31+
if ((pos = req_str.find(" ", prev_pos)) != std::string::npos) {
32+
req.method = req_str.substr(prev_pos, pos-prev_pos);
33+
prev_pos = pos + 1;
34+
}
35+
36+
// the the uri
37+
if ((pos = req_str.find(" ", prev_pos)) != std::string::npos) {
38+
req.uri = req_str.substr(prev_pos, pos-prev_pos);
39+
prev_pos = pos + 1;
40+
}
41+
42+
// finally the HTTP version
43+
std::string http_ver;
44+
if ((pos = req_str.find("\r\n", prev_pos)) != std::string::npos) {
45+
http_ver = req_str.substr(prev_pos, pos-prev_pos);
46+
prev_pos = pos + 1;
47+
}
48+
this->logger->info("Method: " + req.method + ", HTTP version string: " + http_ver + ", URI: " + req.uri);
49+
50+
// now end with checking if it's actually valid
51+
req.valid = is_valid(req, http_ver);
52+
53+
return req;
54+
}
55+
56+
BasicHTTP::response BasicHTTP::render_headers(int code, DataHandler::resource rsrc) {
57+
response resp;
58+
59+
// by default no headers are created
60+
resp.has_headers = false;
61+
if (rsrc.type != "executable") {
62+
resp.headers =
63+
"HTTP/1.1 "+std::to_string(code)+" OK\n"
64+
"Server: HackTTP\n"
65+
"Connection: close\n"
66+
"Content-Type: "+rsrc.type+"\n";
67+
;
68+
69+
if (rsrc.type.find("image/") != std::string::npos) {
70+
resp.headers += "Accept-Ranges: bytes\n";
71+
resp.headers += "Content-Length: " + std::to_string(rsrc.size) + "\n";
72+
}
73+
74+
// now send the headers
75+
resp.headers += "\n";
76+
resp.has_headers = true;
77+
}
78+
79+
return resp;
80+
}

src/BasicHTTP.h

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,45 @@
11
#ifndef SRC_BASICHTTP_H_
22
#define SRC_BASICHTTP_H_
33

4+
#include "DataHandler.h"
5+
#include "Exceptions.h"
6+
#include "Logger.h"
7+
8+
// Currently returned HTTP CODES
9+
#define HTTP_OK 200
10+
#define HTTP_BAD_REQUEST 400
11+
#define HTTP_FORBIDDEN 403
12+
#define HTTP_NOT_FOUND 404
13+
#define HTTP_UNSUP_MEDIA_TYPE 415
14+
#define HTTP_INTERNAL_SRV_ERROR 500
15+
#define HTTP_NOT_IMPLEMENTED 501
16+
417
class BasicHTTP {
18+
private:
19+
Logger *logger;
520
public:
6-
BasicHTTP();
21+
struct request {
22+
std::string method;
23+
std::string uri;
24+
bool valid;
25+
};
26+
27+
struct response {
28+
std::string headers;
29+
bool has_headers;
30+
};
31+
32+
BasicHTTP();
733
virtual ~BasicHTTP();
34+
request parse_request(std::string req_str);
35+
response render_headers(int code, DataHandler::resource rsrc);
36+
37+
class Exception: public BaseException {
38+
public:
39+
Exception(std::string msg = "Unknown basic http exception") {
40+
this->reason = msg;
41+
}
42+
};
843
};
944

1045
#endif /* SRC_BASICHTTP_H_ */

src/DataHandler.cpp

Lines changed: 9 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ bool is(char * mime, std::string type) {
4040
return (strstr(mime, type.c_str()) != NULL);
4141
}
4242

43-
resource DataHandler::read_resource(std::string path) {
43+
DataHandler::resource DataHandler::read_resource(std::string path) {
4444
// prepend cwd() to path
4545

4646
if (!verify_path(path))
@@ -51,16 +51,17 @@ resource DataHandler::read_resource(std::string path) {
5151
this->logger->debug("Checking resource at: " + path);
5252

5353
// check mime type of resource
54+
DataHandler::Exec runner;
5455
std::string args[2] = { "/usr/bin/file", path };
55-
resource file_mime = run_command(args);
56+
DataHandler::resource file_mime = runner.run_command(args);
5657
char * mime = file_mime.data;
5758

58-
resource output;
59+
DataHandler::resource output;
5960
// now check for known mime types
6061
if (is(mime, "executable")) {
6162
// run the script
6263
std::string args[2] = { path, "" }; // TODO: Fix me too!
63-
resource script_output = run_command(args);
64+
DataHandler::resource script_output = runner.run_command(args);
6465
output.data = script_output.data;
6566
output.size = script_output.size;
6667
output.type = "executable";
@@ -73,7 +74,8 @@ resource DataHandler::read_resource(std::string path) {
7374
else if (is(mime, "MS Windows icon")) { output.type = "image/vnd.microsoft.icon"; }
7475

7576
if (output.type.length() > 0 && output.type != "executable") {
76-
resource f = get_file(path);
77+
DataHandler::Static getter;
78+
DataHandler::resource f = getter.get_file(path);
7779
output.data = f.data;
7880
output.size = f.size;
7981
}
@@ -95,32 +97,9 @@ std::string DataHandler::get_working_path() {
9597
return ( getcwd(temp, PATH_MAX) ? std::string( temp ) : std::string("") );
9698
}
9799

98-
resource DataHandler::get_file(std::string path) {
99-
this->logger->debug("Read file: " + path);
100-
int fd = open(path.c_str(), O_RDONLY);
101-
if (fd < 0) {
102-
// TODO: replace with a proper HTTP CODE
103-
char * err = std::strerror(errno);
104-
throw DataHandler::FileNotFound("Error while reading file contents at " + path + ": " + std::string(err ? err : "unknown error"));
105-
}
106-
107-
long fsize = lseek(fd, 0, SEEK_END);
108-
lseek(fd, 0, SEEK_SET);
109-
110-
resource data;
111-
data.data = (char *) malloc(fsize+1);
112-
read(fd, data.data, fsize);
113-
close(fd);
114-
115-
data.data[fsize] = '\0';
116-
data.size = fsize;
117-
118-
return data;
119-
}
120-
121-
resource DataHandler::get_error_file(int error_code, std::string param) {
100+
DataHandler::resource DataHandler::get_error_file(int error_code, std::string param) {
122101
// start by reading the error template
123-
resource output = read_resource("/errors/"+ std::to_string(error_code) +".html");
102+
DataHandler::resource output = DataHandler::read_resource("/errors/"+ std::to_string(error_code) +".html");
124103
// now prepare a place to write the filled template
125104
long new_size = output.size + param.length() - 3;
126105
char * data = (char *) malloc(new_size * sizeof(char));
@@ -135,85 +114,3 @@ resource DataHandler::get_error_file(int error_code, std::string param) {
135114

136115
return output;
137116
}
138-
139-
resource DataHandler::run_command(std::string args[]) {
140-
int comms[2];
141-
// start with a small 1k buffer
142-
int buf_pos = 0, buf_max = 1024, buf_blocks = 1;
143-
resource output;
144-
output.data = (char *) malloc(buf_blocks * buf_max * sizeof(char));
145-
146-
if (pipe(comms) < 0) {
147-
char * err = std::strerror(errno);
148-
throw DataHandler::Exception("Cannot create pipe: " + std::string(err ? err : "unknown error"));
149-
}
150-
151-
int pid = fork();
152-
if (pid == 0) {
153-
// redirect STDOUT to our comms
154-
if (dup2(comms[1], STDOUT_FILENO) == -1) {
155-
char * err = std::strerror(errno);
156-
throw DataHandler::Exception("Cannot redirect STDOUT to pipe: " + std::string(err ? err : "unknown error"));
157-
}
158-
159-
// same with STDERR
160-
if (dup2(comms[1], STDERR_FILENO) == -1) {
161-
char * err = std::strerror(errno);
162-
throw DataHandler::Exception("Cannot redirect STDERR to pipe: " + std::string(err ? err : "unknown error"));
163-
}
164-
165-
// now close the pipe on our side
166-
close(comms[0]);
167-
168-
// now run the target
169-
// TODO: Fix me! I'm ugly!
170-
if (execl(args[0].c_str(), args[0].c_str(), args[1].c_str(), (char *) 0) < 0) {
171-
char * err = std::strerror(errno);
172-
throw DataHandler::Exception(
173-
"Cannot exec '" + std::string(args[0]) + "' due to: " + std::string(err ? err : "unknown error")
174-
);
175-
}
176-
}
177-
else if (pid > 0) {
178-
close(comms[1]);
179-
180-
// Just a char by char read here, you can change it accordingly
181-
char rchar;
182-
while (read(comms[0], &rchar, 1) == 1) {
183-
output.data[buf_pos++] = rchar;
184-
if (buf_pos >= buf_max){
185-
// extend the buffer by another 1k block
186-
buf_blocks++;
187-
// reset the curent position
188-
buf_pos = 0;
189-
// allocate more memory
190-
output.data = (char *) realloc(output.data, buf_blocks * buf_max * sizeof(char));
191-
if (output.data == NULL) {
192-
char * err = std::strerror(errno);
193-
throw DataHandler::Exception(
194-
"Error while reading output from: " + std::string(args[0]) +", "
195-
+ "because of: " + std::string(err ? err : "unknown error")
196-
);
197-
}
198-
}
199-
}
200-
// add NULL termination
201-
output.data[buf_pos] = '\0';
202-
output.size = (buf_blocks - 1) * buf_max + buf_pos + 1;
203-
204-
close(comms[0]);
205-
}
206-
else {
207-
// fork failed
208-
char * err = std::strerror(errno);
209-
close(comms[0]);
210-
close(comms[1]);
211-
throw DataHandler::Exception("Cannot fork: " + std::string(err ? err : "unknown error"));
212-
}
213-
214-
if (strstr(output.data, "DataHandler::Exception") != NULL) {
215-
throw DataHandler::Exception("Fork returned an exception: " + std::string(output.data));
216-
}
217-
218-
return output;
219-
}

src/DataHandler.h

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,26 +4,44 @@
44
#include "Exceptions.h"
55
#include "Logger.h"
66

7-
struct resource {
8-
std::string type;
9-
char * data;
10-
long size;
11-
};
12-
137
class DataHandler {
8+
public:
9+
struct resource {
10+
std::string type;
11+
char * data;
12+
long size;
13+
};
14+
1415
private:
1516
Logger *logger;
1617
std::string get_working_path();
1718
bool verify_path(std::string path);
18-
resource run_command(std::string args[]);
19-
resource get_file(std::string path);
20-
2119
public:
22-
DataHandler();
20+
DataHandler();
2321
virtual ~DataHandler();
2422
resource read_resource(std::string path);
2523
resource get_error_file(int error_code, std::string param);
2624

25+
class Static {
26+
private:
27+
Logger *logger;
28+
public:
29+
Static();
30+
~Static();
31+
resource get_file(std::string path);
32+
resource get_error_file(int error_code, std::string param);
33+
};
34+
35+
class Exec {
36+
private:
37+
Logger *logger;
38+
public:
39+
Exec();
40+
~Exec();
41+
resource run_command(std::string args[]);
42+
};
43+
44+
// Exceptions
2745
class Exception: public BaseException {
2846
public:
2947
Exception(std::string msg = "Unknown data handler exception") {

0 commit comments

Comments
 (0)