Skip to content

Commit

Permalink
Merge remote-tracking branch 'upstream/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
Winston HAYTER committed Nov 1, 2021
2 parents 60c18d8 + 86796b5 commit 3ffddd0
Show file tree
Hide file tree
Showing 17 changed files with 359 additions and 17 deletions.
26 changes: 26 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,3 +213,29 @@ https://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html

##### other
- https://stackoverflow.com/questions/59261547/handle-ctrlc-in-client-server-socket-in-c-programing


### cgi
- https://helpx.adobe.com/coldfusion/cfml-reference/reserved-words-and-variables/cgi-environment-cgi-scope-variables/cgi-server-variables.html
- http://www.faqs.org/rfcs/rfc3875.html
- https://www.php.net/manual/fr/reserved.variables.server.php

#### multipart
- https://stackoverflow.com/questions/913626/what-should-a-multipart-http-request-with-multiple-files-look-like
- https://www.w3.org/Protocols/rfc1341/7_2_Multipart.html
- https://developer.mozilla.org/fr/docs/Web/HTML/Element/Input/file
- https://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.2

#### reactor and c10k problem
- https://dzone.com/articles/understanding-reactor-pattern-thread-based-and-eve
- http://www.kegel.com/c10k.html
- https://hila.sh/2019/12/28/reactor.html
- https://raw.githubusercontent.com/swn73/books/master/Packt.Nginx.HTTP.Server.3rd.Edition.pdf
- https://www.adamtornhill.com/Patterns%20in%20C%205,%20REACTOR.pdf

#### nginx
- https://raw.githubusercontent.com/swn73/books/master/Packt.Nginx.HTTP.Server.3rd.Edition.pdf

#### http header value ',' (list syntax) vs ';'
- https://stackoverflow.com/a/38406581/5374043
- https://github.com/bnoordhuis/mozilla-central/blob/master/netwerk/protocol/http/nsHttpHeaderArray.h#L185
2 changes: 1 addition & 1 deletion config_file_doc.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Default: —
Context: main
https://nginx.org/en/docs/http/ngx_http_core_module.html#server

Syntax: **listen** address[:port]; (this syntax is not invalid, remove the host/address)
Syntax: **listen** address[:port];
**listen** port;
Default: listen *:80;
Context: server
Expand Down
2 changes: 1 addition & 1 deletion includes/cgi/cgi.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ void setEnvironment(http::Request& request, ServerBlock& sblock, fs::path path)
setenv("GATEWAY_INTERFACE", "CGI/1.1", 0);
setenv("SERVER_NAME", sblock.getServerName().c_str(), 0);
setenv("SERVER_SOFTWARE", "webserv/1.0", 0);
setenv("SERVER_PROTOCOL", "http/1.1", 0);
setenv("SERVER_PROTOCOL", "HTTP/1.1", 0);
setenv("HTTP_ACCEPT", request.getHeader("Accept").c_str(), 0);
setenv("HTTP_ACCEPT_CHARSET", request.getHeader("Accept-Charset").c_str(), 0);
setenv("HTTP_ACCEPT_ENCODING", request.getHeader("Accept-Encoding").c_str(), 0);
Expand Down
4 changes: 3 additions & 1 deletion includes/ft/utility.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,13 @@ bool isInteger(std::string& s);
std::string getDate();
std::string trim(const std::string& str,
const std::string& whitespace = " \t");

std::vector<std::string> split(const std::string& str, char delim);

/// return the number of consecutives same elements in two paths.
bool pathsComponentsAreEqual(const filesystem::path& one, const filesystem::path& two, size_t& nSameComp);

bool isValidIpAddress(char *ipAddress);

} /* namespace ft */

#endif
8 changes: 6 additions & 2 deletions includes/http/Status.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,9 @@ struct Status {
void setValue(StatusEnum e);
void setValue(int e);

int getValue();
int getValue() const;

std::string getDefinition();
std::string getDefinition() const;

friend bool operator==(const Status& lhs, const Status& rhs)
{
Expand Down Expand Up @@ -128,6 +128,10 @@ bool isClientError(Status statusCode);
bool isServerError(Status statusCode);
bool isError(Status statusCode);

std::ostream& operator<<(std::ostream& os, const Status& s);
std::ostream& operator<<(std::ostream& os, const Status::StatusEnum& s);


} /* namespace http */

#endif /* STATUS_HPP */
13 changes: 13 additions & 0 deletions includes/http/messageParser.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,19 @@ namespace http {
bool parseRequest(Request &request, Status &error, content_type &buffer);
Message parseCgiResponse(content_type &buffer);

struct multipart_part
{
std::map<std::string, std::string> headers;
unsigned char *content;
size_t len;

std::string getFilename() const;
};

http::Status parseContentMultipart(std::vector<multipart_part>& result,
http::Request& request, const std::string& boundary);


} /* namespace http */

#endif /* MESSAGE_PARSER_HPP */
25 changes: 23 additions & 2 deletions src/config/ServerConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -544,15 +544,36 @@ bool ServerConfig::_parseAutoindex(config::ScannerConfig & scanner)
return false;
}


Host ServerConfig::_parseListenValue(const pr::Token& t)
{
Host result;
unsigned long port;

std::string tmp;

std::string::const_iterator it = t.value.begin();
std::string::const_iterator end = t.value.end();

while(it != end && *it != ':')
tmp += *it++;

if (it == end)
{
it = tmp.begin();
end = tmp.end();
}
else
{
ft::lowerStringInPlace(tmp);
result.setHostname(tmp);
it++;
tmp.clear();
while (it != end)
tmp += *it++;
}
char *nptr;
errno = 0;
port = strtoul(t.value.c_str(), &nptr, 10);
port = strtoul(tmp.c_str(), &nptr, 10);
if (port == ULONG_MAX && ft::make_error_code().value() == ft::errc::result_out_of_range)
_throw_SyntaxError(t, std::string("Overflow in context \"listen\"... thx bro --'"));
if (nptr[0])
Expand Down
28 changes: 28 additions & 0 deletions src/ft/utility.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@
#include "ft/utility.hpp"
#include <algorithm>

#include <netinet/in.h>
#include <arpa/inet.h>

namespace ft {

std::string intToString(int i)
Expand Down Expand Up @@ -75,6 +78,24 @@ std::string trim(const std::string& str,
return str.substr(strBegin, strRange);
}

std::vector<std::string> split(const std::string& str, char delim)
{
std::vector<std::string> result;

std::string tmp = "";
for(size_t i = 0; i< str.length(); ++i)
{
if (str[i] == delim)
{
result.push_back(tmp);
tmp.clear();
}
else
tmp.push_back(str[i]);
}
result.push_back(tmp);
return result;
}

// Return true if both paths are equal, else false and tell how many comp are the same by variable nSameComp
bool pathsComponentsAreEqual(const filesystem::path& one, const filesystem::path& two, size_t& nSameComp)
Expand All @@ -99,4 +120,11 @@ bool pathsComponentsAreEqual(const filesystem::path& one, const filesystem::path
return true;
}

bool isValidIpAddress(char *ipAddress)
{
struct sockaddr_in sa;
int result = ::inet_pton(AF_INET, ipAddress, &(sa.sin_addr));
return result > 0;
}

} /* namespace ft */
22 changes: 19 additions & 3 deletions src/http/Status.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
/* ************************************************************************** */

#include "Status.hpp"
#include "utility.hpp"

namespace http {

Expand Down Expand Up @@ -38,15 +39,16 @@ void Status::setValue(int e)
_e = static_cast<StatusEnum>(e);
}

int Status::getValue()
int Status::getValue() const
{
return _e;
}

std::string Status::getDefinition()
std::string Status::getDefinition() const
{
switch (getValue())
{
case 0: return "None";
case 100: return "Continue";
case 101: return "Switching Protocols";
case 102: return "Processing";
Expand Down Expand Up @@ -107,7 +109,9 @@ std::string Status::getDefinition()
case 508: return "Loop Detected";
case 510: return "Not Extended";
case 511: return "Network Authentication Required";
default: return "Unknown status code";

case 999: return "endOfInput";
default: return std::string("Unknown code: ") + ft::intToString(getValue());
}
}

Expand Down Expand Up @@ -141,4 +145,16 @@ bool isError(Status statusCode)
return (statusCode >= 400);
}

std::ostream& operator<<(std::ostream& os, const Status& s)
{
os << s.getDefinition();
return os;
}

std::ostream& operator<<(std::ostream& os, const Status::StatusEnum& s)
{
os << Status(s).getDefinition();
return os;
}

} /* namespace http */
42 changes: 42 additions & 0 deletions src/http/messageBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,54 @@
#include "messageParser.hpp"
#include "messageBuilder.hpp"
#include "cgi.hpp"
#include "utility.hpp"
#include "HtmlBuilder.hpp"

#include <fstream>

namespace fs = ft::filesystem;

namespace http {

static void writeContentToFile(const fs::path& path, const char *content, size_t n)
{
std::ofstream file;
file.open(path.c_str(), std::ofstream::binary);
file.write(content, n);
file.close();
}

Response postMultipart(const Context& ctxt, Request& request, Response& response)
{
if (ctxt.server.getUploadStore().empty())
return errorResponse(ctxt, response, Status::Forbidden);
std::vector<std::string> vec = ft::split(request.getHeader("Content-Type"), ';');

std::string contentType = vec.size() > 0 ? ft::trim(vec[0]) : "";
if (contentType != "multipart/form-data" || vec.size() != 2)
return errorResponse(ctxt, response, Status::NotImplemented);
std::string boundary = ft::trim(vec[1]);

vec = ft::split(boundary, '=');
if (vec.size() != 2 || vec[0] != "boundary")
return errorResponse(ctxt, response, Status::BadRequest); // bad request ???
boundary = vec[1];

std::vector<multipart_part> parts;
http::Status error = parseContentMultipart(parts, request, boundary);
if (error != Status::None)
return errorResponse(ctxt, response, error);
std::vector<multipart_part>::iterator it = parts.begin();
while (it != parts.end())
{
writeContentToFile(ctxt.server.getUploadStore() / it->getFilename(), reinterpret_cast<char*>(it->content), it->len);
++it;
}
response.setStatus(http::Status::Created);

return response;
}


Response buildResponse(Request& request)
{
Expand Down Expand Up @@ -56,6 +97,7 @@ Response getMethodResponse(const Context& ctxt, Request& request, Response& resp

Response postMethodResponse(const Context& ctxt, Request& request, Response& response)
{
return postMultipart(ctxt, request, response); // just to test
if (postContent(ctxt.path, request.getContent()) < 0)
return (errorResponse(ctxt, response, Status::InternalServerError));
response.setStatus(Status::Created);
Expand Down
Loading

0 comments on commit 3ffddd0

Please sign in to comment.