Skip to content

Commit ce0a4ea

Browse files
feat: implementing default error pages and considering error pages provided in config file
1 parent 0d9749a commit ce0a4ea

File tree

2 files changed

+58
-4
lines changed

2 files changed

+58
-4
lines changed

src/http/http_response.cpp

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
#include "http/http_response.hpp"
22

3+
#include "config/server_config.hpp"
4+
#include "fcntl.h"
5+
#include "sys/stat.h"
6+
#include "unistd.h"
7+
38
#include <cstdlib>
9+
#include <map>
410
#include <sstream>
511

612
// TODO(isma): Maybe make a proper constructor for this class?
@@ -106,13 +112,61 @@ std::string HttpResponse::to_string() const
106112
return out.str();
107113
}
108114

109-
HttpResponse HttpResponse::make_error(HttpResponse::Status status)
115+
bool file_readable(const std::string& path)
116+
{
117+
struct stat sb;
118+
return (stat(path.c_str(), &sb) == 0 && S_ISREG(sb.st_mode));
119+
}
120+
121+
bool read_error_page(const std::string& path, std::string& body)
122+
{
123+
if (!file_readable(path)) {
124+
return false;
125+
}
126+
127+
int fd;
128+
char buf[4096];
129+
int bytes = 1;
130+
fd = open(path.c_str(), O_RDONLY);
131+
if (fd == -1) {
132+
return false;
133+
}
134+
135+
while (bytes) {
136+
size_t bytes = read(fd, buf, sizeof(buf));
137+
if (bytes == 0) {
138+
break;
139+
}
140+
if (bytes < 0) {
141+
close(fd);
142+
return false;
143+
}
144+
body.append(buf, bytes);
145+
}
146+
close(fd);
147+
return true;
148+
}
149+
150+
HttpResponse HttpResponse::make_error(HttpResponse::Status status, const SharedConfig& cfg)
110151
{
111152
HttpResponse res(WEBSERV_DEFAULT_HTTP_VERSION);
112153
res.code = status;
113154
res.content_type = "text/html; charset=UTF-8";
114-
std::ostringstream oss;
115-
oss << static_cast<int>(status) << " " << HttpResponse::reason_phrase(status);
155+
std::map<HttpResponse::Status, std::string>::const_iterator it = cfg.error_pages.find(status);
156+
if (it != cfg.error_pages.end()) {
157+
std::string path = cfg.document_root + it->second;
158+
std::string body;
159+
if (read_error_page(path, body)) {
160+
res.inline_body = body;
161+
return res;
162+
}
163+
}
164+
int code = static_cast<int>(status);
165+
std::ostringstream oss; // send a minimal default html body containing the error status code
166+
oss << "<!doctype html><html><head><meta charset=\"utf-8\">"
167+
"<title>"
168+
<< code << " " << HttpResponse::reason_phrase(status) << "</title></head><body><h1>" << code
169+
<< " " << HttpResponse::reason_phrase(status) << "</h1></body></html>";
116170
res.inline_body = oss.str();
117171
return res;
118172
}

src/http/http_response.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ struct HttpResponse {
2828

2929
explicit HttpResponse(HttpVersion protocol = WEBSERV_DEFAULT_HTTP_VERSION);
3030
static Status status_from_int(int code);
31-
static HttpResponse make_error(HttpResponse::Status status);
31+
static HttpResponse make_error(HttpResponse::Status status, const SharedConfig& cfg);
3232
HttpVersion http_version;
3333
HttpResponse::Status code;
3434

0 commit comments

Comments
 (0)