Skip to content

Commit

Permalink
Merge branch 'main' of github.com:samih713/webserv into main
Browse files Browse the repository at this point in the history
  • Loading branch information
samih713 committed Jun 7, 2024
2 parents da7f895 + adec62b commit 7b7ba6c
Show file tree
Hide file tree
Showing 6 changed files with 114 additions and 43 deletions.
22 changes: 21 additions & 1 deletion .resources/html/file_upload_test.html
Original file line number Diff line number Diff line change
Expand Up @@ -112,11 +112,31 @@
<div class="card">
<h1 class="title">File Upload Test Page</h1>
<p>This is the page for testing file uploads.</p>
<form action="/upload" method="POST" enctype="multipart/form-data">
<form id="uploadForm" action="/upload" method="POST" enctype="multipart/form-data">
<input type="file" name="file" required>
<input type="submit" value="Upload">
</form>
</div>
<script>
document.getElementById('uploadForm').addEventListener('submit', function(event) {
event.preventDefault(); // Prevent the default form submission

var formData = new FormData(this);

fetch('/upload', {
method: 'POST',
body: formData
}).then(response => {
if (response.ok) {
alert('Upload successful!');
} else {
alert('Upload failed. Please try again.');
}
}).catch(error => {
alert('An error occurred. Please try again.');
});
});
</script>
</div>
</body>
</html>
1 change: 0 additions & 1 deletion .resources/html/post_request_test.html
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,6 @@ <h1>POST Test Page</h1>
<p>This is the page for testing POST requests.</p>
<form action="/sample_pages/test.txt" method="POST">
<input type="text" name="username" placeholder="Username" required>
<input type="email" name="email" placeholder="Email" required>
<input type="text" name="message" placeholder="Message" required>
<input type="submit" value="Submit">
</form>
Expand Down
128 changes: 91 additions & 37 deletions sources/http/handler/PostRequestHandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,75 +4,129 @@
Response PostRequestHandler::handle_request(const Request& r)
{
LOG_DEBUG("Handling POST request for resource: " + r.get_resource());

// TODO need to check if the body is exceeding max body size
// TODO need to check type of content

status = r.get_status();
_add_header("Server", cfg.serverName);

status = r.get_status();
vector<char> body = process_data(r);
return Response(status, responseHeaders, body);
}

vector<char> PostRequestHandler::process_data(const Request& r)
{
// 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();

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

vector<char> responseBody;
// for uploads, check if the location block allows uploads
if (!locationMatch.empty() && locationMatch == "/upload") {
// handle_upload();
responseBody = handle_upload(r, cfg.locations.at("/upload").root);
_add_header("Content-Length", ws_itoa(responseBody.size()));
return responseBody;
}

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

if (resourcePath.find("/cgi-bin") != string::npos) { //! cgi check again
else if (!locationMatch.empty() && locationMatch == "/cgi-bin") {
CGI cgi(r, cfg, *cp);
responseBody = cgi.execute(r.cgiStatus, r.cgiReadFd, r.cgiChild);
// _add_header("Content-Length", ws_itoa(responseBody.size()));
_add_header("Content-Length", ws_itoa(responseBody.size()));
return responseBody;
}

struct stat fileInfo;
stat(resourcePath.c_str(), &fileInfo);
if (S_ISDIR(fileInfo.st_mode))
return make_error_body(NOT_IMPLEMENTED);
else if (find_resource_type(r.get_resource()).length() == 0)
return make_error_body(UNSUPPORTED_MEDIA_TYPE);

// append to 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)
if (!parse_request_body(requestBody))
return make_error_body(BAD_REQUEST);

outputFile << requestBody;
outputFile.close();

status = OK;
return responseBody;
}

bool PostRequestHandler::parse_request_body(const string& body)
vector<char> PostRequestHandler::handle_upload(const Request& r, const string& dirPath)
{
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;
HeaderMap::const_iterator itr = r.get_headers().find("content-type");
if (itr == r.get_headers().end())
return make_error_body(BAD_REQUEST);

string contentType = itr->second;
// Find the boundary parameter
size_t boundaryPos = contentType.find("boundary=");
if (boundaryPos == string::npos)
return make_error_body(BAD_REQUEST);

// Extract the boundary value (9 is the length of "boundary=")
string boundary = contentType.substr(boundaryPos + 9);
if (boundary.empty())
return make_error_body(BAD_REQUEST);

// Add the -- prefix to the boundary
string boundaryDelimiter = "--" + boundary;
string endBoundaryDelimiter = boundaryDelimiter + "--";

// Get the body of the request
string body = r.get_body();

// Find the start of the first part
size_t startPos = body.find(boundaryDelimiter);
if (startPos == string::npos)
return make_error_body(BAD_REQUEST);
// Move past the boundary delimiter and the following CRLF
startPos += boundaryDelimiter.length() + 2;

// Find the end of the first part
size_t endPos = body.find(boundaryDelimiter, startPos);
if (endPos == string::npos)
return make_error_body(BAD_REQUEST);

// Extract the headers and content of the part
string part = body.substr(startPos, endPos - startPos);

// Find the end of the headers (CRLF CRLF)
size_t headerEndPos = part.find("\r\n\r\n");
if (headerEndPos == string::npos)
return make_error_body(BAD_REQUEST);

// Extract the headers and content
string bodyHeaders = part.substr(0, headerEndPos);
string fileContent = part.substr(headerEndPos + 4); // Move past the CRLF CRLF

// Find the filename in the headers
size_t filenamePos = bodyHeaders.find("filename=\"");
if (filenamePos == string::npos)
return make_error_body(BAD_REQUEST);
filenamePos += 10; // Move past 'filename="'
size_t filenameEndPos = bodyHeaders.find("\"", filenamePos);
if (filenameEndPos == string::npos)
return make_error_body(BAD_REQUEST);
string fileName = bodyHeaders.substr(filenamePos, filenameEndPos - filenamePos);
fileName = dirPath + "/" + fileName;

// Ensure the upload directory exists
struct stat st;
if (stat(dirPath.c_str(), &st) != 0) {
if (mkdir(dirPath.c_str(), 0700) != 0) {
return make_error_body(INTERNAL_SERVER_ERROR);
}
} else if (!S_ISDIR(st.st_mode)) {
return make_error_body(INTERNAL_SERVER_ERROR);
}
return true;
}

void handle_upload()
{
// ...
ofstream outputFile(fileName.c_str(), std::ios_base::binary);
if (outputFile.fail())
return make_error_body(INTERNAL_SERVER_ERROR);

outputFile.write(fileContent.c_str(), fileContent.size());
outputFile.close();

status = CREATED;
return vector<char>();
}
2 changes: 1 addition & 1 deletion sources/http/handler/PostRequestHandler.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ class PostRequestHandler: public RequestHandlerBase {

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

#endif // POST_REQUEST_HANDLER_HPP
2 changes: 1 addition & 1 deletion sources/http/request/process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,6 @@ void Request::apply_config(const ServerConfig& cfg)
resourcePath = root + uri;

if (header.bodySize > maxBodySize)
status = PAYLOAD_TOO_LARGE; //!
set_status(PAYLOAD_TOO_LARGE);
header.bodySize = std::min(header.bodySize, maxBodySize);
}
2 changes: 0 additions & 2 deletions sources/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ int main(int argc, char** argv)
vector<ServerConfig> servers = parser.parse();
LOG_INFO("Parsing " + configFile);

// for (size_t i = 0; i < servers.size(); i++)
// servers[i].print();
Server& webserv = Server::get_instance(servers, 100);
#if defined(__LINUX__)
webserv.start(SELECT);
Expand Down

0 comments on commit 7b7ba6c

Please sign in to comment.