mirror of
https://github.com/KeyZox71/webserv.git
synced 2025-05-10 20:28:46 +02:00
「✨」 feat(http/GET): file listing page if opening a directory
This commit is contained in:
@ -6,7 +6,7 @@
|
|||||||
/* By: mmoussou <mmoussou@student.42angouleme.fr +#+ +:+ +#+ */
|
/* By: mmoussou <mmoussou@student.42angouleme.fr +#+ +:+ +#+ */
|
||||||
/* +#+#+#+#+#+ +#+ */
|
/* +#+#+#+#+#+ +#+ */
|
||||||
/* Created: 2025/03/16 17:51:46 by mmoussou #+# #+# */
|
/* Created: 2025/03/16 17:51:46 by mmoussou #+# #+# */
|
||||||
/* Updated: 2025/03/17 14:11:44 by mmoussou ### ########.fr */
|
/* Updated: 2025/03/19 02:05:59 by mmoussou ### ########.fr */
|
||||||
/* */
|
/* */
|
||||||
/* ************************************************************************** */
|
/* ************************************************************************** */
|
||||||
|
|
||||||
@ -32,100 +32,14 @@ public:
|
|||||||
static http::Response &getRequest(int error_code);
|
static http::Response &getRequest(int error_code);
|
||||||
static void setEntry(const std::string &key, int value);
|
static void setEntry(const std::string &key, int value);
|
||||||
|
|
||||||
|
static std::map<int, std::string> message;
|
||||||
private:
|
private:
|
||||||
static std::map<int, std::string> populateMessages();
|
static std::map<int, std::string> populateMessages();
|
||||||
|
|
||||||
static std::map<int, std::string> message;
|
|
||||||
static std::map<int, std::string> set_error_pages;
|
static std::map<int, std::string> set_error_pages;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/*std::map<int, std::string> Errors::populateMessages()
|
|
||||||
{
|
|
||||||
std::map<int, std::string> m;
|
|
||||||
|
|
||||||
m[100] = "Continue";
|
|
||||||
m[101] = "Switching Protocols";
|
|
||||||
m[102] = "Processing";
|
|
||||||
m[103] = "Early Hints";
|
|
||||||
m[200] = "OK";
|
|
||||||
m[201] = "Created";
|
|
||||||
m[202] = "Accepted";
|
|
||||||
m[203] = "Non-Authoritative Information";
|
|
||||||
m[204] = "No Content";
|
|
||||||
m[205] = "Reset Content";
|
|
||||||
m[206] = "Partial Content";
|
|
||||||
m[207] = "Multi-Status";
|
|
||||||
m[208] = "Already Reported";
|
|
||||||
m[226] = "IM Used";
|
|
||||||
m[300] = "Multiple Choices";
|
|
||||||
m[301] = "Moved Permanently";
|
|
||||||
m[302] = "Found";
|
|
||||||
m[303] = "See Other";
|
|
||||||
m[304] = "Not Modified";
|
|
||||||
m[305] = "Use Proxy";
|
|
||||||
m[306] = "Switch Proxy";
|
|
||||||
m[307] = "Temporary Redirect";
|
|
||||||
m[308] = "Permanent Redirect";
|
|
||||||
m[400] = "Bad Request";
|
|
||||||
m[401] = "Unauthorized";
|
|
||||||
m[402] = "Payment Required";
|
|
||||||
m[403] = "Forbidden";
|
|
||||||
m[404] = "Not Found";
|
|
||||||
m[405] = "Method Not Allowed";
|
|
||||||
m[406] = "Not Acceptable";
|
|
||||||
m[407] = "Proxy Authentication Required";
|
|
||||||
m[408] = "Request Timeout";
|
|
||||||
m[409] = "Conflict";
|
|
||||||
m[410] = "Gone";
|
|
||||||
m[411] = "Length Required";
|
|
||||||
m[412] = "Precondition Failed";
|
|
||||||
m[413] = "Payload Too Large";
|
|
||||||
m[414] = "URI Too Long";
|
|
||||||
m[415] = "Unsupported Media Type";
|
|
||||||
m[416] = "Range Not Satisfiable";
|
|
||||||
m[417] = "Expectation Failed";
|
|
||||||
m[418] = "I'm a teapot";
|
|
||||||
m[420] = "Method Failure";
|
|
||||||
m[421] = "Misdirected Request";
|
|
||||||
m[422] = "Unprocessable Entity";
|
|
||||||
m[423] = "Locked";
|
|
||||||
m[424] = "Failed Dependency";
|
|
||||||
m[426] = "Upgrade Required";
|
|
||||||
m[428] = "Precondition Required";
|
|
||||||
m[429] = "Too Many Requests";
|
|
||||||
m[431] = "Request Header Fields Too Large";
|
|
||||||
m[451] = "Unavailable For Legal Reasons";
|
|
||||||
m[500] = "Internal Server error";
|
|
||||||
m[501] = "Not Implemented";
|
|
||||||
m[502] = "Bad Gateway";
|
|
||||||
m[503] = "Service Unavailable";
|
|
||||||
m[504] = "gateway Timeout";
|
|
||||||
m[505] = "Http version not supported";
|
|
||||||
m[506] = "Varient Also negotiate";
|
|
||||||
m[507] = "Insufficient Storage";
|
|
||||||
m[508] = "Loop Detected";
|
|
||||||
m[510] = "Not Extended";
|
|
||||||
m[511] = "Network Authentication Required";
|
|
||||||
|
|
||||||
return m;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::map<int, std::string> Errors::message = Errors::populateMessages();
|
|
||||||
|
|
||||||
std::map<int, std::string> Errors::set_error_pages;
|
|
||||||
|
|
||||||
http::Response &Errors::getRequest(int error_code)
|
|
||||||
{
|
|
||||||
http::Response *result = new http::Response;
|
|
||||||
|
|
||||||
if (Errors::set_error_pages.find(error_code) != Errors::set_error_pages.end())
|
|
||||||
result->setBody(Errors::set_error_pages[error_code]);
|
|
||||||
else
|
|
||||||
result->setBody("<html><body><h1>" + Errors::message[error_code] + "</h1></body></html>");
|
|
||||||
return (*result);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
} // -namespace http
|
} // -namespace http
|
||||||
} // -namespace webserv
|
} // -namespace webserv
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
/* By: mmoussou <mmoussou@student.42angouleme.fr +#+ +:+ +#+ */
|
/* By: mmoussou <mmoussou@student.42angouleme.fr +#+ +:+ +#+ */
|
||||||
/* +#+#+#+#+#+ +#+ */
|
/* +#+#+#+#+#+ +#+ */
|
||||||
/* Created: 2025/02/03 17:21:20 by mmoussou #+# #+# */
|
/* Created: 2025/02/03 17:21:20 by mmoussou #+# #+# */
|
||||||
/* Updated: 2025/02/12 00:50:47 by mmoussou ### ########.fr */
|
/* Updated: 2025/03/19 02:09:01 by mmoussou ### ########.fr */
|
||||||
/* */
|
/* */
|
||||||
/* ************************************************************************** */
|
/* ************************************************************************** */
|
||||||
|
|
||||||
@ -31,7 +31,6 @@ public:
|
|||||||
|
|
||||||
void setProtocol(std::string const protocol);
|
void setProtocol(std::string const protocol);
|
||||||
void setStatusCode(size_t const status_code);
|
void setStatusCode(size_t const status_code);
|
||||||
void setStatusText(std::string const status_text);
|
|
||||||
|
|
||||||
std::string str(void) const;
|
std::string str(void) const;
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
/* By: mmoussou <mmoussou@student.42angouleme.fr +#+ +:+ +#+ */
|
/* By: mmoussou <mmoussou@student.42angouleme.fr +#+ +:+ +#+ */
|
||||||
/* +#+#+#+#+#+ +#+ */
|
/* +#+#+#+#+#+ +#+ */
|
||||||
/* Created: 2025/02/03 15:45:07 by mmoussou #+# #+# */
|
/* Created: 2025/02/03 15:45:07 by mmoussou #+# #+# */
|
||||||
/* Updated: 2025/03/17 13:54:48 by mmoussou ### ########.fr */
|
/* Updated: 2025/03/19 03:11:14 by mmoussou ### ########.fr */
|
||||||
/* */
|
/* */
|
||||||
/* ************************************************************************** */
|
/* ************************************************************************** */
|
||||||
|
|
||||||
@ -17,10 +17,12 @@
|
|||||||
#define BUFFER_SIZE 4096
|
#define BUFFER_SIZE 4096
|
||||||
|
|
||||||
int server_socket;
|
int server_socket;
|
||||||
|
int client_socket;
|
||||||
|
|
||||||
void close_socket(int signal)
|
void close_socket(int signal)
|
||||||
{
|
{
|
||||||
std::cerr << std::endl << "closing..." << std::endl;
|
std::cerr << std::endl << "closing..." << std::endl;
|
||||||
|
close(client_socket);
|
||||||
close(server_socket);
|
close(server_socket);
|
||||||
exit(signal);
|
exit(signal);
|
||||||
}
|
}
|
||||||
@ -67,7 +69,8 @@ int main()
|
|||||||
// accept an incoming connection
|
// accept an incoming connection
|
||||||
sockaddr_in client_address;
|
sockaddr_in client_address;
|
||||||
socklen_t client_address_len = sizeof(client_address);
|
socklen_t client_address_len = sizeof(client_address);
|
||||||
int client_socket = accept(server_socket, (sockaddr*)&client_address, &client_address_len);
|
//int client_socket = accept(server_socket, (sockaddr*)&client_address, &client_address_len);
|
||||||
|
client_socket = accept(server_socket, (sockaddr*)&client_address, &client_address_len);
|
||||||
if (client_socket == -1) {
|
if (client_socket == -1) {
|
||||||
std::cerr << "Failed to accept connection" << std::endl;
|
std::cerr << "Failed to accept connection" << std::endl;
|
||||||
continue;
|
continue;
|
||||||
|
@ -6,7 +6,7 @@
|
|||||||
/* By: mmoussou <mmoussou@student.42angouleme.fr +#+ +:+ +#+ */
|
/* By: mmoussou <mmoussou@student.42angouleme.fr +#+ +:+ +#+ */
|
||||||
/* +#+#+#+#+#+ +#+ */
|
/* +#+#+#+#+#+ +#+ */
|
||||||
/* Created: 2025/03/17 14:08:12 by mmoussou #+# #+# */
|
/* Created: 2025/03/17 14:08:12 by mmoussou #+# #+# */
|
||||||
/* Updated: 2025/03/17 14:12:37 by mmoussou ### ########.fr */
|
/* Updated: 2025/03/19 01:51:36 by mmoussou ### ########.fr */
|
||||||
/* */
|
/* */
|
||||||
/* ************************************************************************** */
|
/* ************************************************************************** */
|
||||||
|
|
||||||
|
@ -6,11 +6,16 @@
|
|||||||
/* By: mmoussou <mmoussou@student.42angouleme.fr +#+ +:+ +#+ */
|
/* By: mmoussou <mmoussou@student.42angouleme.fr +#+ +:+ +#+ */
|
||||||
/* +#+#+#+#+#+ +#+ */
|
/* +#+#+#+#+#+ +#+ */
|
||||||
/* Created: 2025/02/03 16:07:01 by mmoussou #+# #+# */
|
/* Created: 2025/02/03 16:07:01 by mmoussou #+# #+# */
|
||||||
/* Updated: 2025/03/17 14:20:31 by mmoussou ### ########.fr */
|
/* Updated: 2025/03/19 03:04:40 by mmoussou ### ########.fr */
|
||||||
/* */
|
/* */
|
||||||
/* ************************************************************************** */
|
/* ************************************************************************** */
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include <requests/HttpRequest.hpp>
|
#include <requests/HttpRequest.hpp>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
|
||||||
using namespace webserv;
|
using namespace webserv;
|
||||||
|
|
||||||
@ -116,32 +121,86 @@ void http::Get::parse(std::string const &data)
|
|||||||
//*/
|
//*/
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char isDirectory(const std::string& path) {
|
||||||
|
struct stat fileStat;
|
||||||
|
if (stat(path.c_str(), &fileStat) != 0)
|
||||||
|
throw;
|
||||||
|
return S_ISDIR(fileStat.st_mode);
|
||||||
|
}
|
||||||
|
|
||||||
http::Response http::Get::execute(void)
|
http::Response http::Get::execute(void)
|
||||||
{
|
{
|
||||||
http::Response response;
|
http::Response response;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
std::ifstream file(this->_target.c_str(), std::ios::binary);
|
if (isDirectory(this->_target))
|
||||||
response.setProtocol(this->_protocol);
|
{
|
||||||
response.setStatusCode(200);
|
DIR *dir;
|
||||||
response.setStatusText("OK");
|
struct dirent *entry;
|
||||||
response.addHeader("Content-Type", "text/html"); // TODO: change it to check the file extension and set it to the corresponding MIME or text/plain if unkown. we will only implement the important MIME types in the Mozilla documentation because https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/MIME_types/Common_types
|
struct stat file_stat;
|
||||||
|
std::vector<std::string> files;
|
||||||
|
|
||||||
|
if ((dir = opendir(this->_target.c_str())) == NULL)
|
||||||
|
throw;
|
||||||
|
while ((entry = readdir(dir)) != NULL)
|
||||||
|
{
|
||||||
|
std::string file_name = entry->d_name;
|
||||||
|
if (file_name == ".")
|
||||||
|
continue;
|
||||||
|
std::string file_path = this->_target + "/" + file_name;
|
||||||
|
if (stat(file_path.c_str(), &file_stat) == 0)
|
||||||
|
{
|
||||||
|
if (S_ISDIR(file_stat.st_mode))
|
||||||
|
files.push_back(file_name + "/");
|
||||||
|
else
|
||||||
|
files.push_back(file_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
closedir(dir);
|
||||||
|
|
||||||
std::ifstream file_end(this->_target.c_str(), std::ios::binary | std::ios::ate);
|
std::sort(files.begin(), files.end());
|
||||||
std::stringstream length;
|
|
||||||
length << (file_end.tellg() - file.tellg());
|
|
||||||
std::cout << length.str();
|
|
||||||
response.addHeader("Content-Length", length.str());
|
|
||||||
|
|
||||||
response.setBody(std::string((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>()));
|
std::string body = "<html><body><ul>\n";
|
||||||
|
for (size_t i = 0; i < files.size(); i++)
|
||||||
|
body += "<li><a href=\"" + files[i] + "\">" + files[i] + "</a></li>\n";
|
||||||
|
body += "</ul></body></html>";
|
||||||
|
|
||||||
|
response.setProtocol(this->_protocol);
|
||||||
|
response.setStatusCode(200);
|
||||||
|
std::stringstream length;
|
||||||
|
length << body.length();
|
||||||
|
response.addHeader("Content-Length", length.str());
|
||||||
|
response.addHeader("Content-Type", "text/html");
|
||||||
|
response.setBody(body);
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::ifstream file(this->_target.c_str(), std::ios::binary);
|
||||||
|
std::streampos file_start = file.tellg();
|
||||||
|
response.setBody(std::string((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>()));
|
||||||
|
std::stringstream length;
|
||||||
|
length << (file.tellg() - file_start);
|
||||||
|
std::cout << length.str() << std::endl;
|
||||||
|
response.addHeader("Content-Length", length.str());
|
||||||
|
|
||||||
|
response.setProtocol(this->_protocol);
|
||||||
|
response.setStatusCode(200);
|
||||||
|
response.addHeader("Content-Type", "text/html"); // TODO: change it to check the file extension and set it to the corresponding MIME or text/plain if unkown. we will only implement the important MIME types in the Mozilla documentation because https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/MIME_types/Common_types
|
||||||
|
|
||||||
|
//std::ifstream file_end(this->_target.c_str(), std::ios::binary | std::ios::ate);
|
||||||
|
//std::stringstream length;
|
||||||
|
//length << (file_end.tellg() - file.tellg());
|
||||||
|
//std::cout << length.str() << std::endl;
|
||||||
|
//response.addHeader("Content-Length", length.str());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (...)
|
catch (...)
|
||||||
{
|
{
|
||||||
// TODO: replace with a predefined array of error pages
|
// TODO: replace with a predefined array of error pages
|
||||||
response.setProtocol(this->_protocol);
|
response.setProtocol(this->_protocol);
|
||||||
response.setStatusCode(404);
|
response.setStatusCode(404);
|
||||||
response.setStatusText("Not Found");
|
|
||||||
response.addHeader("Content-Type", "text/html");
|
response.addHeader("Content-Type", "text/html");
|
||||||
response.setBody("<html><body>nuh uh, get 404'd >:D</body></html>");
|
response.setBody("<html><body>nuh uh, get 404'd >:D</body></html>");
|
||||||
}
|
}
|
||||||
@ -212,7 +271,6 @@ http::Response http::Delete::execute(void)
|
|||||||
throw;
|
throw;
|
||||||
response.setProtocol(this->_protocol);
|
response.setProtocol(this->_protocol);
|
||||||
response.setStatusCode(204); // this cool dude on the internet said i should not do that so i'll change it https://blog.ploeh.dk/2013/04/30/rest-lesson-learned-avoid-204-responses/
|
response.setStatusCode(204); // this cool dude on the internet said i should not do that so i'll change it https://blog.ploeh.dk/2013/04/30/rest-lesson-learned-avoid-204-responses/
|
||||||
response.setStatusText("No Content");
|
|
||||||
time_t now = std::time(NULL);
|
time_t now = std::time(NULL);
|
||||||
response.addHeader("Date", std::string(std::ctime(&now)));
|
response.addHeader("Date", std::string(std::ctime(&now)));
|
||||||
}
|
}
|
||||||
@ -222,7 +280,6 @@ http::Response http::Delete::execute(void)
|
|||||||
|
|
||||||
response.setProtocol(this->_protocol);
|
response.setProtocol(this->_protocol);
|
||||||
response.setStatusCode(404);
|
response.setStatusCode(404);
|
||||||
response.setStatusText("Not Found");
|
|
||||||
response.addHeader("Content-Type", "text/html");
|
response.addHeader("Content-Type", "text/html");
|
||||||
response.setBody("<html><body>nuh uh, get 404'd >:D</body></html>");
|
response.setBody("<html><body>nuh uh, get 404'd >:D</body></html>");
|
||||||
}
|
}
|
||||||
|
@ -6,11 +6,12 @@
|
|||||||
/* By: mmoussou <mmoussou@student.42angouleme.fr +#+ +:+ +#+ */
|
/* By: mmoussou <mmoussou@student.42angouleme.fr +#+ +:+ +#+ */
|
||||||
/* +#+#+#+#+#+ +#+ */
|
/* +#+#+#+#+#+ +#+ */
|
||||||
/* Created: 2025/02/03 17:28:31 by mmoussou #+# #+# */
|
/* Created: 2025/02/03 17:28:31 by mmoussou #+# #+# */
|
||||||
/* Updated: 2025/03/17 14:13:13 by mmoussou ### ########.fr */
|
/* Updated: 2025/03/19 02:05:31 by mmoussou ### ########.fr */
|
||||||
/* */
|
/* */
|
||||||
/* ************************************************************************** */
|
/* ************************************************************************** */
|
||||||
|
|
||||||
#include <requests/HttpResponse.hpp>
|
#include <requests/HttpResponse.hpp>
|
||||||
|
#include <requests/Errors.hpp>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
- do a map of all the status_text and get it from here, not storing them
|
- do a map of all the status_text and get it from here, not storing them
|
||||||
@ -66,9 +67,5 @@ void http::Response::setProtocol(std::string const protocol)
|
|||||||
void http::Response::setStatusCode(size_t const status_code)
|
void http::Response::setStatusCode(size_t const status_code)
|
||||||
{
|
{
|
||||||
this->_status_code = status_code;
|
this->_status_code = status_code;
|
||||||
}
|
this->_status_text = Errors::message[status_code];
|
||||||
|
|
||||||
void http::Response::setStatusText(std::string const status_text)
|
|
||||||
{
|
|
||||||
this->_status_text = status_text;
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user