Skip to content

Commit

Permalink
feat: improved GET request
Browse files Browse the repository at this point in the history
  • Loading branch information
Taanviir committed Jun 6, 2024
1 parent 655d2e7 commit e7d498c
Show file tree
Hide file tree
Showing 5 changed files with 111 additions and 54 deletions.
82 changes: 48 additions & 34 deletions sources/http/handler/GetRequestHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,57 +15,71 @@ const vector<char> GetRequestHandler::get_resource(const Request& r)
{
status = r.get_status();

const string& resource = r.get_resource();
const string& resourcePath = r.get_resource_path();
const string& resource = r.get_resource();
const string& resourcePath = r.get_resource_path();
const string& locationMatch = r.get_location_match();

// return list_directory(resourcePath, resource); //! dir listing
string defaultPath = cfg.root + "/";
string index = defaultPath + cfg.indexFile;
bool autoindex = cfg.autoindex;

// default path
if (!r.get_location_match().empty()) {
// found matching location
if (!locationMatch.empty()) {
const Location& location = cfg.locations.at(locationMatch);

autoindex = location.autoindex;
defaultPath = location.root + "/";
index = defaultPath + location.indexFile;
cp.set_index_page(index);
// TODO handle redirection
}
else if (resourcePath == (cfg.root + "/")) {
// TODO if the index file does not exist + autoindex is on, list dir.
cout << "default path" << endl;

Page& p = cp.get_page("index");
_add_header("Content-Type", p.contentType);
_add_header("Content-Length", ws_itoa(p.contentLength));
return p.data;
vector<char> body;
struct stat fileInfo;
stat(resourcePath.c_str(), &fileInfo);
if (S_ISDIR(fileInfo.st_mode)) {
ifstream indexFile(index.c_str(), std::ios_base::binary);
if (indexFile.good()) {
Page& p = cp.get_page(index);
_add_header("Content-Type", p.contentType);
_add_header("Content-Length", ws_itoa(p.contentLength));
return p.data;
}
else if (autoindex) {
body = list_directory(resourcePath, resource);
_add_header("Content-Type", "text/html");
_add_header("Content-Length", ws_itoa(body.size()));
return body;
}
return make_error_body(NOT_FOUND);
}

ifstream resource_file(resourcePath.c_str(), std::ios_base::binary);
if (resource_file.fail())
status = NOT_FOUND; //! need more error handling, eg: forbidden, not allowed, etc
ifstream resourceFile(resourcePath.c_str(), std::ios_base::binary);
if (resourceFile.fail())
return make_error_body(NOT_FOUND);
else if (access(resourcePath.c_str(), R_OK) == -1)
return make_error_body(FORBIDDEN);

// errors
if (status >= 400)
return (make_error_body(status));
string resource_type = find_resource_type(resource);
if (resource_type.length() == 0)
return make_error_body(UNSUPPORTED_MEDIA_TYPE);

vector<char> body;
string resource_type = find_resource_type(resource); //! doesn't make sense
if (resource_type.length() != 0) //! and what if it is zero?
_add_header("Content-Type", resource_type);
if (resource.find("/cgi-bin") != string::npos) {
_add_header("Content-Type", resource_type);

if (locationMatch == "/cgi-bin" && resource.find("/cgi-bin") != string::npos) {
CGI cgi(r, cfg, cp);
body = cgi.execute(r.cgiStatus, r.cgiReadFd,
r.cgiChild); // ! r.fd set reference is kinda idk
body = cgi.execute(r.cgiStatus, r.cgiReadFd, r.cgiChild);
_add_header("Content-Length", ws_itoa(body.size()));
}
else {
body = vector<char>((std::istreambuf_iterator<char>(resource_file)),
body = vector<char>((std::istreambuf_iterator<char>(resourceFile)),
std::istreambuf_iterator<char>());
_add_header("Content-Length", ws_itoa(body.size()));
}

/* authentication function goes here for the requested resource */
// DEBUG_MSG("Resource '" + resource + "' : [" + ws_itoa(resource_size) + "]", W);

// TODO caching control */

// TODO authentication function goes here for the requested resource
// TODO caching control
// TODO compression/encoding

// TODO support range requests, usefull for large files
// TODO support range requests, useful for large files

return body;
}
52 changes: 37 additions & 15 deletions sources/http/handler/PostRequestHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,33 +16,55 @@ Response PostRequestHandler::handle_request(const Request& r)

vector<char> PostRequestHandler::process_data(const Request& r)
{
const string& resource = r.get_resource();
const string& requestBody = r.get_body();
vector<char> responseBody;
// const string& resource = r.get_resource();
const string& resourcePath = r.get_resource_path();
const string& requestBody = r.get_body();
const string& locationMatch = r.get_location_match();


vector<char> responseBody;
// for uploads, check if the location block allows uploads
if (!locationMatch.empty() && locationMatch == "/upload") {
handle_upload();
}

if (requestBody.empty()) // no data to write
return make_error_body(BAD_REQUEST);

// append to file
ofstream outputFile(resource.c_str(), std::ios_base::app);
if (!outputFile.is_open()) // failed to open file
ofstream outputFile(resourcePath.c_str(), std::ios_base::app);
if (outputFile.fail()) // failed to open file
return make_error_body(INTERNAL_SERVER_ERROR);

// need to check if file is too big (return 413 if so)
// need to check if the file type is allowed (return 415 if not)
// need to handle CGI POST requests
//? need to parse the request body
outputFile << requestBody;
if (!parse_request_body(requestBody))
return make_error_body(BAD_REQUEST);

outputFile.close();

status = OK;
//! build response body
string successMsg = "POST request was successful.";
responseBody.assign(successMsg.begin(), successMsg.end());
_add_header("Content-Length", ws_itoa(responseBody.size()));
_add_header("Content-Type", "text/html;");

return responseBody;
}

bool PostRequestHandler::parse_request_body(const string& body)
{
map<string, string> form;
istringstream iss(body);
string keyValuePair;
while (std::getline(iss, keyValuePair, '&')) {
istringstream keyValueStream(keyValuePair);
string key, value;
if (std::getline(std::getline(keyValueStream, key, '='), value)) {
if (!key.empty() && !value.empty())
form.insert(make_pair(key, value));
else
return false;
}
}
return true;
}

void handle_upload()
{
// ...
}
1 change: 1 addition & 0 deletions sources/http/handler/PostRequestHandler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class PostRequestHandler: public RequestHandlerBase {

private:
vector<char> process_data(const Request& r);
bool parse_request_body(const string& body);
};

#endif // POST_REQUEST_HANDLER_HPP
26 changes: 21 additions & 5 deletions sources/parser/ConfigParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ void ConfigParser::parse_index(string& indexFile, const string& root)
if (is_keyword(*_itr) || _itr->find("/") != string::npos)
THROW_EXCEPTION_WITH_INFO(ERR_INDEX);

indexFile = root + "/" + *_itr;
indexFile = *_itr;

check_semicolon();
}
Expand Down Expand Up @@ -287,9 +287,25 @@ vector<string> ConfigParser::parse_allow_methods(void)
return methods;
}

void ConfigParser::parse_http_redirection()
void ConfigParser::parse_http_redirection(RedirectionMap& redirMap)
{
// redirect [uri] [other uri]
++_itr; // move to the URI being redirected
string redirectFrom = *_itr;
if (redirectFrom[0] != '/') // uri should begin with /
THROW_EXCEPTION_WITH_INFO(ERR_REDIRECT_SLASH);
else if (redirectFrom.find_first_of("/") != redirectFrom.find_last_of("/"))
THROW_EXCEPTION_WITH_INFO(ERR_REDIRECT_DUP_SLASH);

++_itr; // move to the target URI
string redirectTo = *_itr;
if (redirectTo[0] != '/') // uri should begin with /
THROW_EXCEPTION_WITH_INFO(ERR_REDIRECT_SLASH);
else if (redirectTo.find_first_of("/") != redirectTo.find_last_of("/"))
THROW_EXCEPTION_WITH_INFO(ERR_REDIRECT_DUP_SLASH);

redirMap[redirectFrom] = redirectTo;

check_semicolon();
}

void ConfigParser::parse_location_context(ServerConfig& server)
Expand Down Expand Up @@ -329,8 +345,8 @@ void ConfigParser::parse_location_context(ServerConfig& server)
parse_index(location.indexFile, location.root + uri);
else if (*_itr == "autoindex")
location.autoindex = parse_autoindex();
// else if (*itr == "redirect")
// location.
else if (*_itr == "redirect")
parse_http_redirection(location.redirections);
else if (*_itr == ";" || *_itr == "{")
++_itr;
else
Expand Down
4 changes: 4 additions & 0 deletions sources/parser/ServerConfig.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,16 @@
#ifndef CONFIG_HPP
#define CONFIG_HPP

typedef map<string, string> RedirectionMap;

struct Location {
string root;
string indexFile;
bool autoindex;
size_t maxBodySize;
vector<string> methods;
RedirectionMap redirections;


Location() : indexFile("index.html"), autoindex(false), maxBodySize(1000000) {}
};
Expand Down

0 comments on commit e7d498c

Please sign in to comment.