Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f7b31c7db7 | ||
|
|
5225e3258b | ||
|
|
469eca8aa9 | ||
|
|
9b0fcc1520 | ||
|
|
dda0103fb8 | ||
|
|
3d17db996a | ||
|
|
a008c12058 | ||
|
|
6694ffeb66 | ||
|
|
3530595b01 | ||
|
|
b34e49311b | ||
|
|
2613ca2e1a | ||
|
|
e537e9bb78 | ||
|
|
3763249a3e | ||
|
|
366178303f | ||
|
|
df24de46c7 |
25
Makefile
25
Makefile
@@ -1,14 +1,13 @@
|
|||||||
|
|
||||||
NAME = webserv
|
NAME = webserv
|
||||||
CXX = c++
|
CXX = clang++
|
||||||
|
|
||||||
CXXFLAGS = -Wall -Wextra #-Werror
|
CXXFLAGS = -Wall -Wextra -Werror
|
||||||
CXXFLAGS += $(HEADERS_D:%=-I%)
|
CXXFLAGS += $(HEADERS_D:%=-I%)
|
||||||
CXXFLAGS += -std=c++98
|
CXXFLAGS += -std=c++98
|
||||||
CXXFLAGS += -g
|
CXXFLAGS += -g
|
||||||
#CXXFLAGS += -fno-limit-debug-info
|
CXXFLAGS += -MMD -MP # header dependencie
|
||||||
CXXFLAGS += -MMD -MP #header dependencie
|
# for debug
|
||||||
#CXXFLAGS += -O3
|
|
||||||
|
|
||||||
VPATH = $(SRCS_D)
|
VPATH = $(SRCS_D)
|
||||||
|
|
||||||
@@ -25,11 +24,9 @@ SRCS = main.cpp \
|
|||||||
accept.cpp request.cpp response.cpp \
|
accept.cpp request.cpp response.cpp \
|
||||||
method_get.cpp method_post.cpp method_delete.cpp \
|
method_get.cpp method_post.cpp method_delete.cpp \
|
||||||
run_loop.cpp timeout.cpp \
|
run_loop.cpp timeout.cpp \
|
||||||
parser.cpp \
|
parser.cpp extraConfig.cpp postProcessing.cpp \
|
||||||
extraConfig.cpp \
|
|
||||||
postProcessing.cpp \
|
|
||||||
utils.cpp \
|
utils.cpp \
|
||||||
cgi.cpp \
|
cgi.cpp cgi_epoll.cpp \
|
||||||
Client.cpp Client_multipart_body.cpp \
|
Client.cpp Client_multipart_body.cpp \
|
||||||
|
|
||||||
OBJS_D = builds
|
OBJS_D = builds
|
||||||
@@ -46,14 +43,16 @@ DEPS = $(OBJS:.o=.d) #header dependencie
|
|||||||
all: $(NAME)
|
all: $(NAME)
|
||||||
|
|
||||||
$(OBJS_D)/%.o: %.cpp | $(OBJS_D)
|
$(OBJS_D)/%.o: %.cpp | $(OBJS_D)
|
||||||
$(CXX) $(CXXFLAGS) -c $< -o $@
|
$(CXX) -c $< -o $@ $(CXXFLAGS)
|
||||||
printf "$(_CYAN)\r\33[2K\rCompling $@$(_END)"
|
printf "$(_CYAN)\r\33[2K\rCompling $@$(_END)"
|
||||||
|
|
||||||
$(OBJS_D):
|
$(OBJS_D):
|
||||||
mkdir $@
|
mkdir $@
|
||||||
|
|
||||||
$(NAME): $(OBJS)
|
$(NAME): $(OBJS)
|
||||||
$(CXX) $^ -o $(NAME)
|
# $(CXX) $^ -o $(NAME)
|
||||||
|
# add -lpthread for semaphore library
|
||||||
|
$(CXX) $^ -o $(NAME) -lpthread
|
||||||
echo "$(_GREEN)\r\33[2K\r$(NAME) created 😎$(_END)"
|
echo "$(_GREEN)\r\33[2K\r$(NAME) created 😎$(_END)"
|
||||||
|
|
||||||
# CGI
|
# CGI
|
||||||
@@ -68,11 +67,11 @@ cgire:
|
|||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -rf $(OBJS_D)
|
rm -rf $(OBJS_D)
|
||||||
echo "$(_RED).o Files Deleted 😱$(_END)"
|
echo "$(_CYAN).o Files Deleted 🤫$(_END)"
|
||||||
|
|
||||||
fclean: clean
|
fclean: clean
|
||||||
rm -f $(NAME)
|
rm -f $(NAME)
|
||||||
echo "$(_RED)$(NAME) Deleted 😱$(_END)"
|
echo "$(_CYAN)$(NAME) Deleted 🤫$(_END)"
|
||||||
|
|
||||||
re: fclean all
|
re: fclean all
|
||||||
|
|
||||||
|
|||||||
29
Tester/expected_results/expected_delete_test.txt
Normal file
29
Tester/expected_results/expected_delete_test.txt
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
telnet> Trying 127.0.0.1...
|
||||||
|
Connected to localhost.
|
||||||
|
Escape character is '^]'.
|
||||||
|
HTTP/1.1 405 Method Not Allowed
|
||||||
|
Allow: GET
|
||||||
|
Content-Type: text/html; charset=UTF-8
|
||||||
|
Content-Length: 199
|
||||||
|
|
||||||
|
<!DOCTYPE html><html><head><title>405 Method Not Allowed</title></head><body><h1 style="text-align:center">405 Method Not Allowed</h1><hr><p style="text-align:center">Le Webserv/0.1</p></body></html>HTTP/1.1 204 No Content
|
||||||
|
Server: Webserv/0.1
|
||||||
|
Connection: keep-alive
|
||||||
|
|
||||||
|
HTTP/1.1 404 Not Found
|
||||||
|
Server: Webserv/0.1
|
||||||
|
Connection: keep-alive
|
||||||
|
Content-Type: text/html; charset=UTF-8
|
||||||
|
Content-Length: 210
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>404 Not Found</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1 style="text-align:center">Check it UP 404 Not Found</h1>
|
||||||
|
<hr>
|
||||||
|
<p style=\"text-align:center\">Le Webserv/0.1</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
15
Tester/expected_results/expected_header_test.txt
Normal file
15
Tester/expected_results/expected_header_test.txt
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
telnet> Trying 127.0.0.1...
|
||||||
|
Connected to localhost.
|
||||||
|
Escape character is '^]'.
|
||||||
|
HTTP/1.1 501 Not Implemented
|
||||||
|
Server: Webserv/0.1
|
||||||
|
Connection: keep-alive
|
||||||
|
Content-Type: text/html; charset=UTF-8
|
||||||
|
Content-Length: 193
|
||||||
|
|
||||||
|
<!DOCTYPE html><html><head><title>501 Not Implemented</title></head><body><h1 style="text-align:center">501 Not Implemented</h1><hr><p style="text-align:center">Le Webserv/0.1</p></body></html>HTTP/1.1 415 Unsupported Media Type
|
||||||
|
Accept-Encoding:
|
||||||
|
Content-Type: text/html; charset=UTF-8
|
||||||
|
Content-Length: 207
|
||||||
|
|
||||||
|
<!DOCTYPE html><html><head><title>415 Unsupported Media Type</title></head><body><h1 style="text-align:center">415 Unsupported Media Type</h1><hr><p style="text-align:center">Le Webserv/0.1</p></body></html>
|
||||||
37
Tester/expected_results/expected_method_test.txt
Normal file
37
Tester/expected_results/expected_method_test.txt
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
telnet> Trying 127.0.0.1...
|
||||||
|
Connected to localhost.
|
||||||
|
Escape character is '^]'.
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Server: Webserv/0.1
|
||||||
|
Connection: keep-alive
|
||||||
|
Content-Type: text/html; charset=UTF-8
|
||||||
|
Content-Length: 193
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Le Webserv</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1 style="text-align:center">Le index (˘ ͜ʖ˘)</h1>
|
||||||
|
<hr>
|
||||||
|
<p style="text-align:center">(˚3˚)</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
HTTP/1.1 405 Method Not Allowed
|
||||||
|
Allow: GET
|
||||||
|
Content-Type: text/html; charset=UTF-8
|
||||||
|
Content-Length: 199
|
||||||
|
|
||||||
|
<!DOCTYPE html><html><head><title>405 Method Not Allowed</title></head><body><h1 style="text-align:center">405 Method Not Allowed</h1><hr><p style="text-align:center">Le Webserv/0.1</p></body></html>HTTP/1.1 405 Method Not Allowed
|
||||||
|
Allow: GET
|
||||||
|
Content-Type: text/html; charset=UTF-8
|
||||||
|
Content-Length: 199
|
||||||
|
|
||||||
|
<!DOCTYPE html><html><head><title>405 Method Not Allowed</title></head><body><h1 style="text-align:center">405 Method Not Allowed</h1><hr><p style="text-align:center">Le Webserv/0.1</p></body></html>HTTP/1.1 501 Not Implemented
|
||||||
|
Server: Webserv/0.1
|
||||||
|
Connection: keep-alive
|
||||||
|
Content-Type: text/html; charset=UTF-8
|
||||||
|
Content-Length: 193
|
||||||
|
|
||||||
|
<!DOCTYPE html><html><head><title>501 Not Implemented</title></head><body><h1 style="text-align:center">501 Not Implemented</h1><hr><p style="text-align:center">Le Webserv/0.1</p></body></html>
|
||||||
@@ -22,15 +22,13 @@ HTTP/1.1 200 OK
|
|||||||
Server: Webserv/0.1
|
Server: Webserv/0.1
|
||||||
Connection: keep-alive
|
Connection: keep-alive
|
||||||
Content-Type: text/html; charset=UTF-8
|
Content-Type: text/html; charset=UTF-8
|
||||||
Content-Length: 290
|
Content-Length: 227
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Webserv test index</title>
|
<title>Webserv test index</title>
|
||||||
<!-- <link rel="stylesheet" href="stylesheet/style.css"> -->
|
|
||||||
<link rel="stylesheet" href="/stylesheet/style.css">
|
<link rel="stylesheet" href="/stylesheet/style.css">
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Webserv Test Index</h1>
|
<h1>Webserv Test Index</h1>
|
||||||
@@ -42,15 +40,13 @@ HTTP/1.1 200 OK
|
|||||||
Server: Webserv/0.1
|
Server: Webserv/0.1
|
||||||
Connection: keep-alive
|
Connection: keep-alive
|
||||||
Content-Type: text/html; charset=UTF-8
|
Content-Type: text/html; charset=UTF-8
|
||||||
Content-Length: 290
|
Content-Length: 227
|
||||||
|
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
<title>Webserv test index</title>
|
<title>Webserv test index</title>
|
||||||
<!-- <link rel="stylesheet" href="stylesheet/style.css"> -->
|
|
||||||
<link rel="stylesheet" href="/stylesheet/style.css">
|
<link rel="stylesheet" href="/stylesheet/style.css">
|
||||||
|
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<h1>Webserv Test Index</h1>
|
<h1>Webserv Test Index</h1>
|
||||||
@@ -58,13 +54,13 @@ Content-Length: 290
|
|||||||
<p style="text-align:center">(˚3˚)</p>
|
<p style="text-align:center">(˚3˚)</p>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
HTTP/1.1
|
HTTP/1.1 200 OK
|
||||||
Server: Webserv/0.1
|
Server: Webserv/0.1
|
||||||
Connection: keep-alive
|
Connection: keep-alive
|
||||||
Content-Type: text/html; charset=UTF-8
|
Content-Type: text/html; charset=UTF-8
|
||||||
Content-Length: 1277
|
Content-Length: 1281
|
||||||
|
|
||||||
<!DOCTYPE html><html><head><title>Index of ./Tester/www/</title></head><body><h1>Index of ./Tester/www/</h1><hr><pre><a style="font-size:1.5em" href="/list/..">..</a>
|
<!DOCTYPE html><html><head><title>Index of ./Tester/www/</title></head><body><h1>Index of ./Tester/www/</h1><hr><pre><a style="font-size:1.5em" href="/list/..">../</a>
|
||||||
<a style="font-size:1.5em" href="/list/upload_form.html">upload_form.html</a>
|
<a style="font-size:1.5em" href="/list/upload_form.html">upload_form.html</a>
|
||||||
<a style="font-size:1.5em" href="/list/form_get.html">form_get.html</a>
|
<a style="font-size:1.5em" href="/list/form_get.html">form_get.html</a>
|
||||||
<a style="font-size:1.5em" href="/list/kermit.ico">kermit.ico</a>
|
<a style="font-size:1.5em" href="/list/kermit.ico">kermit.ico</a>
|
||||||
@@ -72,14 +68,14 @@ Content-Length: 1277
|
|||||||
<a style="font-size:1.5em" href="/list/Cagneyc_intro.gif">Cagneyc_intro.gif</a>
|
<a style="font-size:1.5em" href="/list/Cagneyc_intro.gif">Cagneyc_intro.gif</a>
|
||||||
<a style="font-size:1.5em" href="/list/Van_Eyck_Portrait_Arnolfini.jpg">Van_Eyck_Portrait_Arnolfini.jpg</a>
|
<a style="font-size:1.5em" href="/list/Van_Eyck_Portrait_Arnolfini.jpg">Van_Eyck_Portrait_Arnolfini.jpg</a>
|
||||||
<a style="font-size:1.5em" href="/list/root.png">root.png</a>
|
<a style="font-size:1.5em" href="/list/root.png">root.png</a>
|
||||||
<a style="font-size:1.5em" href="/list/test">test</a>
|
<a style="font-size:1.5em" href="/list/test">test/</a>
|
||||||
<a style="font-size:1.5em" href="/list/drill.jpg">drill.jpg</a>
|
<a style="font-size:1.5em" href="/list/drill.jpg">drill.jpg</a>
|
||||||
<a style="font-size:1.5em" href="/list/punpun.png">punpun.png</a>
|
<a style="font-size:1.5em" href="/list/punpun.png">punpun.png</a>
|
||||||
<a style="font-size:1.5em" href="/list/favicon.ico">favicon.ico</a>
|
<a style="font-size:1.5em" href="/list/favicon.ico">favicon.ico</a>
|
||||||
<a style="font-size:1.5em" href="/list/index.html">index.html</a>
|
<a style="font-size:1.5em" href="/list/index.html">index.html</a>
|
||||||
<a style="font-size:1.5em" href="/list/rfc2119.html">rfc2119.html</a>
|
<a style="font-size:1.5em" href="/list/rfc2119.html">rfc2119.html</a>
|
||||||
<a style="font-size:1.5em" href="/list/error_pages">error_pages</a>
|
<a style="font-size:1.5em" href="/list/error_pages">error_pages/</a>
|
||||||
<a style="font-size:1.5em" href="/list/rfc2119_files">rfc2119_files</a>
|
<a style="font-size:1.5em" href="/list/rfc2119_files">rfc2119_files/</a>
|
||||||
</pre><hr></body></html>HTTP/1.1 404 Not Found
|
</pre><hr></body></html>HTTP/1.1 404 Not Found
|
||||||
Server: Webserv/0.1
|
Server: Webserv/0.1
|
||||||
Connection: keep-alive
|
Connection: keep-alive
|
||||||
|
|||||||
110
Tester/expected_results/expected_valid_uri_test.txt
Normal file
110
Tester/expected_results/expected_valid_uri_test.txt
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
telnet> Trying 127.0.0.1...
|
||||||
|
Connected to localhost.
|
||||||
|
Escape character is '^]'.
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Server: Webserv/0.1
|
||||||
|
Connection: keep-alive
|
||||||
|
Content-Type: text/html; charset=UTF-8
|
||||||
|
Content-Length: 193
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Le Webserv</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1 style="text-align:center">Le index (˘ ͜ʖ˘)</h1>
|
||||||
|
<hr>
|
||||||
|
<p style="text-align:center">(˚3˚)</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Server: Webserv/0.1
|
||||||
|
Connection: keep-alive
|
||||||
|
Content-Type: text/css; charset=UTF-8
|
||||||
|
Content-Length: 43
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
color: red;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Server: Webserv/0.1
|
||||||
|
Connection: keep-alive
|
||||||
|
Content-Type: text/html; charset=UTF-8
|
||||||
|
Content-Length: 207
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Webserv test Something</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1 style="text-align:center">Webserv Test Something</h1>
|
||||||
|
<hr>
|
||||||
|
<p style="text-align:center">(˚3˚)</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Server: Webserv/0.1
|
||||||
|
Connection: keep-alive
|
||||||
|
Content-Type: text/html; charset=UTF-8
|
||||||
|
Content-Length: 207
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Webserv test Something</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1 style="text-align:center">Webserv Test Something</h1>
|
||||||
|
<hr>
|
||||||
|
<p style="text-align:center">(˚3˚)</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Server: Webserv/0.1
|
||||||
|
Connection: keep-alive
|
||||||
|
Content-Type: text/html; charset=UTF-8
|
||||||
|
Content-Length: 227
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Webserv test index</title>
|
||||||
|
<link rel="stylesheet" href="/stylesheet/style.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Webserv Test Index</h1>
|
||||||
|
<hr>
|
||||||
|
<p style="text-align:center">(˚3˚)</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
HTTP/1.1 200 OK
|
||||||
|
Server: Webserv/0.1
|
||||||
|
Connection: keep-alive
|
||||||
|
Content-Type: text/html; charset=UTF-8
|
||||||
|
Content-Length: 1281
|
||||||
|
|
||||||
|
<!DOCTYPE html><html><head><title>Index of ./Tester/www/</title></head><body><h1>Index of ./Tester/www/</h1><hr><pre><a style="font-size:1.5em" href="/list/..">../</a>
|
||||||
|
<a style="font-size:1.5em" href="/list/upload_form.html">upload_form.html</a>
|
||||||
|
<a style="font-size:1.5em" href="/list/form_get.html">form_get.html</a>
|
||||||
|
<a style="font-size:1.5em" href="/list/kermit.ico">kermit.ico</a>
|
||||||
|
<a style="font-size:1.5em" href="/list/upload_form_single.html">upload_form_single.html</a>
|
||||||
|
<a style="font-size:1.5em" href="/list/Cagneyc_intro.gif">Cagneyc_intro.gif</a>
|
||||||
|
<a style="font-size:1.5em" href="/list/Van_Eyck_Portrait_Arnolfini.jpg">Van_Eyck_Portrait_Arnolfini.jpg</a>
|
||||||
|
<a style="font-size:1.5em" href="/list/root.png">root.png</a>
|
||||||
|
<a style="font-size:1.5em" href="/list/test">test/</a>
|
||||||
|
<a style="font-size:1.5em" href="/list/drill.jpg">drill.jpg</a>
|
||||||
|
<a style="font-size:1.5em" href="/list/punpun.png">punpun.png</a>
|
||||||
|
<a style="font-size:1.5em" href="/list/favicon.ico">favicon.ico</a>
|
||||||
|
<a style="font-size:1.5em" href="/list/index.html">index.html</a>
|
||||||
|
<a style="font-size:1.5em" href="/list/rfc2119.html">rfc2119.html</a>
|
||||||
|
<a style="font-size:1.5em" href="/list/error_pages">error_pages/</a>
|
||||||
|
<a style="font-size:1.5em" href="/list/rfc2119_files">rfc2119_files/</a>
|
||||||
|
</pre><hr></body></html>HTTP/1.1 301 Moved Permanently
|
||||||
|
Location: https://berniesanders.com/404/
|
||||||
|
|
||||||
|
HTTP/1.1 307 Temporary Redirect
|
||||||
|
Location: https://fr.wikipedia.org/wiki/Ketchup
|
||||||
|
|
||||||
@@ -25,6 +25,16 @@ server {
|
|||||||
root ./Tester/www/;
|
root ./Tester/www/;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
location /to_delete.txt {
|
||||||
|
allow_methods GET DELETE;
|
||||||
|
root ./Tester/www/to_delete.txt;
|
||||||
|
}
|
||||||
|
|
||||||
|
location /i_do_not_exist.txt {
|
||||||
|
allow_methods GET DELETE;
|
||||||
|
root ./Tester/www/to_delete.txt;
|
||||||
|
}
|
||||||
|
|
||||||
location /srcs/cgi-bin/ {
|
location /srcs/cgi-bin/ {
|
||||||
root ./srcs/cgi-bin/;
|
root ./srcs/cgi-bin/;
|
||||||
allow_methods POST;
|
allow_methods POST;
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ body+="this is a message this is a message this is a message this is a message t
|
|||||||
#header_cycle=("Content-Length: 17\n" "\n")
|
#header_cycle=("Content-Length: 17\n" "\n")
|
||||||
#header_cycle=("Content-Length: 17\n")
|
#header_cycle=("Content-Length: 17\n")
|
||||||
#header_cycle=()
|
#header_cycle=()
|
||||||
#header+="Content-Length: 8\n"
|
header+="Content-Length: 8\n"
|
||||||
|
|
||||||
run_this_test()
|
run_this_test()
|
||||||
{
|
{
|
||||||
|
|||||||
75
Tester/test_delete.sh
Normal file
75
Tester/test_delete.sh
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
#! /bin/bash
|
||||||
|
|
||||||
|
test_name="Delete Test"
|
||||||
|
|
||||||
|
config_file="./Tester/test1.config"
|
||||||
|
port=4040
|
||||||
|
host="localhost"
|
||||||
|
|
||||||
|
#paths=("/" "/test" "/test/" "/list" "list" "/wrong") # you can add many
|
||||||
|
paths=("/" "/to_delete.txt" "/i_do_not_exist.txt") # you can add many
|
||||||
|
#methods=("GET" "POST" "DELETE")
|
||||||
|
methods=("DELETE")
|
||||||
|
httpz=("HTTP/1.1")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
l1="${methods[0]} ${paths[0]} ${httpz[0]}"
|
||||||
|
|
||||||
|
header="Host: $host"
|
||||||
|
body=
|
||||||
|
|
||||||
|
|
||||||
|
run_this_test()
|
||||||
|
{
|
||||||
|
|
||||||
|
echo "we will delete" > ./Tester/www/to_delete.txt
|
||||||
|
|
||||||
|
for i in "${paths[@]}"
|
||||||
|
do
|
||||||
|
l1="${methods[0]} $i ${httpz[0]}"
|
||||||
|
request="$l1\n$header\n$body\n"
|
||||||
|
{
|
||||||
|
echo "----- $test_name -----"
|
||||||
|
echo -e "$_RED$request$_END"
|
||||||
|
} >> telnet.log
|
||||||
|
echo -e "$request"
|
||||||
|
sleep 1
|
||||||
|
echo -e "\n" >> telnet.log
|
||||||
|
done
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# expected result...
|
||||||
|
|
||||||
|
|
||||||
|
files=()
|
||||||
|
|
||||||
|
file="expected_delete_test.txt"
|
||||||
|
#files+=("expected_path_root_test.txt")
|
||||||
|
#files+=("expected_path_testnoslash_test.txt")
|
||||||
|
#files+=("expected_path_testslash_test.txt")
|
||||||
|
#files+=("expected_path_list_test.txt")
|
||||||
|
#files+=("expected_path_badlist_test.txt")
|
||||||
|
#files+=("expected_path_wrong_test.txt")
|
||||||
|
|
||||||
|
|
||||||
|
#local_expected_test_file=$file
|
||||||
|
local_expected_test_files=()
|
||||||
|
test_path=""
|
||||||
|
|
||||||
|
add_path()
|
||||||
|
{
|
||||||
|
for i in "${files[@]}"
|
||||||
|
do
|
||||||
|
local_expected_test_files+=("$test_path$i")
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
#add_path
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -17,7 +17,6 @@ httpz=("HTTP/1.1")
|
|||||||
# the parts we will send to webserv
|
# the parts we will send to webserv
|
||||||
|
|
||||||
|
|
||||||
# let main.sh handle the l1
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -26,8 +25,6 @@ header+="Nonsense: fu\n"
|
|||||||
|
|
||||||
#header_cycle=("Transfer-encoding: fu" "Content-encoding: fu")
|
#header_cycle=("Transfer-encoding: fu" "Content-encoding: fu")
|
||||||
|
|
||||||
#header+="Transfer-encoding: fu\n"
|
|
||||||
#header+="Content-endcoding: fu\n"
|
|
||||||
body=
|
body=
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ httpz=("HTTP/1.1")
|
|||||||
|
|
||||||
l1="${methods[0]} ${paths[0]} ${httpz[0]}"
|
l1="${methods[0]} ${paths[0]} ${httpz[0]}"
|
||||||
|
|
||||||
header="Host: $host"
|
header="Host: $host\n"
|
||||||
body=
|
body=
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -45,8 +45,7 @@ run_this_test()
|
|||||||
|
|
||||||
files=()
|
files=()
|
||||||
|
|
||||||
file="expected_path_test.txt"
|
file="expected_port_test.txt"
|
||||||
files+=("expected_path_test.txt")
|
|
||||||
#files+=("expected_path_root_test.txt")
|
#files+=("expected_path_root_test.txt")
|
||||||
#files+=("expected_path_testnoslash_test.txt")
|
#files+=("expected_path_testnoslash_test.txt")
|
||||||
#files+=("expected_path_testslash_test.txt")
|
#files+=("expected_path_testslash_test.txt")
|
||||||
|
|||||||
31
compare.txt
31
compare.txt
@@ -1,4 +1,29 @@
|
|||||||
telnet> Trying 127.0.0.1...
|
telnet> Trying 127.0.0.1...
|
||||||
telnet> ?Invalid command
|
Connected to localhost.
|
||||||
telnet> ?Invalid command
|
Escape character is '^]'.
|
||||||
telnet> telnet> telnet>
|
HTTP/1.1 405 Method Not Allowed
|
||||||
|
Allow: GET
|
||||||
|
Content-Type: text/html; charset=UTF-8
|
||||||
|
Content-Length: 199
|
||||||
|
|
||||||
|
<!DOCTYPE html><html><head><title>405 Method Not Allowed</title></head><body><h1 style="text-align:center">405 Method Not Allowed</h1><hr><p style="text-align:center">Le Webserv/0.1</p></body></html>HTTP/1.1 204 No Content
|
||||||
|
Server: Webserv/0.1
|
||||||
|
Connection: keep-alive
|
||||||
|
|
||||||
|
HTTP/1.1 404 Not Found
|
||||||
|
Server: Webserv/0.1
|
||||||
|
Connection: keep-alive
|
||||||
|
Content-Type: text/html; charset=UTF-8
|
||||||
|
Content-Length: 210
|
||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>404 Not Found</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1 style="text-align:center">Check it UP 404 Not Found</h1>
|
||||||
|
<hr>
|
||||||
|
<p style=\"text-align:center\">Le Webserv/0.1</p>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|||||||
156
default.config
156
default.config
@@ -11,109 +11,99 @@ server {
|
|||||||
client_body_limit 5000;
|
client_body_limit 5000;
|
||||||
# Max == 18446744073709551615 / 1024 == 18014398509481984
|
# Max == 18446744073709551615 / 1024 == 18014398509481984
|
||||||
|
|
||||||
|
|
||||||
index index.html; # this is another comment
|
index index.html; # this is another comment
|
||||||
#index mdr.html; # this is another comment
|
#index mdr.html; # this is another comment
|
||||||
|
|
||||||
root ./www/;
|
root ./www/;
|
||||||
|
|
||||||
error_page 404 ./www/error_pages/error_404.html;
|
# error_page 404 ./www/error_pages/error_404.html;
|
||||||
|
# error_page 403 ./www/error_pages/error_404.html;
|
||||||
|
|
||||||
|
|
||||||
|
# location /kapouet {
|
||||||
|
# root /tmp/www;
|
||||||
|
# }
|
||||||
|
|
||||||
location / {
|
location / {
|
||||||
allow_methods GET;
|
allow_methods GET;
|
||||||
root ./www/;
|
root ./www/;
|
||||||
}
|
}
|
||||||
|
|
||||||
location /srcs/cgi-bin/ {
|
# location /srcs/cgi-bin/ {
|
||||||
root ./srcs/cgi-bin/;
|
# root ./srcs/cgi-bin/;
|
||||||
allow_methods POST;
|
# allow_methods POST;
|
||||||
cgi_ext php;
|
# cgi_ext php;
|
||||||
}
|
# }
|
||||||
|
#
|
||||||
|
# location /list {
|
||||||
|
# autoindex on;
|
||||||
|
# }
|
||||||
|
|
||||||
location /list {
|
|
||||||
autoindex on;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /cgi-bin {
|
location /cgi-bin {
|
||||||
root ./srcs/cgi-bin/;
|
root ./srcs/cgi-bin/;
|
||||||
cgi_ext out php sh;
|
cgi_ext out php sh;
|
||||||
}
|
}
|
||||||
|
|
||||||
location /upload {
|
# location /upload {
|
||||||
allow_methods POST;
|
# allow_methods POST;
|
||||||
# autoindex on;
|
# upload_dir ./www/user_files/;
|
||||||
# root ./www/;
|
# # root doesn’t matter if used only with POST and no CGI
|
||||||
# index upload_form_single.html;
|
# }
|
||||||
|
#
|
||||||
# upload_dir ./www/user_files/;
|
# location /the_dump {
|
||||||
# root doesn’t matter if used only with POST and no CGI
|
# allow_methods GET DELETE;
|
||||||
}
|
# root ./www/user_files;
|
||||||
|
# autoindex on;
|
||||||
location /uploaded {
|
# }
|
||||||
allow_methods GET;
|
#
|
||||||
autoindex on;
|
# location /redirect {
|
||||||
# upload_dir ./www/user_files/;
|
# redirect 307 https://fr.wikipedia.org/wiki/Ketchup;
|
||||||
root ./www/user_files;
|
## redirect 307 https://www.youtube.com/watch?v=rG6b8gjMEkw;
|
||||||
# root doesn’t matter if used only with POST and no CGI
|
|
||||||
}
|
|
||||||
|
|
||||||
location /the_dump {
|
|
||||||
allow_methods GET DELETE;
|
|
||||||
root ./www/user_files;
|
|
||||||
autoindex on;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /redirect {
|
|
||||||
redirect 307 https://fr.wikipedia.org/wiki/Ketchup;
|
|
||||||
# redirect 307 https://www.youtube.com/watch?v=rG6b8gjMEkw;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /test {
|
|
||||||
index index1.html subdex.html;
|
|
||||||
root ./www/test/;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /stylesheet {
|
|
||||||
root ./stylesheet/;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /test/index1.html {
|
|
||||||
root ./www/test/index1.html;
|
|
||||||
index index1.html subdex.html;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /hilarious_404/ {
|
|
||||||
redirect 301 https://berniesanders.com/404/;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /test/something.html {
|
|
||||||
# allow_methods DELETE;
|
|
||||||
root ./www/test/something.html;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /test/test_deeper/ {
|
|
||||||
# allow_methods
|
|
||||||
root ./www/test/test_deeper/;
|
|
||||||
index index1.html;
|
|
||||||
}
|
|
||||||
|
|
||||||
location /test/test_deeper/super_deep {
|
|
||||||
root ./www/test/test_deeper/super_deep/;
|
|
||||||
index something.html;
|
|
||||||
}
|
|
||||||
|
|
||||||
# location /test/test_deeper/something.html {
|
|
||||||
# allow_methods DELETE;
|
|
||||||
# }
|
# }
|
||||||
|
|
||||||
}
|
# location /test {
|
||||||
|
# index index1.html subdex.html;
|
||||||
server {
|
# root ./www/test/;
|
||||||
server_name server2;
|
# }
|
||||||
|
#
|
||||||
listen 0.0.0.0:4040;
|
# location /stylesheet {
|
||||||
|
# root ./stylesheet/;
|
||||||
index index.html;
|
# }
|
||||||
root ./www2/;
|
#
|
||||||
|
# location /test/index1.html {
|
||||||
|
# root ./www/test/index1.html;
|
||||||
|
# index index1.html subdex.html;
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# location /hilarious_404/ {
|
||||||
|
# redirect 301 https://berniesanders.com/404/;
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# location /test/something.html {
|
||||||
|
# # allow_methods DELETE;
|
||||||
|
# root ./www/test/something.html;
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# location /test/test_deeper/ {
|
||||||
|
## allow_methods
|
||||||
|
# root ./www/test/test_deeper/;
|
||||||
|
# index index1.html;
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
# location /test/test_deeper/super_deep {
|
||||||
|
# root ./www/test/test_deeper/super_deep/;
|
||||||
|
# index something.html;
|
||||||
|
# }
|
||||||
|
#
|
||||||
|
#}
|
||||||
|
#
|
||||||
|
#server {
|
||||||
|
# server_name server2;
|
||||||
|
#
|
||||||
|
# listen 0.0.0.0:8080;
|
||||||
|
#
|
||||||
|
# index index.html;
|
||||||
|
# root ./www2/;
|
||||||
}
|
}
|
||||||
|
|||||||
13
main_test.sh
13
main_test.sh
@@ -21,11 +21,13 @@ _END='\033[0m'
|
|||||||
|
|
||||||
|
|
||||||
#test_file_names=("test_template.sh" "test_header.sh" "test_path.sh")
|
#test_file_names=("test_template.sh" "test_header.sh" "test_path.sh")
|
||||||
#test_file_names=("test_method.sh" "test_header.sh" "test_path.sh")
|
test_file_names=("test_method.sh" "test_header.sh" "test_path.sh" "test_valid_uri.sh" "test_delete.sh")
|
||||||
test_file_names=("test_port.sh")
|
|
||||||
|
# Run this separately cuz of the content length subtlty
|
||||||
#test_file_names=("test_body.sh")
|
#test_file_names=("test_body.sh")
|
||||||
#test_file_names=("test_valid_uri.sh")
|
|
||||||
#test_file_names=("test_path.sh")
|
# kinda fucking useless, easier to test IRL
|
||||||
|
#test_file_names=("test_port.sh")
|
||||||
|
|
||||||
test_files=()
|
test_files=()
|
||||||
expected_result_files=()
|
expected_result_files=()
|
||||||
@@ -54,7 +56,6 @@ test_all()
|
|||||||
{
|
{
|
||||||
|
|
||||||
arg=${1}
|
arg=${1}
|
||||||
c=0
|
|
||||||
|
|
||||||
make
|
make
|
||||||
|
|
||||||
@@ -102,8 +103,6 @@ test_all()
|
|||||||
cat compare.txt > $expected_result_file
|
cat compare.txt > $expected_result_file
|
||||||
fi
|
fi
|
||||||
|
|
||||||
c+=1
|
|
||||||
|
|
||||||
done
|
done
|
||||||
|
|
||||||
if [ "$arg" = "" ];
|
if [ "$arg" = "" ];
|
||||||
|
|||||||
28
memo.txt
28
memo.txt
@@ -1,7 +1,4 @@
|
|||||||
----Priorité élevée------------------------
|
----Priorité élevée------------------------
|
||||||
- CGI (TODO HUGO)
|
|
||||||
|
|
||||||
- Need to test normal body parsing (Verif avec HUGO)
|
|
||||||
|
|
||||||
- curl --resolve, for testing hostname
|
- curl --resolve, for testing hostname
|
||||||
curl -v --resolve server1:4040:127.0.0.1 --resolve server2:4040:127.0.0.1 server1:4040
|
curl -v --resolve server1:4040:127.0.0.1 --resolve server2:4040:127.0.0.1 server1:4040
|
||||||
@@ -10,34 +7,17 @@
|
|||||||
- handle redirection (Work, but weird behavior need deeper test)
|
- handle redirection (Work, but weird behavior need deeper test)
|
||||||
- Ecrire des tests !
|
- Ecrire des tests !
|
||||||
|
|
||||||
- cgi_cpp_status.cpp with POST dont show error page. Normal or not ?
|
|
||||||
|
|
||||||
For non blocking CGI :
|
|
||||||
// We could maybe,
|
|
||||||
// add FD_RD_FR_CHLD to epoll,
|
|
||||||
// return to the main loop,
|
|
||||||
// read FD_RD_FR_CHLD each time epoll say its ready,
|
|
||||||
// then try waitpid() with WNOHANG after each read.
|
|
||||||
// when waitpid() tell us its finish (or maybe when epoll return EPOLLHUP)
|
|
||||||
// then actually parse the script_output and send it to the client.
|
|
||||||
|
|
||||||
- check status in autoindex
|
|
||||||
|
|
||||||
- merge changes from hugo5 to master (attention a pas casse svp :clown:)
|
|
||||||
|
|
||||||
|
|
||||||
----Priorité modérée------------------------
|
----Priorité modérée------------------------
|
||||||
- namespace utils ?
|
- namespace utils ?
|
||||||
- change "std::string" to reference "std::string &" in most functions
|
- change "std::string" to reference "std::string &" in most functions
|
||||||
and add "const" if apropriate.
|
and add "const" if apropriate.
|
||||||
- peut-être check si ip > 32bits
|
- peut-être check si ip > 32bits
|
||||||
|
|
||||||
|
|
||||||
----Priorité faible------------------------
|
----Priorité faible------------------------
|
||||||
- idealy, we should not clear() raw_request after a response,
|
- idealy, we should not clear() raw_request after a response,
|
||||||
but just the part we actually parsed for this response.
|
but just the part we actually parsed for this response.
|
||||||
I think the client could send multiples request on the same connection one after the other without waiting for response.
|
I think in HTTP/1 the client could not send multiples request on the same connection one after the other without waiting for response.
|
||||||
So raw_request could contain more than the first request we handle.
|
So only for HTTP/2 adn HTTP/3 raw_request could contain more than the first request we handle.
|
||||||
- chunked request (need testing)
|
- chunked request (need testing)
|
||||||
- client_body_limit 0 valeur special pour desactiver dans config
|
- client_body_limit 0 valeur special pour desactiver dans config
|
||||||
- gerer le champ "Accept" du client
|
- gerer le champ "Accept" du client
|
||||||
@@ -47,8 +27,6 @@ and add "const" if apropriate.
|
|||||||
little global timeout on epoll, like 100ms, then find client that actualy need to timeout
|
little global timeout on epoll, like 100ms, then find client that actualy need to timeout
|
||||||
if (actual_time - client.last_action_time > 10000ms){timeout(client)}
|
if (actual_time - client.last_action_time > 10000ms){timeout(client)}
|
||||||
- add headers "Date" and "Last-Modified" to response
|
- add headers "Date" and "Last-Modified" to response
|
||||||
- change "std::string" to reference "std::string &" in most functions
|
|
||||||
and add "const" if apropriate.
|
|
||||||
- Il faut vérifier le path de la requête, voir si le serveur est bien censé délivrer cette ressource et si le client y a accès, avant d'appeler le CGI.
|
- Il faut vérifier le path de la requête, voir si le serveur est bien censé délivrer cette ressource et si le client y a accès, avant d'appeler le CGI.
|
||||||
|
|
||||||
Valgrind error RESOLVED ! :
|
Valgrind error RESOLVED ! :
|
||||||
@@ -56,7 +34,7 @@ Valgrind error RESOLVED ! :
|
|||||||
==847174== at 0x483BE63: operator new(unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
|
==847174== at 0x483BE63: operator new(unsigned long) (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
|
||||||
==847174== by 0x49AA35D: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_mutate(unsigned long, unsigned long, char const*, unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28)
|
==847174== by 0x49AA35D: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_mutate(unsigned long, unsigned long, char const*, unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28)
|
||||||
==847174== by 0x49ABB52: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_append(char const*, unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28)
|
==847174== by 0x49ABB52: std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >::_M_append(char const*, unsigned long) (in /usr/lib/x86_64-linux-gnu/libstdc++.so.6.0.28)
|
||||||
==847174== by 0x426BC5: Webserv::_read_cgi_output(cgi_pipe_rfd&) (run_loop.cpp:39) // (LUKE: its an string.append() call)
|
==847174== by 0x426BC5: Webserv::_read_cgi_output(cgi_pipe_r_from_child&) (run_loop.cpp:39) // (LUKE: its an string.append() call)
|
||||||
==847174== by 0x427962: Webserv::run() (run_loop.cpp:153)
|
==847174== by 0x427962: Webserv::run() (run_loop.cpp:153)
|
||||||
==847174== by 0x4052E9: main (main.cpp:38)
|
==847174== by 0x4052E9: main (main.cpp:38)
|
||||||
|
|
||||||
|
|||||||
1
siege.txt
Normal file
1
siege.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
http://localhost:4040/cgi-bin/cgi_cpp_empty.out?fname=John&lname=Doe
|
||||||
@@ -12,9 +12,13 @@ Client::Client()
|
|||||||
request_complete(false),
|
request_complete(false),
|
||||||
assigned_server(NULL),
|
assigned_server(NULL),
|
||||||
assigned_location(NULL),
|
assigned_location(NULL),
|
||||||
cgi_pipe_rfd(0),
|
cgi_state(CGI_NO_CGI),
|
||||||
|
cgi_pipe_w_to_child(-1),
|
||||||
|
cgi_pipe_r_from_child(-1),
|
||||||
|
cgi_pipe_w_to_parent(-1),
|
||||||
|
cgi_pipe_r_from_parent(-1),
|
||||||
cgi_pid(0),
|
cgi_pid(0),
|
||||||
_fd(0),
|
_fd(-1),
|
||||||
_port(""),
|
_port(""),
|
||||||
_ip(""),
|
_ip(""),
|
||||||
_lsocket(NULL)
|
_lsocket(NULL)
|
||||||
@@ -29,7 +33,11 @@ Client::Client(int afd, listen_socket *lsocket, std::string aport, std::string a
|
|||||||
request_complete(false),
|
request_complete(false),
|
||||||
assigned_server(NULL),
|
assigned_server(NULL),
|
||||||
assigned_location(NULL),
|
assigned_location(NULL),
|
||||||
cgi_pipe_rfd(0),
|
cgi_state(CGI_NO_CGI),
|
||||||
|
cgi_pipe_w_to_child(-1),
|
||||||
|
cgi_pipe_r_from_child(-1),
|
||||||
|
cgi_pipe_w_to_parent(-1),
|
||||||
|
cgi_pipe_r_from_parent(-1),
|
||||||
cgi_pid(0),
|
cgi_pid(0),
|
||||||
_fd(afd),
|
_fd(afd),
|
||||||
_port(aport),
|
_port(aport),
|
||||||
@@ -87,7 +95,7 @@ void Client::parse_request_headers(std::vector<ServerConfig> &servers)
|
|||||||
if (raw_request.find(CRLF CRLF) == NPOS)
|
if (raw_request.find(CRLF CRLF) == NPOS)
|
||||||
return ;
|
return ;
|
||||||
header_complete = true;
|
header_complete = true;
|
||||||
clear_request(); // not mandatory
|
clear_request_vars(); // not mandatory
|
||||||
|
|
||||||
_parse_request_line();
|
_parse_request_line();
|
||||||
if (status)
|
if (status)
|
||||||
@@ -104,7 +112,6 @@ void Client::parse_request_headers(std::vector<ServerConfig> &servers)
|
|||||||
_check_request_errors();
|
_check_request_errors();
|
||||||
if (status)
|
if (status)
|
||||||
return;
|
return;
|
||||||
_parse_port_hostname(get_rq_headers("Host")); // use getter for headers because it works case insensitive
|
|
||||||
|
|
||||||
// DEBUG
|
// DEBUG
|
||||||
// std::cerr << get_rq_method_str() << " " << get_rq_target() << " " << get_rq_version() << "\n";
|
// std::cerr << get_rq_method_str() << " " << get_rq_target() << " " << get_rq_version() << "\n";
|
||||||
@@ -229,7 +236,7 @@ void Client::fill_script_path(std::string &path, size_t pos)
|
|||||||
|
|
||||||
void Client::clear()
|
void Client::clear()
|
||||||
{
|
{
|
||||||
clear_request();
|
clear_request_vars();
|
||||||
raw_request.clear();
|
raw_request.clear();
|
||||||
response.clear();
|
response.clear();
|
||||||
status = 0;
|
status = 0;
|
||||||
@@ -238,12 +245,10 @@ void Client::clear()
|
|||||||
request_complete = false;
|
request_complete = false;
|
||||||
assigned_server = NULL;
|
assigned_server = NULL;
|
||||||
assigned_location = NULL;
|
assigned_location = NULL;
|
||||||
cgi_pipe_rfd = 0;
|
clear_cgi_vars();
|
||||||
cgi_pid = 0;
|
|
||||||
cgi_output.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::clear_request()
|
void Client::clear_request_vars()
|
||||||
{
|
{
|
||||||
clear_script();
|
clear_script();
|
||||||
_request.method = UNKNOWN;
|
_request.method = UNKNOWN;
|
||||||
@@ -254,8 +259,6 @@ void Client::clear_request()
|
|||||||
_request.multi_bodys.clear();
|
_request.multi_bodys.clear();
|
||||||
_request.abs_path.clear();
|
_request.abs_path.clear();
|
||||||
_request.query.clear();
|
_request.query.clear();
|
||||||
_request.port.clear();
|
|
||||||
_request.hostname.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Client::clear_script()
|
void Client::clear_script()
|
||||||
@@ -264,14 +267,25 @@ void Client::clear_script()
|
|||||||
_request.script.info.clear();
|
_request.script.info.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Client::clear_cgi_vars()
|
||||||
|
{
|
||||||
|
cgi_state = CGI_NO_CGI;
|
||||||
|
cgi_pipe_w_to_child = -1;
|
||||||
|
cgi_pipe_r_from_child = -1;
|
||||||
|
cgi_pipe_w_to_parent = -1;
|
||||||
|
cgi_pipe_r_from_parent = -1;
|
||||||
|
cgi_pid = 0;
|
||||||
|
cgi_output.clear();
|
||||||
|
}
|
||||||
|
|
||||||
// debug
|
// debug
|
||||||
void Client::print_client(std::string message)
|
void Client::print_client(std::string message)
|
||||||
{
|
{
|
||||||
std::map<std::string, std::string>::iterator it;
|
std::map<std::string, std::string>::iterator it;
|
||||||
std::cout << "\n=== DEBUG PRINT CLIENT ===\n";
|
std::cerr << "\n=== DEBUG PRINT CLIENT ===\n";
|
||||||
std::cout << message << ":\n----------\n\n" << "raw_request:\n__\n";
|
std::cerr << message << ":\n----------\n\n" << "raw_request:\n__\n";
|
||||||
::print_special(raw_request);
|
::print_special(raw_request);
|
||||||
std::cout << "\n__\n"
|
std::cerr << "\n__\n"
|
||||||
<< "get_cl_fd() : [" << get_cl_fd() << "]\n"
|
<< "get_cl_fd() : [" << get_cl_fd() << "]\n"
|
||||||
<< "get_cl_port() : [" << get_cl_port() << "]\n"
|
<< "get_cl_port() : [" << get_cl_port() << "]\n"
|
||||||
<< "get_cl_ip() : [" << get_cl_ip() << "]\n"
|
<< "get_cl_ip() : [" << get_cl_ip() << "]\n"
|
||||||
@@ -281,14 +295,12 @@ std::cout << "\n=== DEBUG PRINT CLIENT ===\n";
|
|||||||
<< "get_rq_query() : [" << get_rq_query() << "]\n"
|
<< "get_rq_query() : [" << get_rq_query() << "]\n"
|
||||||
<< "get_rq_version() : [" << get_rq_version() << "]\n"
|
<< "get_rq_version() : [" << get_rq_version() << "]\n"
|
||||||
<< "get_rq_body() : [" << get_rq_body() << "]\n"
|
<< "get_rq_body() : [" << get_rq_body() << "]\n"
|
||||||
<< "get_rq_port() : [" << get_rq_port() << "]\n"
|
|
||||||
<< "get_rq_hostname() : [" << get_rq_hostname() << "]\n"
|
|
||||||
<< "get_rq_script_path() : [" << get_rq_script_path() << "]\n"
|
<< "get_rq_script_path() : [" << get_rq_script_path() << "]\n"
|
||||||
<< "get_rq_script_info() : [" << get_rq_script_info() << "]\n"
|
<< "get_rq_script_info() : [" << get_rq_script_info() << "]\n"
|
||||||
<< "headers :\n";
|
<< "headers :\n";
|
||||||
for (it = _request.headers.begin(); it != _request.headers.end(); it++)
|
for (it = _request.headers.begin(); it != _request.headers.end(); it++)
|
||||||
std::cout << " " << it->first << ": [" << it->second << "]\n";
|
std::cerr << " " << it->first << ": [" << it->second << "]\n";
|
||||||
std::cout << "\n=== END PRINT CLIENT ===\n\n";
|
std::cerr << "\n=== END PRINT CLIENT ===\n\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
/*********************************************
|
/*********************************************
|
||||||
@@ -310,8 +322,6 @@ std::string Client::get_rq_abs_path() const { return _request.abs_path; }
|
|||||||
std::string Client::get_rq_query() const { return _request.query; }
|
std::string Client::get_rq_query() const { return _request.query; }
|
||||||
std::string Client::get_rq_version() const { return _request.version; }
|
std::string Client::get_rq_version() const { return _request.version; }
|
||||||
std::string Client::get_rq_body() const { return _request.body; }
|
std::string Client::get_rq_body() const { return _request.body; }
|
||||||
std::string Client::get_rq_port() const { return _request.port; }
|
|
||||||
std::string Client::get_rq_hostname() const { return _request.hostname; }
|
|
||||||
std::string Client::get_rq_script_path()const { return _request.script.path; }
|
std::string Client::get_rq_script_path()const { return _request.script.path; }
|
||||||
std::string Client::get_rq_script_info()const { return _request.script.info; }
|
std::string Client::get_rq_script_info()const { return _request.script.info; }
|
||||||
|
|
||||||
@@ -394,31 +404,11 @@ void Client::_parse_request_fields()
|
|||||||
::str_map_key_tolower(_request.headers);
|
::str_map_key_tolower(_request.headers);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO : I think its now useless. Probably to delete.
|
|
||||||
void Client::_parse_port_hostname(std::string host)
|
|
||||||
{
|
|
||||||
size_t pos;
|
|
||||||
|
|
||||||
if (host == "")
|
|
||||||
std::cerr << "no host\n";
|
|
||||||
|
|
||||||
pos = host.find(':');
|
|
||||||
// port :
|
|
||||||
if (pos == NPOS)
|
|
||||||
_request.port = "4040"; // TODO: make equal to default port in config
|
|
||||||
else
|
|
||||||
_request.port = host.substr(pos);
|
|
||||||
if (_request.port == ":")
|
|
||||||
_request.port = "";
|
|
||||||
// hostname :
|
|
||||||
_request.hostname = host.substr(0, pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Client::_check_request_errors()
|
void Client::_check_request_errors()
|
||||||
{
|
{
|
||||||
/* Debug */ std::cerr << "Content-Length=" << get_rq_headers("Content-Length") << "\n";
|
// /* Debug */ std::cerr << "Content-Length=" << get_rq_headers("Content-Length") << "\n";
|
||||||
/* Debug */ std::cerr << "strtoul=" << std::strtoul(get_rq_headers("Content-Length").c_str(), NULL, 10) << "\n";
|
// /* Debug */ std::cerr << "strtoul=" << std::strtoul(get_rq_headers("Content-Length").c_str(), NULL, 10) << "\n";
|
||||||
/* Debug */ std::cerr << "client_body_limit=" << assigned_server->client_body_limit << "\n";
|
// /* Debug */ std::cerr << "client_body_limit=" << assigned_server->client_body_limit << "\n";
|
||||||
///////////////////////
|
///////////////////////
|
||||||
// Request line checks
|
// Request line checks
|
||||||
if (_request.method == UNKNOWN)
|
if (_request.method == UNKNOWN)
|
||||||
@@ -518,7 +508,6 @@ If we get a url that ends in / ignore the last /
|
|||||||
|
|
||||||
for (std::vector<LocationConfig>::const_iterator it = server.locations.begin(); it != server.locations.end(); it++)
|
for (std::vector<LocationConfig>::const_iterator it = server.locations.begin(); it != server.locations.end(); it++)
|
||||||
{
|
{
|
||||||
// std::cout << it->path << " -- ";
|
|
||||||
if (it->path.size() > uri.size())
|
if (it->path.size() > uri.size())
|
||||||
continue ;
|
continue ;
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
# define CLIENT_HPP
|
# define CLIENT_HPP
|
||||||
|
|
||||||
# include <iostream>
|
# include <iostream>
|
||||||
|
# include <iomanip> // setw
|
||||||
# include <string>
|
# include <string>
|
||||||
# include <map>
|
# include <map>
|
||||||
# include <vector>
|
# include <vector>
|
||||||
@@ -35,11 +36,18 @@ struct Request
|
|||||||
std::map<std::string, std::string> headers;
|
std::map<std::string, std::string> headers;
|
||||||
std::string body;
|
std::string body;
|
||||||
std::vector<MultipartBody> multi_bodys;
|
std::vector<MultipartBody> multi_bodys;
|
||||||
std::string port;
|
|
||||||
std::string hostname;
|
|
||||||
struct Script script;
|
struct Script script;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum cgi_states
|
||||||
|
{
|
||||||
|
CGI_NO_CGI = 0,
|
||||||
|
CGI_WAIT_TO_EXEC,
|
||||||
|
CGI_READY_TO_EXEC,
|
||||||
|
CGI_OUTPUT_READING,
|
||||||
|
CGI_OUTPUT_COMPLETE
|
||||||
|
};
|
||||||
|
|
||||||
class Client
|
class Client
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@@ -55,10 +63,15 @@ class Client
|
|||||||
bool header_complete;
|
bool header_complete;
|
||||||
bool body_complete;
|
bool body_complete;
|
||||||
bool request_complete;
|
bool request_complete;
|
||||||
// size_t read_body_size; // unused for now
|
|
||||||
ServerConfig *assigned_server; // cant be const cause of error_pages.operator[]
|
ServerConfig *assigned_server; // cant be const cause of error_pages.operator[]
|
||||||
const LocationConfig *assigned_location;
|
const LocationConfig *assigned_location;
|
||||||
int cgi_pipe_rfd;
|
|
||||||
|
// CGI variables
|
||||||
|
cgi_states cgi_state;
|
||||||
|
int cgi_pipe_w_to_child;
|
||||||
|
int cgi_pipe_r_from_child;
|
||||||
|
int cgi_pipe_w_to_parent;
|
||||||
|
int cgi_pipe_r_from_parent;
|
||||||
pid_t cgi_pid;
|
pid_t cgi_pid;
|
||||||
std::string cgi_output;
|
std::string cgi_output;
|
||||||
|
|
||||||
@@ -76,8 +89,6 @@ class Client
|
|||||||
std::string get_rq_query() const;
|
std::string get_rq_query() const;
|
||||||
std::string get_rq_version() const;
|
std::string get_rq_version() const;
|
||||||
std::string get_rq_body() const;
|
std::string get_rq_body() const;
|
||||||
std::string get_rq_port() const;
|
|
||||||
std::string get_rq_hostname() const;
|
|
||||||
std::string get_rq_script_path() const;
|
std::string get_rq_script_path() const;
|
||||||
std::string get_rq_script_info() const;
|
std::string get_rq_script_info() const;
|
||||||
std::string get_rq_headers(const std::string & key) const;
|
std::string get_rq_headers(const std::string & key) const;
|
||||||
@@ -88,7 +99,8 @@ class Client
|
|||||||
void parse_request_headers(std::vector<ServerConfig> &servers);
|
void parse_request_headers(std::vector<ServerConfig> &servers);
|
||||||
void parse_request_body();
|
void parse_request_body();
|
||||||
void clear();
|
void clear();
|
||||||
void clear_request();
|
void clear_request_vars();
|
||||||
|
void clear_cgi_vars();
|
||||||
void clear_script();
|
void clear_script();
|
||||||
void fill_script_path(std::string &path, size_t pos);
|
void fill_script_path(std::string &path, size_t pos);
|
||||||
// DEBUG
|
// DEBUG
|
||||||
@@ -104,7 +116,6 @@ class Client
|
|||||||
void _parse_request_line();
|
void _parse_request_line();
|
||||||
void _parse_request_fields();
|
void _parse_request_fields();
|
||||||
void _parse_request_target( std::string target );
|
void _parse_request_target( std::string target );
|
||||||
void _parse_port_hostname(std::string host);
|
|
||||||
void _parse_chunked_body(size_t pos);
|
void _parse_chunked_body(size_t pos);
|
||||||
void _parse_multipart_body(size_t pos);
|
void _parse_multipart_body(size_t pos);
|
||||||
void _check_request_errors();
|
void _check_request_errors();
|
||||||
|
|||||||
@@ -36,8 +36,6 @@ void Client::_parse_multipart_body(size_t pos)
|
|||||||
}
|
}
|
||||||
start_pos += sizeof("boundary=")-1;
|
start_pos += sizeof("boundary=")-1;
|
||||||
boundary = boundary.substr(start_pos);
|
boundary = boundary.substr(start_pos);
|
||||||
std::cerr << "boundary =|" << boundary << "|\n";
|
|
||||||
|
|
||||||
|
|
||||||
// Search boundary
|
// Search boundary
|
||||||
start_pos = raw_request.find("--" + boundary, pos);
|
start_pos = raw_request.find("--" + boundary, pos);
|
||||||
@@ -48,7 +46,7 @@ void Client::_parse_multipart_body(size_t pos)
|
|||||||
}
|
}
|
||||||
start_pos += sizeof("--")-1 + boundary.size() + CRLF_SIZE;
|
start_pos += sizeof("--")-1 + boundary.size() + CRLF_SIZE;
|
||||||
|
|
||||||
while (1) // TODO : test loop for multi body
|
while (1)
|
||||||
{
|
{
|
||||||
end_pos = raw_request.find("--" + boundary, start_pos);
|
end_pos = raw_request.find("--" + boundary, start_pos);
|
||||||
if (end_pos == NPOS)
|
if (end_pos == NPOS)
|
||||||
@@ -56,9 +54,6 @@ void Client::_parse_multipart_body(size_t pos)
|
|||||||
status = 400; std::cerr << "_parse_multipart_body() error 3\n";
|
status = 400; std::cerr << "_parse_multipart_body() error 3\n";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
/* // Maye useful for multi body (remove "start_pos - CRLF_SIZE" if used)
|
|
||||||
end_pos = raw_request.rfind(CRLF, end_pos); if (end_pos == NPOS) {status = 400; return; } */
|
|
||||||
|
|
||||||
new_body.body = raw_request.substr(start_pos, end_pos - start_pos - CRLF_SIZE);
|
new_body.body = raw_request.substr(start_pos, end_pos - start_pos - CRLF_SIZE);
|
||||||
|
|
||||||
// Split headers from body
|
// Split headers from body
|
||||||
@@ -74,7 +69,6 @@ void Client::_parse_multipart_body(size_t pos)
|
|||||||
}
|
}
|
||||||
tmp_pos += CRLF_SIZE*2;
|
tmp_pos += CRLF_SIZE*2;
|
||||||
new_body.body.erase(0, tmp_pos);
|
new_body.body.erase(0, tmp_pos);
|
||||||
// ::print_map(new_body.headers);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{ // No headers case
|
{ // No headers case
|
||||||
@@ -94,10 +88,5 @@ void Client::_parse_multipart_body(size_t pos)
|
|||||||
&& raw_request[start_pos] == '-'
|
&& raw_request[start_pos] == '-'
|
||||||
&& raw_request[start_pos+1] == '-')
|
&& raw_request[start_pos+1] == '-')
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* ::print_special(raw_request);
|
|
||||||
std::cerr << "start_pos = " << start_pos << "\n";
|
|
||||||
std::cerr << "raw_request.size() = " << raw_request.size() << "\n";
|
|
||||||
std::cerr << raw_request.substr(start_pos); */
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,4 +92,3 @@ fclean: clean
|
|||||||
re: fclean all
|
re: fclean all
|
||||||
|
|
||||||
.PHONY : all clean fclean re
|
.PHONY : all clean fclean re
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ int main (int ac, char **av, char ** env)
|
|||||||
path = get_value("file", rq_body);
|
path = get_value("file", rq_body);
|
||||||
path = "./www/" + path;
|
path = "./www/" + path;
|
||||||
|
|
||||||
status = ::eval_file_read(path);
|
status = ::eval_file_access(path, R_OK);
|
||||||
if (status)
|
if (status)
|
||||||
{
|
{
|
||||||
std::cout << "Status: " << status << CRLF CRLF;
|
std::cout << "Status: " << status << CRLF CRLF;
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ void
|
|||||||
http_body += HTML_BODY_BOTTOM;
|
http_body += HTML_BODY_BOTTOM;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t eval_file_read(const std::string &path)
|
size_t eval_file_access(const std::string &path, int mode)
|
||||||
{
|
{
|
||||||
if (::access(path.c_str(), F_OK) == -1)
|
if (::access(path.c_str(), F_OK) == -1)
|
||||||
{
|
{
|
||||||
@@ -189,7 +189,7 @@ size_t eval_file_read(const std::string &path)
|
|||||||
return 404; // NOT_FOUND, file doesn't exist
|
return 404; // NOT_FOUND, file doesn't exist
|
||||||
}
|
}
|
||||||
|
|
||||||
if (::access(path.c_str(), R_OK) == -1)
|
if (::access(path.c_str(), mode) == -1)
|
||||||
{
|
{
|
||||||
std::perror("err access()");
|
std::perror("err access()");
|
||||||
return 403; // FORBIDDEN, file doesn't have access permission
|
return 403; // FORBIDDEN, file doesn't have access permission
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ void
|
|||||||
fill_body_basic(char **env, std::string & http_body, const std::string & rq_body);
|
fill_body_basic(char **env, std::string & http_body, const std::string & rq_body);
|
||||||
|
|
||||||
size_t
|
size_t
|
||||||
eval_file_read(const std::string &path);
|
eval_file_access(const std::string &path, int mode);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -14,12 +14,11 @@
|
|||||||
# include <cstdlib> // strtol, stroul
|
# include <cstdlib> // strtol, stroul
|
||||||
# include <iostream> // cout, cin
|
# include <iostream> // cout, cin
|
||||||
# include <fstream> // ifstream
|
# include <fstream> // ifstream
|
||||||
# include <sys/stat.h> // stat(), replaces opendir() don't bother with ERRNO ?
|
|
||||||
# include <algorithm> // sort() in Post
|
# include <algorithm> // sort() in Post
|
||||||
|
|
||||||
class ConfigParser {
|
class ConfigParser {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
ConfigParser();
|
ConfigParser();
|
||||||
~ConfigParser();
|
~ConfigParser();
|
||||||
@@ -27,33 +26,28 @@ public:
|
|||||||
|
|
||||||
void read_config(const std::string &config_file);
|
void read_config(const std::string &config_file);
|
||||||
|
|
||||||
std::vector<ServerConfig> * parse(); // const?
|
std::vector<ServerConfig> *parse() const;
|
||||||
|
|
||||||
|
|
||||||
// i thought if it were an instance of this class you could call
|
|
||||||
// private member functions from anywhere... // QUESTION : Wut ?
|
|
||||||
void print_content() const;
|
void print_content() const;
|
||||||
|
|
||||||
|
private:
|
||||||
private:
|
|
||||||
std::string _content;
|
std::string _content;
|
||||||
|
|
||||||
|
ServerConfig _parse_server(size_t *start) const;
|
||||||
|
LocationConfig _parse_location(size_t *start) const;
|
||||||
|
|
||||||
ServerConfig _parse_server(size_t *start);
|
void _set_server_values(ServerConfig *server, const std::string &key, std::string value) const;
|
||||||
LocationConfig _parse_location(size_t *start);
|
void _set_location_values(LocationConfig *location, const std::string &key, std::string value) const;
|
||||||
|
|
||||||
void _set_server_values(ServerConfig *server, const std::string key, std::string value);
|
/* Extra */
|
||||||
void _set_location_values(LocationConfig *location, const std::string key, std::string value);
|
std::string _pre_set_val_check(const std::string &key,
|
||||||
|
const std::string &value) const;
|
||||||
|
|
||||||
/* Extra */
|
std::string _get_first_word(size_t *curr) const;
|
||||||
std::string _pre_set_val_check(const std::string key,
|
std::string _get_rest_of_line(size_t *curr) const;
|
||||||
const std::string value);
|
|
||||||
|
|
||||||
std::string _get_first_word(size_t *curr); // const?
|
/* Post Processing */
|
||||||
std::string _get_rest_of_line(size_t *curr); // const?
|
void _post_processing(std::vector<ServerConfig> *servers) const;
|
||||||
|
|
||||||
/* Post Processing */
|
|
||||||
void _post_processing(std::vector<ServerConfig> *servers);
|
|
||||||
bool _find_root_path_location(std::vector<LocationConfig> locations) const;
|
bool _find_root_path_location(std::vector<LocationConfig> locations) const;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,8 +17,7 @@ struct ServerConfig
|
|||||||
std::string host;
|
std::string host;
|
||||||
std::string port;
|
std::string port;
|
||||||
|
|
||||||
std::string root; // ./www/ or www work www/ and www work
|
std::string root;
|
||||||
// i do remove trailing / tho
|
|
||||||
|
|
||||||
size_t client_body_limit;
|
size_t client_body_limit;
|
||||||
|
|
||||||
@@ -42,10 +41,7 @@ struct ServerConfig
|
|||||||
for(std::map<int, std::string>::const_iterator it = error_pages.begin(); \
|
for(std::map<int, std::string>::const_iterator it = error_pages.begin(); \
|
||||||
it != error_pages.end(); it++)
|
it != error_pages.end(); it++)
|
||||||
std::cout << it->first << "--" << it->second << " ";
|
std::cout << it->first << "--" << it->second << " ";
|
||||||
// for (size_t i = 0; i < error_pages.size(); i++)
|
|
||||||
// std::cout << error_pages->first << "--" << error_pages->second << " ";
|
|
||||||
|
|
||||||
// std::cout << "skiping Locations for now...\n";
|
|
||||||
for (std::vector<LocationConfig>::const_iterator it = locations.begin(); it < locations.end(); it++)
|
for (std::vector<LocationConfig>::const_iterator it = locations.begin(); it < locations.end(); it++)
|
||||||
it->print_all();
|
it->print_all();
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,13 @@
|
|||||||
|
|
||||||
#include "ConfigParser.hpp"
|
#include "ConfigParser.hpp"
|
||||||
|
|
||||||
// should i be sending & references?
|
std::string ConfigParser::_pre_set_val_check(const std::string &key,
|
||||||
// const?
|
const std::string &value) const
|
||||||
std::string ConfigParser::_pre_set_val_check(const std::string key,
|
|
||||||
const std::string value)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
// check key for ;
|
// check key for ;
|
||||||
// check values for ; at end and right number of words depending on key
|
// check values for ; at end and right number of words depending on key
|
||||||
|
|
||||||
// std::cout << "pre check\n";
|
|
||||||
if (key.find_first_of(";") != NPOS)
|
if (key.find_first_of(";") != NPOS)
|
||||||
throw std::invalid_argument("bad config file arguments");
|
throw std::invalid_argument("bad config file arguments");
|
||||||
|
|
||||||
@@ -30,9 +27,8 @@ std::string ConfigParser::_pre_set_val_check(const std::string key,
|
|||||||
return (value.substr(0, i));
|
return (value.substr(0, i));
|
||||||
}
|
}
|
||||||
|
|
||||||
// const?
|
|
||||||
// assumes curr is on a space or \t or \n
|
// assumes curr is on a space or \t or \n
|
||||||
std::string ConfigParser::_get_first_word(size_t *curr)
|
std::string ConfigParser::_get_first_word(size_t *curr) const
|
||||||
{
|
{
|
||||||
size_t start;
|
size_t start;
|
||||||
|
|
||||||
@@ -45,9 +41,8 @@ std::string ConfigParser::_get_first_word(size_t *curr)
|
|||||||
return (key);
|
return (key);
|
||||||
}
|
}
|
||||||
|
|
||||||
// const?
|
|
||||||
// also assumes curr is on a space \t or \n
|
// also assumes curr is on a space \t or \n
|
||||||
std::string ConfigParser::_get_rest_of_line(size_t *curr)
|
std::string ConfigParser::_get_rest_of_line(size_t *curr) const
|
||||||
{
|
{
|
||||||
size_t start;
|
size_t start;
|
||||||
|
|
||||||
|
|||||||
@@ -41,8 +41,7 @@ void ConfigParser::read_config(const std::string &config_file)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// const?
|
std::vector<ServerConfig> * ConfigParser::parse() const
|
||||||
std::vector<ServerConfig> * ConfigParser::parse()
|
|
||||||
{
|
{
|
||||||
std::vector<ServerConfig> * ret = new std::vector<ServerConfig>();
|
std::vector<ServerConfig> * ret = new std::vector<ServerConfig>();
|
||||||
|
|
||||||
@@ -67,7 +66,7 @@ std::vector<ServerConfig> * ConfigParser::parse()
|
|||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerConfig ConfigParser::_parse_server(size_t *start)
|
ServerConfig ConfigParser::_parse_server(size_t *start) const
|
||||||
{
|
{
|
||||||
ServerConfig ret;
|
ServerConfig ret;
|
||||||
size_t curr = _content.find_first_not_of(" \t\n", *start);
|
size_t curr = _content.find_first_not_of(" \t\n", *start);
|
||||||
@@ -78,7 +77,6 @@ ServerConfig ConfigParser::_parse_server(size_t *start)
|
|||||||
|
|
||||||
if ((curr = _content.find_first_of(" \t\n", curr + 1)) == NPOS)
|
if ((curr = _content.find_first_of(" \t\n", curr + 1)) == NPOS)
|
||||||
throw std::invalid_argument("bad config file syntax");
|
throw std::invalid_argument("bad config file syntax");
|
||||||
// are there other things to check for?
|
|
||||||
while (curr != NPOS) // here curr == { + 1
|
while (curr != NPOS) // here curr == { + 1
|
||||||
{
|
{
|
||||||
// so this moves curr to past the word...
|
// so this moves curr to past the word...
|
||||||
@@ -104,7 +102,7 @@ ServerConfig ConfigParser::_parse_server(size_t *start)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
LocationConfig ConfigParser::_parse_location(size_t *start)
|
LocationConfig ConfigParser::_parse_location(size_t *start) const
|
||||||
{
|
{
|
||||||
LocationConfig ret;
|
LocationConfig ret;
|
||||||
size_t curr = *start;
|
size_t curr = *start;
|
||||||
@@ -148,11 +146,9 @@ LocationConfig ConfigParser::_parse_location(size_t *start)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
// should i be sending pointers or references?
|
|
||||||
void ConfigParser::_set_server_values(ServerConfig *server,
|
void ConfigParser::_set_server_values(ServerConfig *server,
|
||||||
const std::string key, std::string value)
|
const std::string &key, std::string value) const
|
||||||
{
|
{
|
||||||
// should i be sending pointers or references?
|
|
||||||
value = _pre_set_val_check(key, value);
|
value = _pre_set_val_check(key, value);
|
||||||
|
|
||||||
std::vector<std::string> tmp_val = ::split(value, ' ');
|
std::vector<std::string> tmp_val = ::split(value, ' ');
|
||||||
@@ -174,11 +170,11 @@ void ConfigParser::_set_server_values(ServerConfig *server,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (key == "listen" && size == 1 && server->host == ""
|
else if (key == "listen" && size == 1 && server->host == ""
|
||||||
&& server->port == "") // QUESTION LUKE : C'est quoi cette condition ? Si listen est vide ? Je comprends pas trop.
|
&& server->port == "")
|
||||||
{
|
{
|
||||||
if (tmp_val[0].find_first_of(":") == NPOS)
|
if (tmp_val[0].find_first_of(":") == NPOS)
|
||||||
{
|
{
|
||||||
if (!::isNumeric_btw(0, 65535, tmp_val[0]))
|
if (!::is_numeric_btw(0, 65535, tmp_val[0]))
|
||||||
throw std::invalid_argument("bad port number");
|
throw std::invalid_argument("bad port number");
|
||||||
server->host = "0.0.0.0";
|
server->host = "0.0.0.0";
|
||||||
server->port = tmp_val[0];
|
server->port = tmp_val[0];
|
||||||
@@ -192,10 +188,10 @@ void ConfigParser::_set_server_values(ServerConfig *server,
|
|||||||
throw std::invalid_argument("bad host ip");
|
throw std::invalid_argument("bad host ip");
|
||||||
for (size_t i = 0; i < ip.size(); i++)
|
for (size_t i = 0; i < ip.size(); i++)
|
||||||
{
|
{
|
||||||
if (!::isNumeric_btw(0, 255, ip[i]))
|
if (!::is_numeric_btw(0, 255, ip[i]))
|
||||||
throw std::invalid_argument("bad host ip");
|
throw std::invalid_argument("bad host ip");
|
||||||
}
|
}
|
||||||
if (!::isNumeric_btw(0, 65535, tmp2[1]))
|
if (!::is_numeric_btw(0, 65535, tmp2[1]))
|
||||||
throw std::invalid_argument("bad port number");
|
throw std::invalid_argument("bad port number");
|
||||||
server->host = tmp2[0];
|
server->host = tmp2[0];
|
||||||
server->port = tmp2[1];
|
server->port = tmp2[1];
|
||||||
@@ -206,13 +202,12 @@ void ConfigParser::_set_server_values(ServerConfig *server,
|
|||||||
// remove trailing /
|
// remove trailing /
|
||||||
if (tmp_val[0][tmp_val[0].size() - 1] == '/')
|
if (tmp_val[0][tmp_val[0].size() - 1] == '/')
|
||||||
tmp_val[0].erase(tmp_val[0].size() - 1, 1);
|
tmp_val[0].erase(tmp_val[0].size() - 1, 1);
|
||||||
// tmp_val[0].push_back('/');
|
|
||||||
server->root = tmp_val[0];
|
server->root = tmp_val[0];
|
||||||
}
|
}
|
||||||
else if (key == "client_body_limit" && size == 1
|
else if (key == "client_body_limit" && size == 1
|
||||||
&& server->client_body_limit == 0)
|
&& server->client_body_limit == 0)
|
||||||
{
|
{
|
||||||
if (!::isNumeric(tmp_val[0]))
|
if (!::is_numeric(tmp_val[0]))
|
||||||
throw std::invalid_argument("client_body_limit not a number");
|
throw std::invalid_argument("client_body_limit not a number");
|
||||||
server->client_body_limit = std::strtoul(tmp_val[0].c_str(), NULL, 10);
|
server->client_body_limit = std::strtoul(tmp_val[0].c_str(), NULL, 10);
|
||||||
if (errno == ERANGE || server->client_body_limit > (ULONG_MAX / KB) )
|
if (errno == ERANGE || server->client_body_limit > (ULONG_MAX / KB) )
|
||||||
@@ -229,7 +224,7 @@ void ConfigParser::_set_server_values(ServerConfig *server,
|
|||||||
std::string path = tmp_val[size - 1];
|
std::string path = tmp_val[size - 1];
|
||||||
for (size_t i = 0; i < size - 1; i++)
|
for (size_t i = 0; i < size - 1; i++)
|
||||||
{
|
{
|
||||||
if (!(isNumeric_btw(400, 599, tmp_val[i])))
|
if (!(is_numeric_btw(400, 599, tmp_val[i])))
|
||||||
throw std::invalid_argument("invalid error code");
|
throw std::invalid_argument("invalid error code");
|
||||||
int status_code = std::strtoul(tmp_val[i].c_str(), NULL, 10);
|
int status_code = std::strtoul(tmp_val[i].c_str(), NULL, 10);
|
||||||
if (server->error_pages.find(status_code) != server->error_pages.end())
|
if (server->error_pages.find(status_code) != server->error_pages.end())
|
||||||
@@ -242,11 +237,9 @@ void ConfigParser::_set_server_values(ServerConfig *server,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// should i be sending pointers or references?
|
|
||||||
void ConfigParser::_set_location_values(LocationConfig *location,
|
void ConfigParser::_set_location_values(LocationConfig *location,
|
||||||
const std::string key, std::string value)
|
const std::string &key, std::string value) const
|
||||||
{
|
{
|
||||||
// should i be sending pointers or references?
|
|
||||||
value = _pre_set_val_check(key, value);
|
value = _pre_set_val_check(key, value);
|
||||||
|
|
||||||
std::vector<std::string> tmp_val = ::split(value, ' ');
|
std::vector<std::string> tmp_val = ::split(value, ' ');
|
||||||
@@ -259,7 +252,6 @@ void ConfigParser::_set_location_values(LocationConfig *location,
|
|||||||
// remove trailing /
|
// remove trailing /
|
||||||
if (tmp_val[0][tmp_val[0].size() - 1] == '/')
|
if (tmp_val[0][tmp_val[0].size() - 1] == '/')
|
||||||
tmp_val[0].erase(tmp_val[0].size() - 1, 1);
|
tmp_val[0].erase(tmp_val[0].size() - 1, 1);
|
||||||
// tmp_val[0].push_back('/');
|
|
||||||
location->root = tmp_val[0];
|
location->root = tmp_val[0];
|
||||||
}
|
}
|
||||||
else if (key == "autoindex" && size == 1)
|
else if (key == "autoindex" && size == 1)
|
||||||
@@ -306,7 +298,6 @@ void ConfigParser::_set_location_values(LocationConfig *location,
|
|||||||
}
|
}
|
||||||
else if (key == "upload_dir" && size == 1 && location->upload_dir == "")
|
else if (key == "upload_dir" && size == 1 && location->upload_dir == "")
|
||||||
{
|
{
|
||||||
// what checks to do?
|
|
||||||
// add trailing /
|
// add trailing /
|
||||||
if (tmp_val[0][tmp_val[0].size() - 1] != '/')
|
if (tmp_val[0][tmp_val[0].size() - 1] != '/')
|
||||||
tmp_val[0].push_back('/');
|
tmp_val[0].push_back('/');
|
||||||
|
|||||||
@@ -3,21 +3,18 @@
|
|||||||
|
|
||||||
#include "ConfigParser.hpp"
|
#include "ConfigParser.hpp"
|
||||||
|
|
||||||
void ConfigParser::_post_processing(std::vector<ServerConfig> *servers)
|
void ConfigParser::_post_processing(std::vector<ServerConfig> *servers) const
|
||||||
{
|
{
|
||||||
std::vector<ServerConfig>::iterator it = servers->begin();
|
std::vector<ServerConfig>::iterator it = servers->begin();
|
||||||
|
|
||||||
while (it != servers->end())
|
while (it != servers->end())
|
||||||
{
|
{
|
||||||
// host and port are Mandatory
|
|
||||||
if (it->host == "")
|
if (it->host == "")
|
||||||
throw std::invalid_argument("Config file needs a host and port");
|
throw std::invalid_argument("Config file needs a host and port");
|
||||||
|
|
||||||
// root is mandatory
|
|
||||||
if (it->root == "")
|
if (it->root == "")
|
||||||
throw std::invalid_argument("Config file needs a root");
|
throw std::invalid_argument("Config file needs a root");
|
||||||
|
|
||||||
// index is mandatory in Server
|
|
||||||
if (it->index.empty())
|
if (it->index.empty())
|
||||||
throw std::invalid_argument("Config file needs an Index");
|
throw std::invalid_argument("Config file needs an Index");
|
||||||
|
|
||||||
|
|||||||
@@ -5,41 +5,36 @@
|
|||||||
#include "Webserv.hpp"
|
#include "Webserv.hpp"
|
||||||
#include "ConfigParser.hpp"
|
#include "ConfigParser.hpp"
|
||||||
|
|
||||||
|
// debug
|
||||||
|
family_state g_family;
|
||||||
|
sem_t* g_shmem;
|
||||||
|
// debug end
|
||||||
|
|
||||||
int main(int ac, char **av)
|
int main(int ac, char **av)
|
||||||
{
|
{
|
||||||
|
// debug
|
||||||
|
init_semaphore();
|
||||||
|
|
||||||
|
std::vector<ServerConfig>* servers_config = NULL;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
std::string config = (ac == 2 ? av[1] : "./default.config");
|
std::string config = (ac == 2 ? av[1] : "./default.config");
|
||||||
|
|
||||||
|
|
||||||
ConfigParser configParser(config);
|
ConfigParser configParser(config);
|
||||||
// configParser.print_content();
|
// configParser.print_content();
|
||||||
|
|
||||||
// i don't love that servers has to be a pointer...
|
servers_config = configParser.parse();
|
||||||
std::vector<ServerConfig>* servers = configParser.parse();
|
|
||||||
|
|
||||||
// use an iterator you moron
|
|
||||||
for (std::vector<ServerConfig>::iterator it = servers->begin(); it < servers->end(); it++)
|
|
||||||
{
|
|
||||||
(void)0;
|
|
||||||
// std::cout << it->server_name << " ";
|
|
||||||
// it->print_all();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Webserv serv(configParser.parse());
|
|
||||||
// is this better or worse than using
|
|
||||||
|
|
||||||
Webserv serv;
|
Webserv serv;
|
||||||
|
serv.init_virtual_servers(servers_config);
|
||||||
// serv.init_virtual_servers();
|
delete servers_config;
|
||||||
serv.init_virtual_servers(servers);
|
servers_config = NULL;
|
||||||
delete servers;
|
|
||||||
serv.run();
|
serv.run();
|
||||||
}
|
}
|
||||||
catch (std::exception& e)
|
catch (std::exception& e)
|
||||||
{
|
{
|
||||||
std::cerr << e.what() << '\n';
|
std::cerr << e.what() << '\n';
|
||||||
|
delete servers_config;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (0);
|
return (0);
|
||||||
|
|||||||
@@ -1,14 +1,6 @@
|
|||||||
|
|
||||||
#include "utils.hpp"
|
#include "utils.hpp"
|
||||||
|
|
||||||
void throw_test()
|
|
||||||
{
|
|
||||||
static int i = 0;
|
|
||||||
++i;
|
|
||||||
if (i % 8 == 0)
|
|
||||||
throw std::bad_alloc();
|
|
||||||
}
|
|
||||||
|
|
||||||
// notice : the use of getline make it such as
|
// notice : the use of getline make it such as
|
||||||
// it doesn't identify multiple delim as one :
|
// it doesn't identify multiple delim as one :
|
||||||
// " something \n else " -> 1 - something
|
// " something \n else " -> 1 - something
|
||||||
@@ -72,19 +64,6 @@ std::string trim(std::string str, char del)
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
//// trim a set of char
|
|
||||||
//std::string trim(std::string str, std::string del)
|
|
||||||
//{
|
|
||||||
// std::string new_str;
|
|
||||||
//
|
|
||||||
// while (new_str.compare(str) != 0)
|
|
||||||
// {
|
|
||||||
// for (size_t i = 0; i < del.size(); i++)
|
|
||||||
// trim(str, del[i]);
|
|
||||||
// }
|
|
||||||
// return str;
|
|
||||||
//}
|
|
||||||
|
|
||||||
std::string itos(int n)
|
std::string itos(int n)
|
||||||
{
|
{
|
||||||
std::stringstream strs;
|
std::stringstream strs;
|
||||||
@@ -93,7 +72,7 @@ std::string itos(int n)
|
|||||||
return ( strs.str() );
|
return ( strs.str() );
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isNumeric(std::string str)
|
bool is_numeric(std::string str)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < str.length(); i++)
|
for (size_t i = 0; i < str.length(); i++)
|
||||||
{
|
{
|
||||||
@@ -103,7 +82,7 @@ bool isNumeric(std::string str)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isNumeric_btw(int low, int high, std::string str)
|
bool is_numeric_btw(int low, int high, std::string str)
|
||||||
{
|
{
|
||||||
for (size_t i = 0; i < str.length(); i++)
|
for (size_t i = 0; i < str.length(); i++)
|
||||||
{
|
{
|
||||||
@@ -155,7 +134,7 @@ file_type eval_file_type(const std::string &path)
|
|||||||
{
|
{
|
||||||
struct stat s;
|
struct stat s;
|
||||||
|
|
||||||
if (stat(path.c_str(), &s) != -1)
|
if (::stat(path.c_str(), &s) != -1)
|
||||||
{
|
{
|
||||||
if (S_ISREG(s.st_mode))
|
if (S_ISREG(s.st_mode))
|
||||||
return (IS_FILE);
|
return (IS_FILE);
|
||||||
@@ -305,6 +284,15 @@ void str_map_key_tolower(std::map<std::string, std::string> & mp)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DEBUG
|
// DEBUG
|
||||||
|
|
||||||
|
void throw_test()
|
||||||
|
{
|
||||||
|
static int i = 0;
|
||||||
|
++i;
|
||||||
|
if (i % 8 == 0)
|
||||||
|
throw std::bad_alloc();
|
||||||
|
}
|
||||||
|
|
||||||
void print_special(std::string str)
|
void print_special(std::string str)
|
||||||
{
|
{
|
||||||
char c;
|
char c;
|
||||||
@@ -313,15 +301,60 @@ void print_special(std::string str)
|
|||||||
{
|
{
|
||||||
c = str[i];
|
c = str[i];
|
||||||
if (c == '\r')
|
if (c == '\r')
|
||||||
std::cout << YELLOW << "\\r" << RESET;
|
std::cerr << YELLOW << "\\r" << RESET;
|
||||||
else if (c == '\n')
|
else if (c == '\n')
|
||||||
std::cout << YELLOW << "\\n" << RESET << "\n";
|
std::cerr << YELLOW << "\\n" << RESET << "\n";
|
||||||
else
|
else
|
||||||
std::cout << c;
|
std::cerr << c;
|
||||||
fflush(stdout);
|
std::fflush(stdout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// https://stackoverflow.com/questions/5656530/how-to-use-shared-memory-with-linux-in-c
|
||||||
|
void* create_shared_memory(size_t size) {
|
||||||
|
// Our memory buffer will be readable and writable:
|
||||||
|
int protection = PROT_READ | PROT_WRITE;
|
||||||
|
|
||||||
|
// The buffer will be shared (meaning other processes can access it), but
|
||||||
|
// anonymous (meaning third-party processes cannot obtain an address for it),
|
||||||
|
// so only this process and its children will be able to use it:
|
||||||
|
int visibility = MAP_SHARED | MAP_ANONYMOUS;
|
||||||
|
|
||||||
|
// The remaining parameters to `mmap()` are not important for this use case,
|
||||||
|
// but the manpage for `mmap` explains their purpose.
|
||||||
|
return mmap(NULL, size, protection, visibility, -1, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void init_semaphore()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
g_shmem = static_cast<sem_t*>(create_shared_memory(4));
|
||||||
|
|
||||||
|
ret = sem_init(g_shmem, 1, 1);
|
||||||
|
if (ret != 0)
|
||||||
|
{
|
||||||
|
perror("err sem_init()");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_secure(std::string message)
|
||||||
|
{
|
||||||
|
sem_wait(g_shmem);
|
||||||
|
std::cerr << g_family << "| " << message;
|
||||||
|
sem_post(g_shmem);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_secure(int fd, std::string message)
|
||||||
|
{
|
||||||
|
sem_wait(g_shmem);
|
||||||
|
std::cerr << g_family << "| (" << std::setw(2) << fd << ") " << message;
|
||||||
|
sem_post(g_shmem);
|
||||||
|
}
|
||||||
|
|
||||||
|
// OVERLOADS
|
||||||
|
|
||||||
bool operator==(const listen_socket& lhs, int fd)
|
bool operator==(const listen_socket& lhs, int fd)
|
||||||
{ return lhs.fd == fd; }
|
{ return lhs.fd == fd; }
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
# include <string>
|
# include <string>
|
||||||
# include <sstream>
|
# include <sstream>
|
||||||
# include <iostream>
|
# include <iostream>
|
||||||
|
# include <iomanip> // setw
|
||||||
# include <cstdlib> // strtol, strtoul
|
# include <cstdlib> // strtol, strtoul
|
||||||
# include <climits> // LONG_MAX
|
# include <climits> // LONG_MAX
|
||||||
# include <cerrno> // errno
|
# include <cerrno> // errno
|
||||||
@@ -17,6 +18,10 @@
|
|||||||
# include <unistd.h> // close, access
|
# include <unistd.h> // close, access
|
||||||
# include "colors.h" // for debug print_special
|
# include "colors.h" // for debug print_special
|
||||||
|
|
||||||
|
// debug
|
||||||
|
# include <sys/mman.h> // mmap (for shared memory)
|
||||||
|
# include <semaphore.h> // sem_init, sem_post, sem_wait
|
||||||
|
|
||||||
# define CR "\r"
|
# define CR "\r"
|
||||||
# define LF "\n"
|
# define LF "\n"
|
||||||
# define CRLF CR LF
|
# define CRLF CR LF
|
||||||
@@ -31,6 +36,12 @@
|
|||||||
** CRLF_SIZE*2
|
** CRLF_SIZE*2
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
enum family_state
|
||||||
|
{
|
||||||
|
PARENT,
|
||||||
|
CHILD
|
||||||
|
};
|
||||||
|
|
||||||
enum file_type
|
enum file_type
|
||||||
{
|
{
|
||||||
IS_OTHER,
|
IS_OTHER,
|
||||||
@@ -45,8 +56,6 @@ enum http_method
|
|||||||
POST = 1 << 1,
|
POST = 1 << 1,
|
||||||
DELETE = 1 << 2,
|
DELETE = 1 << 2,
|
||||||
ANY_METHODS = 0b11111111,
|
ANY_METHODS = 0b11111111,
|
||||||
// ALL_METHODS = 0b11111111,
|
|
||||||
// i would prefer this...
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct listen_socket
|
struct listen_socket
|
||||||
@@ -58,10 +67,13 @@ struct listen_socket
|
|||||||
bool operator==(const listen_socket& lhs, int fd);
|
bool operator==(const listen_socket& lhs, int fd);
|
||||||
bool operator==(int fd, const listen_socket& rhs);
|
bool operator==(int fd, const listen_socket& rhs);
|
||||||
|
|
||||||
|
extern family_state g_family;
|
||||||
|
extern sem_t* g_shmem;
|
||||||
|
|
||||||
std::vector<std::string> split(std::string input, char delimiter);
|
std::vector<std::string> split(std::string input, char delimiter);
|
||||||
std::vector<std::string> split_trim(std::string input, std::string delim = "\n", char ctrim = '\0');
|
std::vector<std::string> split_trim(std::string input, std::string delim = "\n", char ctrim = '\0');
|
||||||
bool isNumeric(std::string str);
|
bool is_numeric(std::string str);
|
||||||
bool isNumeric_btw(int low, int high, std::string str);
|
bool is_numeric_btw(int low, int high, std::string str);
|
||||||
std::string itos(int n);
|
std::string itos(int n);
|
||||||
std::string trim(std::string str, char del);
|
std::string trim(std::string str, char del);
|
||||||
http_method str_to_http_method(std::string &str);
|
http_method str_to_http_method(std::string &str);
|
||||||
@@ -77,7 +89,10 @@ void str_map_key_tolower(std::map<std::string, std::string> & mp);
|
|||||||
// debug
|
// debug
|
||||||
void throw_test();
|
void throw_test();
|
||||||
void print_special(std::string str);
|
void print_special(std::string str);
|
||||||
|
void* create_shared_memory(size_t size);
|
||||||
|
void init_semaphore();
|
||||||
|
void print_secure(int fd, std::string message);
|
||||||
|
void print_secure(std::string message);
|
||||||
|
|
||||||
/* Template */
|
/* Template */
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,7 @@
|
|||||||
# include <cerrno> // errno
|
# include <cerrno> // errno
|
||||||
# include <unistd.h> // close, access
|
# include <unistd.h> // close, access
|
||||||
# include <iostream> // cout, cin
|
# include <iostream> // cout, cin
|
||||||
|
# include <iomanip> // setw
|
||||||
# include <cstring> // memset
|
# include <cstring> // memset
|
||||||
# include <sys/socket.h> // socket, accept, listen, send, recv, bind, connect, setsockopt, getsockname
|
# include <sys/socket.h> // socket, accept, listen, send, recv, bind, connect, setsockopt, getsockname
|
||||||
# include <arpa/inet.h> // htonl, htons, ntohl, ntohs, inet_addr, inet_ntoa
|
# include <arpa/inet.h> // htonl, htons, ntohl, ntohs, inet_addr, inet_ntoa
|
||||||
@@ -38,10 +39,6 @@ extern bool g_run;
|
|||||||
extern int g_last_signal;
|
extern int g_last_signal;
|
||||||
void signal_handler(int signum);
|
void signal_handler(int signum);
|
||||||
|
|
||||||
// these might only be TMP
|
|
||||||
# define FAILURE -1
|
|
||||||
# define SUCCESS 1
|
|
||||||
|
|
||||||
# define MIME_TYPE_DEFAULT "application/octet-stream"
|
# define MIME_TYPE_DEFAULT "application/octet-stream"
|
||||||
|
|
||||||
class Webserv
|
class Webserv
|
||||||
@@ -49,13 +46,7 @@ class Webserv
|
|||||||
public:
|
public:
|
||||||
// base.cpp
|
// base.cpp
|
||||||
Webserv();
|
Webserv();
|
||||||
// Webserv(Webserv const &src);
|
|
||||||
|
|
||||||
// what should it take as arg, *, &, ?
|
|
||||||
// Webserv(std::vector<ServerConfig>& servers);
|
|
||||||
|
|
||||||
~Webserv();
|
~Webserv();
|
||||||
// Webserv &operator=(Webserv const &rhs);
|
|
||||||
|
|
||||||
// init.cpp
|
// init.cpp
|
||||||
void init_virtual_servers(std::vector<ServerConfig>* servers);
|
void init_virtual_servers(std::vector<ServerConfig>* servers);
|
||||||
@@ -105,11 +96,10 @@ class Webserv
|
|||||||
void _handle_last_signal();
|
void _handle_last_signal();
|
||||||
// close.cpp
|
// close.cpp
|
||||||
void _close_client(int fd);
|
void _close_client(int fd);
|
||||||
|
void _close_client_cgi_pipes(Client *client);
|
||||||
void _close_all_clients();
|
void _close_all_clients();
|
||||||
void _close_all_clients_fd();
|
void _close_all_clients_fd();
|
||||||
void _close_all_clients_cgi_fd();
|
void _close_all_clients_cgi_pipes();
|
||||||
void _close_cgi_pipe_rfd(int fd);
|
|
||||||
void _close_all_cgi_pipe_rfd();
|
|
||||||
void _close_all_listen_sockets();
|
void _close_all_listen_sockets();
|
||||||
void _reopen_lsocket(std::vector<listen_socket>::iterator it);
|
void _reopen_lsocket(std::vector<listen_socket>::iterator it);
|
||||||
void _handle_epoll_error_lsocket(uint32_t events, std::vector<listen_socket>::iterator it);
|
void _handle_epoll_error_lsocket(uint32_t events, std::vector<listen_socket>::iterator it);
|
||||||
@@ -124,6 +114,8 @@ class Webserv
|
|||||||
// cgi.cpp
|
// cgi.cpp
|
||||||
bool _is_cgi(Client *client, std::string path);
|
bool _is_cgi(Client *client, std::string path);
|
||||||
size_t _cgi_pos(Client *client, std::string &path, size_t pos);
|
size_t _cgi_pos(Client *client, std::string &path, size_t pos);
|
||||||
|
void _cgi_open_pipes(Client *client);
|
||||||
|
void _write_body_to_cgi(Client *client);
|
||||||
void _exec_cgi(Client *client);
|
void _exec_cgi(Client *client);
|
||||||
void _set_env_vector(Client *client, std::vector<std::string> &env_vector);
|
void _set_env_vector(Client *client, std::vector<std::string> &env_vector);
|
||||||
void _set_env_cstr(char *env_cstr[], std::vector<std::string> &env_vector);
|
void _set_env_cstr(char *env_cstr[], std::vector<std::string> &env_vector);
|
||||||
@@ -132,15 +124,19 @@ class Webserv
|
|||||||
void _exec_script(Client *client, char *env[]);
|
void _exec_script(Client *client, char *env[]);
|
||||||
void _check_script_output(Client *client, std::string & output);
|
void _check_script_output(Client *client, std::string & output);
|
||||||
void _check_script_status(Client *client, std::string & output);
|
void _check_script_status(Client *client, std::string & output);
|
||||||
size_t _check_script_fields(const std::string & output, size_t status);
|
unsigned int
|
||||||
|
_check_script_fields(const std::string & output, unsigned int status);
|
||||||
void _check_fields_duplicates(Client *client, std::string & output);
|
void _check_fields_duplicates(Client *client, std::string & output);
|
||||||
void _add_script_body_length_header(std::string & output);
|
void _add_script_body_length_header(std::string & output);
|
||||||
void _remove_body_leading_empty_lines(std::string & output);
|
void _remove_body_leading_empty_lines(std::string & output);
|
||||||
|
// cgi_epoll.cpp
|
||||||
Client *_find_cgi_fd(int cgi_fd);
|
|
||||||
void _read_cgi_output(Client *client);
|
void _read_cgi_output(Client *client);
|
||||||
void _handle_epoll_error_cgi_fd(uint32_t events, Client *client);
|
void _handle_epollerr_cgi_output(uint32_t events, Client *client);
|
||||||
void _cgi_epollhup(uint32_t events, Client *client);
|
void _handle_epollhup_cgi_output(uint32_t events, Client *client);
|
||||||
|
void _cgi_input_ready(Client *client);
|
||||||
|
void _handle_epollerr_cgi_input(uint32_t events, Client *client);
|
||||||
|
Client *_find_cgi_output_fd(int fd);
|
||||||
|
Client *_find_cgi_input_fd(int fd);
|
||||||
|
|
||||||
|
|
||||||
///////////////////////
|
///////////////////////
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ void Webserv::_accept_connection(listen_socket &lsocket)
|
|||||||
int accepted_fd;
|
int accepted_fd;
|
||||||
std::map<std::string, std::string> infos;
|
std::map<std::string, std::string> infos;
|
||||||
|
|
||||||
std::cerr << "accept()\n";
|
print_secure(" accept() socket (" + ::itos(lsocket.fd) + ")\n");
|
||||||
addr_len = sizeof addr;
|
addr_len = sizeof addr;
|
||||||
accepted_fd = ::accept(lsocket.fd, (sockaddr*)&addr, &addr_len);
|
accepted_fd = ::accept(lsocket.fd, (sockaddr*)&addr, &addr_len);
|
||||||
if (accepted_fd == -1)
|
if (accepted_fd == -1)
|
||||||
@@ -18,7 +18,12 @@ void Webserv::_accept_connection(listen_socket &lsocket)
|
|||||||
_handle_last_signal();
|
_handle_last_signal();
|
||||||
return ;
|
return ;
|
||||||
}
|
}
|
||||||
::fcntl(accepted_fd, F_SETFL, O_NONBLOCK);
|
if (::fcntl(accepted_fd, F_SETFL, O_NONBLOCK) == -1)
|
||||||
|
{
|
||||||
|
std::perror("err fcntl()");
|
||||||
|
if (::close(accepted_fd) == -1)
|
||||||
|
std::perror("err close()");
|
||||||
|
}
|
||||||
|
|
||||||
infos = _extract_infos(addr);
|
infos = _extract_infos(addr);
|
||||||
Client new_client(accepted_fd, &lsocket, infos["port"], infos["ip"]);
|
Client new_client(accepted_fd, &lsocket, infos["port"], infos["ip"]);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ Webserv::Webserv()
|
|||||||
{
|
{
|
||||||
std::cerr << "Server init\n";
|
std::cerr << "Server init\n";
|
||||||
|
|
||||||
_epfd = ::epoll_create1(0); // (EPOLL_CLOEXEC) for CGI fork ?
|
_epfd = ::epoll_create1(EPOLL_CLOEXEC);
|
||||||
if (_epfd == -1)
|
if (_epfd == -1)
|
||||||
{
|
{
|
||||||
std::perror("err epoll_create1()");
|
std::perror("err epoll_create1()");
|
||||||
@@ -19,30 +19,6 @@ Webserv::Webserv()
|
|||||||
std::signal(SIGINT, signal_handler);
|
std::signal(SIGINT, signal_handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Webserv::Webserv(Webserv const &src)
|
|
||||||
{
|
|
||||||
|
|
||||||
} */
|
|
||||||
|
|
||||||
// we'll come back to this
|
|
||||||
/*
|
|
||||||
Webserv::Webserv(std::vector<ServerConfig>* servers)
|
|
||||||
: _servers(servers)
|
|
||||||
{
|
|
||||||
// talk to luke about what all this does
|
|
||||||
// the Param Constructor might need to do dif stuff
|
|
||||||
std::cout << "Server init\n";
|
|
||||||
|
|
||||||
_epfd = ::epoll_create1(0); // (EPOLL_CLOEXEC) for CGI fork ?
|
|
||||||
if (_epfd == -1)
|
|
||||||
{
|
|
||||||
std::perror("err epoll_create1(): ");
|
|
||||||
throw std::runtime_error("Epoll init");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
Webserv::~Webserv()
|
Webserv::~Webserv()
|
||||||
{
|
{
|
||||||
close(_epfd);
|
close(_epfd);
|
||||||
@@ -50,8 +26,3 @@ Webserv::~Webserv()
|
|||||||
_close_all_listen_sockets();
|
_close_all_listen_sockets();
|
||||||
std::cerr << "Server destroyed\n";
|
std::cerr << "Server destroyed\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Webserv & Webserv::operator=(Webserv const &rhs)
|
|
||||||
{
|
|
||||||
|
|
||||||
} */
|
|
||||||
|
|||||||
@@ -9,12 +9,14 @@ bool Webserv::_is_cgi(Client *client, std::string path)
|
|||||||
{
|
{
|
||||||
std::string script_path;
|
std::string script_path;
|
||||||
size_t file_type;
|
size_t file_type;
|
||||||
size_t file_mode = client->status;
|
size_t file_access = client->status;
|
||||||
size_t pos = 0;
|
size_t pos = 0;
|
||||||
|
|
||||||
|
print_secure(client->get_cl_fd(), "....._is_cgi()\n");
|
||||||
while (pos != NPOS)
|
while (pos != NPOS)
|
||||||
{
|
{
|
||||||
pos = _cgi_pos(client, path, pos);
|
pos = _cgi_pos(client, path, pos);
|
||||||
|
print_secure(client->get_cl_fd(), "....>_is_cgi()\n");
|
||||||
if (pos == NPOS)
|
if (pos == NPOS)
|
||||||
break;
|
break;
|
||||||
client->fill_script_path(path, pos);
|
client->fill_script_path(path, pos);
|
||||||
@@ -24,13 +26,13 @@ bool Webserv::_is_cgi(Client *client, std::string path)
|
|||||||
continue;
|
continue;
|
||||||
if (file_type == IS_FILE)
|
if (file_type == IS_FILE)
|
||||||
{
|
{
|
||||||
file_mode = ::eval_file_access( script_path, X_OK );
|
file_access = ::eval_file_access( script_path, X_OK );
|
||||||
if (!file_mode)
|
if (!file_access)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
client->clear_script();
|
client->clear_script();
|
||||||
client->status = file_mode; // 404 not_found OR 403 forbidden
|
client->status = file_access; // 404 not_found OR 403 forbidden
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,6 +44,7 @@ size_t Webserv::_cgi_pos(Client *client, std::string &path, size_t pos)
|
|||||||
size_t len;
|
size_t len;
|
||||||
std::locale loc; // for isalpha()
|
std::locale loc; // for isalpha()
|
||||||
|
|
||||||
|
print_secure(client->get_cl_fd(), "....._cgi_pos()\n");
|
||||||
v_ext = client->assigned_location->cgi_ext;
|
v_ext = client->assigned_location->cgi_ext;
|
||||||
if (v_ext.empty())
|
if (v_ext.empty())
|
||||||
return NPOS;
|
return NPOS;
|
||||||
@@ -66,6 +69,60 @@ size_t Webserv::_cgi_pos(Client *client, std::string &path, size_t pos)
|
|||||||
return NPOS;
|
return NPOS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Webserv::_cgi_open_pipes(Client *client)
|
||||||
|
{
|
||||||
|
#define R 0
|
||||||
|
#define W 1
|
||||||
|
int pipe_fd[2];
|
||||||
|
|
||||||
|
print_secure(client->get_cl_fd(), "....._cgi_open_pipes()\n");
|
||||||
|
if (::pipe(pipe_fd) == -1)
|
||||||
|
{
|
||||||
|
std::perror("err pipe");
|
||||||
|
client->status = 500;
|
||||||
|
}
|
||||||
|
client->cgi_pipe_r_from_parent = pipe_fd[R];
|
||||||
|
print_secure(client->get_cl_fd(), "open pipe rfp [" + ::itos(client->cgi_pipe_r_from_parent) + "]\n");
|
||||||
|
client->cgi_pipe_w_to_child = pipe_fd[W];
|
||||||
|
print_secure(client->get_cl_fd(), "open pipe wtc [" + ::itos(client->cgi_pipe_w_to_child) + "]\n");
|
||||||
|
|
||||||
|
if (::pipe(pipe_fd) == -1)
|
||||||
|
{
|
||||||
|
std::perror("err pipe");
|
||||||
|
if (::close(client->cgi_pipe_r_from_parent) == -1)
|
||||||
|
std::perror("err close()");
|
||||||
|
if (::close(client->cgi_pipe_w_to_child) == -1)
|
||||||
|
std::perror("err close()");
|
||||||
|
client->status = 500;
|
||||||
|
}
|
||||||
|
client->cgi_pipe_r_from_child = pipe_fd[R];
|
||||||
|
print_secure(client->get_cl_fd(), "open pipe rfc [" + ::itos(client->cgi_pipe_r_from_child) + "]\n");
|
||||||
|
client->cgi_pipe_w_to_parent = pipe_fd[W];
|
||||||
|
print_secure(client->get_cl_fd(), "open pipe wtp [" + ::itos(client->cgi_pipe_w_to_parent) + "]\n");
|
||||||
|
|
||||||
|
// epoll add for writing body to child
|
||||||
|
_epoll_update(client->cgi_pipe_w_to_child, EPOLLOUT, EPOLL_CTL_ADD);
|
||||||
|
// stop monitoring client->fd until we can write body
|
||||||
|
_epoll_update(client->get_cl_fd(), 0, EPOLL_CTL_DEL);
|
||||||
|
client->cgi_state = CGI_WAIT_TO_EXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Webserv::_write_body_to_cgi(Client *client)
|
||||||
|
{
|
||||||
|
ssize_t ret;
|
||||||
|
std::string body = client->get_rq_body();
|
||||||
|
|
||||||
|
print_secure(client->get_cl_fd(), "....._write_body_to_cgi()\n");
|
||||||
|
ret = ::write(client->cgi_pipe_w_to_child, body.c_str(), body.size());
|
||||||
|
if (ret == -1)
|
||||||
|
{
|
||||||
|
std::perror("err write()");
|
||||||
|
_close_client_cgi_pipes(client);
|
||||||
|
client->status = 500;
|
||||||
|
client->cgi_state = CGI_NO_CGI;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Webserv::_exec_cgi(Client *client)
|
void Webserv::_exec_cgi(Client *client)
|
||||||
{
|
{
|
||||||
char* env_cstr[19] = {NULL};
|
char* env_cstr[19] = {NULL};
|
||||||
@@ -73,6 +130,7 @@ void Webserv::_exec_cgi(Client *client)
|
|||||||
env_vector.reserve(18);
|
env_vector.reserve(18);
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
|
print_secure(client->get_cl_fd(), "....._exec_cgi()\n");
|
||||||
_set_env_vector(client, env_vector);
|
_set_env_vector(client, env_vector);
|
||||||
try {
|
try {
|
||||||
_set_env_cstr(env_cstr, env_vector);
|
_set_env_cstr(env_cstr, env_vector);
|
||||||
@@ -108,25 +166,25 @@ std::string Webserv::_dup_env(std::string var, int i)
|
|||||||
return (str);
|
return (str);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO : verifier que les variables sont corrects
|
|
||||||
/*
|
/*
|
||||||
https://www.rfc-editor.org/rfc/rfc3875#section-4.1
|
https://www.rfc-editor.org/rfc/rfc3875#section-4.1
|
||||||
*/
|
*/
|
||||||
void Webserv::_set_env_vector(Client *client, std::vector<std::string> &env_vector)
|
void Webserv::_set_env_vector(Client *client, std::vector<std::string> &env_vector)
|
||||||
{
|
{
|
||||||
env_vector.push_back(_dup_env("AUTH_TYPE")); // authentification not supporte
|
print_secure(client->get_cl_fd(), "....._set_env_vector()\n");
|
||||||
|
env_vector.push_back(_dup_env("AUTH_TYPE")); // authentification not supported
|
||||||
env_vector.push_back(_dup_env("CONTENT_LENGTH" , client->get_rq_body().size()));
|
env_vector.push_back(_dup_env("CONTENT_LENGTH" , client->get_rq_body().size()));
|
||||||
env_vector.push_back(_dup_env("CONTENT_TYPE" , client->get_rq_headers("Content-Type")));
|
env_vector.push_back(_dup_env("CONTENT_TYPE" , client->get_rq_headers("Content-Type")));
|
||||||
env_vector.push_back(_dup_env("GATEWAY_INTERFACE" , "CGI/1.1")); // https://www.rfc-editor.org/rfc/rfc3875#section-4.1.4
|
env_vector.push_back(_dup_env("GATEWAY_INTERFACE" , "CGI/1.1")); // https://www.rfc-editor.org/rfc/rfc3875#section-4.1.4
|
||||||
env_vector.push_back(_dup_env("PATH_INFO" , client->get_rq_script_info())); // LUKE: To Check
|
env_vector.push_back(_dup_env("PATH_INFO" , client->get_rq_script_info()));
|
||||||
env_vector.push_back(_dup_env("PATH_TRANSLATED")); // not supported // LUKE: Why not supported ?
|
env_vector.push_back(_dup_env("PATH_TRANSLATED")); // not used
|
||||||
env_vector.push_back(_dup_env("QUERY_STRING" , client->get_rq_query()));
|
env_vector.push_back(_dup_env("QUERY_STRING" , client->get_rq_query()));
|
||||||
env_vector.push_back(_dup_env("REMOTE_ADDR" , client->get_cl_ip()));
|
env_vector.push_back(_dup_env("REMOTE_ADDR" , client->get_cl_ip()));
|
||||||
env_vector.push_back(_dup_env("REMOTE_HOST" , client->get_cl_ip())); // equal to REMOTE_ADDR or empty
|
env_vector.push_back(_dup_env("REMOTE_HOST" , client->get_cl_ip())); // equal to REMOTE_ADDR or empty
|
||||||
env_vector.push_back(_dup_env("REMOTE_IDENT")); // authentification not supported
|
env_vector.push_back(_dup_env("REMOTE_IDENT")); // authentification not supported
|
||||||
env_vector.push_back(_dup_env("REMOTE_USER")); // authentification not supported
|
env_vector.push_back(_dup_env("REMOTE_USER")); // authentification not supported
|
||||||
env_vector.push_back(_dup_env("REQUEST_METHOD" , client->get_rq_method_str()));
|
env_vector.push_back(_dup_env("REQUEST_METHOD" , client->get_rq_method_str()));
|
||||||
env_vector.push_back(_dup_env("SCRIPT_NAME" , "/" + client->get_rq_script_path())); // LUKE: To Check
|
env_vector.push_back(_dup_env("SCRIPT_NAME" , "/" + client->get_rq_script_path()));
|
||||||
env_vector.push_back(_dup_env("SERVER_NAME" , client->get_cl_lsocket()->host));
|
env_vector.push_back(_dup_env("SERVER_NAME" , client->get_cl_lsocket()->host));
|
||||||
env_vector.push_back(_dup_env("SERVER_PORT" , client->get_cl_lsocket()->port));
|
env_vector.push_back(_dup_env("SERVER_PORT" , client->get_cl_lsocket()->port));
|
||||||
env_vector.push_back(_dup_env("SERVER_PROTOCOL" , "HTTP/1.1"));
|
env_vector.push_back(_dup_env("SERVER_PROTOCOL" , "HTTP/1.1"));
|
||||||
@@ -139,6 +197,7 @@ void Webserv::_set_env_cstr(char *env_cstr[], std::vector<std::string> &env_vect
|
|||||||
std::vector<std::string>::const_iterator it = env_vector.begin();
|
std::vector<std::string>::const_iterator it = env_vector.begin();
|
||||||
std::vector<std::string>::const_iterator it_end = env_vector.end();
|
std::vector<std::string>::const_iterator it_end = env_vector.end();
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
while (it != it_end)
|
while (it != it_end)
|
||||||
{
|
{
|
||||||
env_cstr[i] = new char[it->size()+1];
|
env_cstr[i] = new char[it->size()+1];
|
||||||
@@ -152,87 +211,90 @@ void Webserv::_set_env_cstr(char *env_cstr[], std::vector<std::string> &env_vect
|
|||||||
|
|
||||||
void Webserv::_exec_script(Client *client, char *env[])
|
void Webserv::_exec_script(Client *client, char *env[])
|
||||||
{
|
{
|
||||||
#define RD 0
|
|
||||||
#define WR 1
|
|
||||||
#define FD_WR_TO_CHLD fd_in[WR]
|
|
||||||
#define FD_WR_TO_PRNT fd_out[WR]
|
|
||||||
#define FD_RD_FR_CHLD fd_out[RD]
|
|
||||||
#define FD_RD_FR_PRNT fd_in[RD]
|
|
||||||
|
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
char * const nll[1] = {NULL};
|
char * const nll[1] = {NULL};
|
||||||
std::string script_output;
|
|
||||||
std::string body = client->get_rq_body();
|
|
||||||
int fd_in[2];
|
|
||||||
int fd_out[2];
|
|
||||||
std::string path;
|
std::string path;
|
||||||
|
|
||||||
::pipe(fd_in);
|
print_secure(client->get_cl_fd(), "....._exec_script()\n");
|
||||||
::pipe(fd_out);
|
// pid = 1; // DEBUG, if no fork, no problem
|
||||||
|
|
||||||
pid = fork();
|
pid = fork();
|
||||||
|
print_secure(client->get_cl_fd(), "fork()\n");
|
||||||
if (pid == -1)
|
if (pid == -1)
|
||||||
|
{
|
||||||
std::perror("err fork()");
|
std::perror("err fork()");
|
||||||
|
client->status = 500;
|
||||||
|
_close_client_cgi_pipes(client);
|
||||||
|
}
|
||||||
else if (pid == 0) // child
|
else if (pid == 0) // child
|
||||||
{
|
{
|
||||||
std::signal(SIGPIPE, SIG_DFL);
|
std::signal(SIGPIPE, SIG_DFL);
|
||||||
std::signal(SIGINT, SIG_DFL);
|
std::signal(SIGINT, SIG_DFL);
|
||||||
|
g_family = CHILD;
|
||||||
|
|
||||||
|
if (dup2(client->cgi_pipe_r_from_parent, STDIN_FILENO) == -1)
|
||||||
|
{
|
||||||
|
std::perror("err dup2() STDIN_FILENO");
|
||||||
|
throw ExecFail();
|
||||||
|
}
|
||||||
|
if (dup2(client->cgi_pipe_w_to_parent, STDOUT_FILENO) == -1)
|
||||||
|
{
|
||||||
|
std::perror("err dup2() STDOUT_FILENO");
|
||||||
|
if (::close(STDIN_FILENO) == -1) // Valgind debug, not essential
|
||||||
|
std::perror("err close");
|
||||||
|
throw ExecFail();
|
||||||
|
}
|
||||||
|
|
||||||
_close_all_clients_fd();
|
_close_all_clients_fd();
|
||||||
::close(_epfd);
|
|
||||||
::close(FD_WR_TO_CHLD);
|
|
||||||
::close(FD_RD_FR_CHLD);
|
|
||||||
if (dup2(FD_RD_FR_PRNT, STDIN_FILENO) == -1)
|
|
||||||
{
|
|
||||||
std::perror("err dup2()");
|
|
||||||
::close(FD_RD_FR_PRNT); // Valgind debug, not essential
|
|
||||||
::close(FD_WR_TO_PRNT); // Valgind debug, not essential
|
|
||||||
throw ExecFail();
|
|
||||||
}
|
|
||||||
if (dup2(FD_WR_TO_PRNT, STDOUT_FILENO) == -1)
|
|
||||||
{
|
|
||||||
std::perror("err dup2()");
|
|
||||||
::close(FD_RD_FR_PRNT); // Valgind debug, not essential
|
|
||||||
::close(FD_WR_TO_PRNT); // Valgind debug, not essential
|
|
||||||
throw ExecFail();
|
|
||||||
}
|
|
||||||
|
|
||||||
::close(FD_RD_FR_PRNT);
|
path = client->get_rq_script_path();
|
||||||
::close(FD_WR_TO_PRNT);
|
print_secure(client->get_cl_fd(), "execve:[" + path + "]\n");
|
||||||
|
|
||||||
path = client->get_rq_script_path(); // Wut ? Only relative path ?
|
|
||||||
/*DEBUG*/std::cerr << "execve:[" << path << "]\n";
|
|
||||||
if (::execve(path.c_str(), nll, env) == -1) // replace path for debug error forcing
|
if (::execve(path.c_str(), nll, env) == -1) // replace path for debug error forcing
|
||||||
{
|
{
|
||||||
std::perror("err execve()");
|
std::perror("err execve()");
|
||||||
::close(STDIN_FILENO); // Valgind debug, not essential
|
if (::close(STDIN_FILENO) == -1) // Valgind debug, not essential
|
||||||
::close(STDOUT_FILENO); // Valgind debug, not essential
|
std::perror("err close");
|
||||||
|
if (::close(STDOUT_FILENO) == -1) // Valgind debug, not essential
|
||||||
|
std::perror("err close");
|
||||||
throw ExecFail();
|
throw ExecFail();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else //parent
|
else //parent
|
||||||
{
|
{
|
||||||
::close(FD_RD_FR_PRNT);
|
//usleep(1 * 10000);
|
||||||
::close(FD_WR_TO_PRNT);
|
|
||||||
::write(FD_WR_TO_CHLD, body.c_str(), body.size()); // move this before the fork ?
|
|
||||||
::close(FD_WR_TO_CHLD);
|
|
||||||
|
|
||||||
// add FD_RD_FR_CHLD to epoll,
|
print_secure(client->get_cl_fd(), "close pipe rfp [" + ::itos(client->cgi_pipe_r_from_parent) + "]\n");
|
||||||
_epoll_update(FD_RD_FR_CHLD, EPOLLIN, EPOLL_CTL_ADD);
|
if (::close(client->cgi_pipe_r_from_parent) == -1)
|
||||||
|
std::perror("err close");
|
||||||
|
client->cgi_pipe_r_from_parent = -1;
|
||||||
|
|
||||||
|
print_secure(client->get_cl_fd(), "close pipe wtp [" + ::itos(client->cgi_pipe_w_to_parent) + "]\n");
|
||||||
|
if (::close(client->cgi_pipe_w_to_parent) == -1)
|
||||||
|
std::perror("err close");
|
||||||
|
client->cgi_pipe_w_to_parent = -1;
|
||||||
|
|
||||||
|
print_secure(client->get_cl_fd(), "close pipe wtc [" + ::itos(client->cgi_pipe_w_to_child) + "]\n");
|
||||||
|
if (::close(client->cgi_pipe_w_to_child) == -1)
|
||||||
|
std::perror("err close");
|
||||||
|
client->cgi_pipe_w_to_child = -1;
|
||||||
|
|
||||||
|
// add client->cgi_pipe_r_from_child to epoll,
|
||||||
|
_epoll_update(client->cgi_pipe_r_from_child, EPOLLIN, EPOLL_CTL_ADD);
|
||||||
// stop monitoring client->fd until the cgi-script as done is job
|
// stop monitoring client->fd until the cgi-script as done is job
|
||||||
_epoll_update(client->get_cl_fd(), 0, EPOLL_CTL_DEL);
|
_epoll_update(client->get_cl_fd(), 0, EPOLL_CTL_DEL);
|
||||||
|
|
||||||
client->cgi_pipe_rfd = FD_RD_FR_CHLD;
|
|
||||||
client->cgi_pid = pid;
|
client->cgi_pid = pid;
|
||||||
|
client->cgi_state = CGI_OUTPUT_READING;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#define STATUS_500 std::string("Status: 500" CRLF CRLF);
|
|
||||||
|
|
||||||
void Webserv::_check_script_output(Client *client, std::string & output)
|
void Webserv::_check_script_output(Client *client, std::string & output)
|
||||||
{
|
{
|
||||||
size_t pos;
|
size_t pos;
|
||||||
pos = client->cgi_output.find(CRLF CRLF);
|
pos = client->cgi_output.find(CRLF CRLF);
|
||||||
|
|
||||||
|
print_secure(client->get_cl_fd(), "....._check_script_output()\n");
|
||||||
if (pos == 0 || pos == NPOS)
|
if (pos == 0 || pos == NPOS)
|
||||||
{
|
{
|
||||||
client->status = 500;;
|
client->status = 500;;
|
||||||
@@ -241,14 +303,10 @@ void Webserv::_check_script_output(Client *client, std::string & output)
|
|||||||
_check_script_status(client, output);
|
_check_script_status(client, output);
|
||||||
if (client->status >= 400 && client->status < 600)
|
if (client->status >= 400 && client->status < 600)
|
||||||
return;
|
return;
|
||||||
//*DEBUG*/ std::cout << "\n" B_PURPLE "[script status]:" RESET "\n"; ::print_special(output); std::cout << B_PURPLE "-----------" RESET "\n\n";
|
|
||||||
client->status = _check_script_fields(output, client->status);
|
client->status = _check_script_fields(output, client->status);
|
||||||
_check_fields_duplicates(client, output);
|
_check_fields_duplicates(client, output);
|
||||||
//*DEBUG*/ std::cout << "\n" B_PURPLE "[script fields]:" RESET "\n"; ::print_special(output); std::cout << B_PURPLE "-----------" RESET "\n\n";
|
|
||||||
_remove_body_leading_empty_lines(output);
|
_remove_body_leading_empty_lines(output);
|
||||||
//*DEBUG*/ std::cout << "\n" B_PURPLE "[script empty lines]:" RESET "\n"; ::print_special(output); std::cout << B_PURPLE "-----------" RESET "\n\n";
|
|
||||||
_add_script_body_length_header(output);
|
_add_script_body_length_header(output);
|
||||||
//*DEBUG*/ std::cout << "\n" B_PURPLE "[script content length]:" RESET "\n"; ::print_special(output); std::cout << B_PURPLE "-----------" RESET "\n\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Webserv::_check_script_status(Client *client, std::string & output)
|
void Webserv::_check_script_status(Client *client, std::string & output)
|
||||||
@@ -256,6 +314,7 @@ void Webserv::_check_script_status(Client *client, std::string & output)
|
|||||||
size_t pos;
|
size_t pos;
|
||||||
int status_pos;
|
int status_pos;
|
||||||
|
|
||||||
|
print_secure(client->get_cl_fd(), "....._check_script_status()\n");
|
||||||
pos = output.find("Status:");
|
pos = output.find("Status:");
|
||||||
if (pos != NPOS)
|
if (pos != NPOS)
|
||||||
{
|
{
|
||||||
@@ -267,7 +326,7 @@ void Webserv::_check_script_status(Client *client, std::string & output)
|
|||||||
client->status = 200;
|
client->status = 200;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t Webserv::_check_script_fields(const std::string & output, size_t status)
|
unsigned int Webserv::_check_script_fields(const std::string & output, unsigned int status)
|
||||||
{
|
{
|
||||||
std::string headers;
|
std::string headers;
|
||||||
std::string body;
|
std::string body;
|
||||||
@@ -304,6 +363,7 @@ void Webserv::_check_fields_duplicates(Client *client, std::string & output)
|
|||||||
std::string tmp;
|
std::string tmp;
|
||||||
size_t pos;
|
size_t pos;
|
||||||
|
|
||||||
|
print_secure(client->get_cl_fd(), "....._check_fields_duplicates()\n");
|
||||||
// put server headers in map
|
// put server headers in map
|
||||||
tmp = client->response;
|
tmp = client->response;
|
||||||
pos = tmp.find(CRLF CRLF);
|
pos = tmp.find(CRLF CRLF);
|
||||||
@@ -384,4 +444,3 @@ void Webserv::_add_script_body_length_header(std::string & output)
|
|||||||
tmp += CRLF;
|
tmp += CRLF;
|
||||||
output.insert(0, tmp);
|
output.insert(0, tmp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
110
srcs/webserv/cgi_epoll.cpp
Normal file
110
srcs/webserv/cgi_epoll.cpp
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
|
||||||
|
#include "Webserv.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
#define BUFSIZE 8192 // (8Ko)
|
||||||
|
void Webserv::_read_cgi_output(Client *client)
|
||||||
|
{
|
||||||
|
char buf[BUFSIZE];
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
|
ret = ::read(client->cgi_pipe_r_from_child, buf, BUFSIZE);
|
||||||
|
if (ret == -1)
|
||||||
|
{
|
||||||
|
std::perror("err read(cgi_fd)");
|
||||||
|
client->status = 500;
|
||||||
|
client->cgi_state = CGI_NO_CGI;
|
||||||
|
}
|
||||||
|
else if (ret == 0)
|
||||||
|
std::cerr << "Madame s'il vous plait, du Ketchup pour mon hamburger" << " (AKA:ret=0)" << "\n"; // :)
|
||||||
|
else
|
||||||
|
client->cgi_output.append(buf, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Webserv::_handle_epollerr_cgi_output(uint32_t events, Client *client)
|
||||||
|
{
|
||||||
|
(void)events;
|
||||||
|
|
||||||
|
client->status = 500;
|
||||||
|
client->cgi_state = CGI_NO_CGI;
|
||||||
|
|
||||||
|
// Common with EPOLLHUP
|
||||||
|
pid_t wait_ret;
|
||||||
|
wait_ret = ::waitpid(client->cgi_pid, NULL, WNOHANG);
|
||||||
|
if (wait_ret == client->cgi_pid)
|
||||||
|
{
|
||||||
|
_epoll_update(client->cgi_pipe_r_from_child, 0, EPOLL_CTL_DEL);
|
||||||
|
|
||||||
|
print_secure(client->get_cl_fd(), "close pipe rfc [" + ::itos(client->cgi_pipe_r_from_child) + "]\n");
|
||||||
|
if (::close(client->cgi_pipe_r_from_child) == -1)
|
||||||
|
std::perror("err close()");
|
||||||
|
client->cgi_pipe_r_from_child = -1;
|
||||||
|
|
||||||
|
_epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Webserv::_handle_epollhup_cgi_output(uint32_t events, Client *client)
|
||||||
|
{
|
||||||
|
(void)events;
|
||||||
|
|
||||||
|
// Common with EPOLLERR
|
||||||
|
pid_t wait_ret;
|
||||||
|
wait_ret = ::waitpid(client->cgi_pid, NULL, WNOHANG);
|
||||||
|
if (wait_ret == client->cgi_pid)
|
||||||
|
{
|
||||||
|
_epoll_update(client->cgi_pipe_r_from_child, 0, EPOLL_CTL_DEL);
|
||||||
|
|
||||||
|
print_secure(client->get_cl_fd(), "close pipe rfc [" + ::itos(client->cgi_pipe_r_from_child) + "]\n");
|
||||||
|
if (::close(client->cgi_pipe_r_from_child) == -1)
|
||||||
|
std::perror("err close()");
|
||||||
|
client->cgi_pipe_r_from_child = -1;
|
||||||
|
|
||||||
|
_epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD);
|
||||||
|
client->cgi_state = CGI_OUTPUT_COMPLETE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Webserv::_cgi_input_ready(Client *client)
|
||||||
|
{
|
||||||
|
client->cgi_state = CGI_READY_TO_EXEC;
|
||||||
|
_epoll_update(client->cgi_pipe_w_to_child, 0, EPOLL_CTL_DEL);
|
||||||
|
_epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Webserv::_handle_epollerr_cgi_input(uint32_t events, Client *client)
|
||||||
|
{
|
||||||
|
(void)events;
|
||||||
|
|
||||||
|
client->status = 500;
|
||||||
|
client->cgi_state = CGI_NO_CGI;
|
||||||
|
_close_client_cgi_pipes(client);
|
||||||
|
_epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD);
|
||||||
|
}
|
||||||
|
|
||||||
|
Client *Webserv::_find_cgi_output_fd(int fd)
|
||||||
|
{
|
||||||
|
std::vector<Client>::iterator it = _clients.begin();
|
||||||
|
std::vector<Client>::iterator it_end = _clients.end();
|
||||||
|
while (it != it_end)
|
||||||
|
{
|
||||||
|
if (it->cgi_pipe_r_from_child == fd)
|
||||||
|
return (&(*it));
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
Client *Webserv::_find_cgi_input_fd(int fd)
|
||||||
|
{
|
||||||
|
std::vector<Client>::iterator it = _clients.begin();
|
||||||
|
std::vector<Client>::iterator it_end = _clients.end();
|
||||||
|
while (it != it_end)
|
||||||
|
{
|
||||||
|
if (it->cgi_pipe_w_to_child == fd)
|
||||||
|
return (&(*it));
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
@@ -9,10 +9,10 @@ void Webserv::_close_client(int fd)
|
|||||||
{
|
{
|
||||||
if (*it == fd)
|
if (*it == fd)
|
||||||
{
|
{
|
||||||
// _epoll_update(fd, 0, EPOLL_CTL_DEL); // normalement superflu, DEBUG
|
print_secure(it->get_cl_fd(), "close client fd " + ::itos(fd) + "\n");
|
||||||
std::cerr << "close fd " << fd << "\n";
|
|
||||||
if (::close(fd) == -1)
|
if (::close(fd) == -1)
|
||||||
std::perror("err close()");
|
std::perror("err close()");
|
||||||
|
_close_client_cgi_pipes(&(*it));
|
||||||
_clients.erase(it);
|
_clients.erase(it);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -20,6 +20,36 @@ void Webserv::_close_client(int fd)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Webserv::_close_client_cgi_pipes(Client *client)
|
||||||
|
{
|
||||||
|
if (client->cgi_state)
|
||||||
|
{ // No need to reset the fd to -1 normaly
|
||||||
|
print_secure(client->get_cl_fd(), "close pipe wtc [" + ::itos(client->cgi_pipe_w_to_child) + "]\n");
|
||||||
|
if (client->cgi_pipe_w_to_child != -1)
|
||||||
|
if (::close(client->cgi_pipe_w_to_child) == -1)
|
||||||
|
std::perror("err close()");
|
||||||
|
client->cgi_pipe_w_to_child = -1;
|
||||||
|
|
||||||
|
print_secure(client->get_cl_fd(), "close pipe rfc [" + ::itos(client->cgi_pipe_r_from_child) + "]\n");
|
||||||
|
if (client->cgi_pipe_r_from_child != -1)
|
||||||
|
if (::close(client->cgi_pipe_r_from_child) == -1)
|
||||||
|
std::perror("err close()");
|
||||||
|
client->cgi_pipe_r_from_child = -1;
|
||||||
|
|
||||||
|
print_secure(client->get_cl_fd(), "close pipe wtp [" + ::itos(client->cgi_pipe_w_to_parent) + "]\n");
|
||||||
|
if (client->cgi_pipe_w_to_parent != -1)
|
||||||
|
if (::close(client->cgi_pipe_w_to_parent) == -1)
|
||||||
|
std::perror("err close()");
|
||||||
|
client->cgi_pipe_w_to_parent = -1;
|
||||||
|
|
||||||
|
print_secure(client->get_cl_fd(), "close pipe rfp [" + ::itos(client->cgi_pipe_r_from_parent) + "]\n");
|
||||||
|
if (client->cgi_pipe_r_from_parent != -1)
|
||||||
|
if (::close(client->cgi_pipe_r_from_parent) == -1)
|
||||||
|
std::perror("err close()");
|
||||||
|
client->cgi_pipe_r_from_parent = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Webserv::_close_all_clients()
|
void Webserv::_close_all_clients()
|
||||||
{
|
{
|
||||||
_close_all_clients_fd();
|
_close_all_clients_fd();
|
||||||
@@ -28,32 +58,25 @@ void Webserv::_close_all_clients()
|
|||||||
|
|
||||||
void Webserv::_close_all_clients_fd()
|
void Webserv::_close_all_clients_fd()
|
||||||
{
|
{
|
||||||
_close_all_clients_cgi_fd();
|
_close_all_clients_cgi_pipes();
|
||||||
std::vector<Client>::iterator it = _clients.begin();
|
std::vector<Client>::iterator it = _clients.begin();
|
||||||
std::vector<Client>::iterator it_end = _clients.end();
|
std::vector<Client>::iterator it_end = _clients.end();
|
||||||
while (it != it_end)
|
while (it != it_end)
|
||||||
{
|
{
|
||||||
// _epoll_update(_clients.back().fd, 0, EPOLL_CTL_DEL); // normalement superflu, DEBUG
|
print_secure(it->get_cl_fd(), "close client fd " + ::itos(it->get_cl_fd()) + "\n");
|
||||||
std::cerr << "close fd " << it->get_cl_fd() << "\n";
|
|
||||||
if (::close(it->get_cl_fd()) == -1)
|
if (::close(it->get_cl_fd()) == -1)
|
||||||
std::perror("err close()");
|
std::perror("err close()");
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Webserv::_close_all_clients_cgi_fd()
|
void Webserv::_close_all_clients_cgi_pipes()
|
||||||
{
|
{
|
||||||
std::vector<Client>::iterator it = _clients.begin();
|
std::vector<Client>::iterator it = _clients.begin();
|
||||||
std::vector<Client>::iterator it_end = _clients.end();
|
std::vector<Client>::iterator it_end = _clients.end();
|
||||||
while (it != it_end)
|
while (it != it_end)
|
||||||
{
|
{
|
||||||
// _epoll_update(_clients.back().fd, 0, EPOLL_CTL_DEL); // normalement superflu, DEBUG
|
_close_client_cgi_pipes(&(*it));
|
||||||
if (it->cgi_pipe_rfd)
|
|
||||||
{
|
|
||||||
std::cerr << "close cgi-fd " << it->cgi_pipe_rfd << "\n";
|
|
||||||
if (::close(it->cgi_pipe_rfd) == -1)
|
|
||||||
std::perror("err close()");
|
|
||||||
}
|
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -63,19 +86,18 @@ void Webserv::_close_all_listen_sockets()
|
|||||||
{ // TODO : change like clients (clear in place of pop_back)
|
{ // TODO : change like clients (clear in place of pop_back)
|
||||||
while (!_listen_sockets.empty())
|
while (!_listen_sockets.empty())
|
||||||
{
|
{
|
||||||
// _epoll_update(_listen_sockets.back().fd, 0, EPOLL_CTL_DEL); // normalement superflu, DEBUG
|
std::cerr << "close lsocket fd " << _listen_sockets.back().fd << "\n";
|
||||||
std::cerr << "close fd " << _listen_sockets.back().fd << "\n";
|
|
||||||
if (::close(_listen_sockets.back().fd) == -1)
|
if (::close(_listen_sockets.back().fd) == -1)
|
||||||
std::perror("err close()");
|
std::perror("err close()");
|
||||||
_listen_sockets.pop_back();
|
_listen_sockets.pop_back();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Webserv::_reopen_lsocket(std::vector<listen_socket>::iterator it)
|
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
** Many common code with init_virtual_servers(). Could refactor it.
|
** Many common code with init_virtual_servers(). Could refactor it.
|
||||||
*/
|
*/
|
||||||
|
void Webserv::_reopen_lsocket(std::vector<listen_socket>::iterator it)
|
||||||
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
std::cerr << "close lsocket " << it->fd << "\n";
|
std::cerr << "close lsocket " << it->fd << "\n";
|
||||||
@@ -91,9 +113,8 @@ void Webserv::_reopen_lsocket(std::vector<listen_socket>::iterator it)
|
|||||||
}
|
}
|
||||||
it->fd = ret;
|
it->fd = ret;
|
||||||
|
|
||||||
// HUGO ADD
|
// From : https://www.ibm.com/docs/en/i/7.2?topic=designs-example-nonblocking-io-select
|
||||||
// allow socket descriptor to be reuseable
|
// allow socket descriptor to be reuseable
|
||||||
// I just copied it from https://www.ibm.com/docs/en/i/7.2?topic=designs-example-nonblocking-io-select
|
|
||||||
int on = 1;
|
int on = 1;
|
||||||
if (setsockopt(it->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
|
if (setsockopt(it->fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
|
||||||
{
|
{
|
||||||
@@ -101,7 +122,6 @@ void Webserv::_reopen_lsocket(std::vector<listen_socket>::iterator it)
|
|||||||
_listen_sockets.erase(it);
|
_listen_sockets.erase(it);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// HUGO ADD END
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
_bind(it->fd, std::strtoul(it->port.c_str(), NULL, 10), it->host);
|
_bind(it->fd, std::strtoul(it->port.c_str(), NULL, 10), it->host);
|
||||||
@@ -136,8 +156,5 @@ void Webserv::_handle_epoll_error_client(uint32_t events, int fd)
|
|||||||
std::cerr << "EPOLLERR on client fd " << fd << "\n"; // DEBUG
|
std::cerr << "EPOLLERR on client fd " << fd << "\n"; // DEBUG
|
||||||
if (events & EPOLLHUP)
|
if (events & EPOLLHUP)
|
||||||
std::cerr << "EPOLLHUP on client fd " << fd << "\n"; // DEBUG
|
std::cerr << "EPOLLHUP on client fd " << fd << "\n"; // DEBUG
|
||||||
if (std::find(_clients.begin(), _clients.end(), fd) != _clients.end())
|
_close_client(fd);
|
||||||
std::cerr << "Found the client in _clients" << "\n"; // DEBUG
|
|
||||||
|
|
||||||
_close_client(fd); // " EPOLLHUP on client fd 8 " en boucle quand on mattraque un peu les CGI, donc il ne le trouve pas dans _clients. Etrange.
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,18 +35,14 @@ void Webserv::init_virtual_servers(std::vector<ServerConfig>* servers)
|
|||||||
new_socket.port = it->port;
|
new_socket.port = it->port;
|
||||||
_listen_sockets.push_back(new_socket);
|
_listen_sockets.push_back(new_socket);
|
||||||
|
|
||||||
// HUGO ADD
|
// From : https://www.ibm.com/docs/en/i/7.2?topic=designs-example-nonblocking-io-select
|
||||||
//
|
|
||||||
// allow socket descriptor to be reuseable
|
// allow socket descriptor to be reuseable
|
||||||
// I just copied it from https://www.ibm.com/docs/en/i/7.2?topic=designs-example-nonblocking-io-select
|
|
||||||
int on = 1;
|
int on = 1;
|
||||||
if (setsockopt(new_socket.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
|
if (setsockopt(new_socket.fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0)
|
||||||
{
|
{
|
||||||
::perror("err setsockopt()");
|
::perror("err setsockopt()");
|
||||||
throw std::runtime_error("Socket init");
|
throw std::runtime_error("Socket init");
|
||||||
}
|
}
|
||||||
//
|
|
||||||
// HUGO ADD END
|
|
||||||
|
|
||||||
_bind(new_socket.fd, std::strtoul(it->port.c_str(), NULL, 10), it->host);
|
_bind(new_socket.fd, std::strtoul(it->port.c_str(), NULL, 10), it->host);
|
||||||
_listen(new_socket.fd, 42); // 42 arbitrary
|
_listen(new_socket.fd, 42); // 42 arbitrary
|
||||||
@@ -69,7 +65,6 @@ void Webserv::_bind(int socket_fd, in_port_t port, std::string host)
|
|||||||
addr.sin_family = AF_INET;
|
addr.sin_family = AF_INET;
|
||||||
addr.sin_port = ::htons(port);
|
addr.sin_port = ::htons(port);
|
||||||
addr.sin_addr.s_addr = ::htonl(::inet_addr(host.c_str()));
|
addr.sin_addr.s_addr = ::htonl(::inet_addr(host.c_str()));
|
||||||
// addr.sin_addr.s_addr = ::htonl(INADDR_ANY); // htonl useless with 0 value (INADDR_ANY) ?
|
|
||||||
|
|
||||||
if (::bind(socket_fd, (const sockaddr*)&addr, sizeof addr) == -1)
|
if (::bind(socket_fd, (const sockaddr*)&addr, sizeof addr) == -1)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ void Webserv::_delete(Client *client, const std::string &path)
|
|||||||
|
|
||||||
void Webserv::_delete_file(Client *client, const std::string &path)
|
void Webserv::_delete_file(Client *client, const std::string &path)
|
||||||
{
|
{
|
||||||
std::cout << "_delete_file()\n";
|
std::cerr << "_delete_file()\n";
|
||||||
client->status = ::eval_file_access(path, W_OK);
|
client->status = ::eval_file_access(path, W_OK);
|
||||||
if (client->status)
|
if (client->status)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -2,13 +2,12 @@
|
|||||||
#include "Webserv.hpp"
|
#include "Webserv.hpp"
|
||||||
#define MAX_FILESIZE 1 * MB // unused
|
#define MAX_FILESIZE 1 * MB // unused
|
||||||
|
|
||||||
// const?
|
|
||||||
/*
|
/*
|
||||||
https://www.rfc-editor.org/rfc/rfc9110.html#name-get
|
https://www.rfc-editor.org/rfc/rfc9110.html#name-get
|
||||||
*/
|
*/
|
||||||
void Webserv::_get(Client *client, std::string &path)
|
void Webserv::_get(Client *client, std::string &path)
|
||||||
{
|
{
|
||||||
std::cout << "_get()\n";
|
print_secure(client->get_cl_fd(), "_get()\n");
|
||||||
if (eval_file_type(path) == IS_DIR)
|
if (eval_file_type(path) == IS_DIR)
|
||||||
{
|
{
|
||||||
if (path[path.size() - 1] != '/')
|
if (path[path.size() - 1] != '/')
|
||||||
@@ -19,7 +18,7 @@ void Webserv::_get(Client *client, std::string &path)
|
|||||||
{
|
{
|
||||||
path.append(client->assigned_location->index[i]);
|
path.append(client->assigned_location->index[i]);
|
||||||
_get_file(client, path);
|
_get_file(client, path);
|
||||||
std::cerr << "Added an index\n"; //debug
|
print_secure(client->get_cl_fd(), "Added an index\n");
|
||||||
return ;
|
return ;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -42,8 +41,7 @@ void Webserv::_get_file(Client *client, const std::string &path)
|
|||||||
std::ifstream ifd; // For chunk, ifstream directly in struct CLient for multiples read without close() ?
|
std::ifstream ifd; // For chunk, ifstream directly in struct CLient for multiples read without close() ?
|
||||||
std::stringstream buf;
|
std::stringstream buf;
|
||||||
|
|
||||||
std::cout << "_get_file()\n";
|
print_secure(client->get_cl_fd(), "_get_file()\n");
|
||||||
|
|
||||||
client->status = ::eval_file_access(path, R_OK);
|
client->status = ::eval_file_access(path, R_OK);
|
||||||
if (client->status)
|
if (client->status)
|
||||||
return;
|
return;
|
||||||
@@ -84,16 +82,19 @@ if (size > MAX_FILESIZE)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
// const?
|
/*
|
||||||
|
<a href="http://nginx.org/">nginx.org</a>.<br/>
|
||||||
|
<a href="/test/test_deeper/index1.html">index1.html</a>
|
||||||
|
<a href="/test/test_deeper/..">..</a>
|
||||||
|
*/
|
||||||
void Webserv::_autoindex(Client *client, const std::string &path)
|
void Webserv::_autoindex(Client *client, const std::string &path)
|
||||||
{
|
{
|
||||||
std::cout << "_autoindex()\n";
|
std::cerr << "_autoindex()\n";
|
||||||
|
|
||||||
std::string dir_list;
|
std::string dir_list;
|
||||||
DIR *dir;
|
DIR *dir;
|
||||||
struct dirent *ent;
|
struct dirent *ent;
|
||||||
|
|
||||||
// std::cout << "Path in auto is: " << path << '\n';
|
|
||||||
if ( (dir = opendir(path.c_str()) ) != NULL)
|
if ( (dir = opendir(path.c_str()) ) != NULL)
|
||||||
{
|
{
|
||||||
dir_list.append(AUTOINDEX_START);
|
dir_list.append(AUTOINDEX_START);
|
||||||
@@ -117,13 +118,6 @@ void Webserv::_autoindex(Client *client, const std::string &path)
|
|||||||
dir_list.append("</a>");
|
dir_list.append("</a>");
|
||||||
dir_list.append("\n");
|
dir_list.append("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// <a href="http://nginx.org/">nginx.org</a>.<br/>
|
|
||||||
// <a href="/test/test_deeper/index1.html">index1.html</a>
|
|
||||||
|
|
||||||
// apparently this is more than good enough!
|
|
||||||
// <a href="/test/test_deeper/..">..</a>
|
|
||||||
|
|
||||||
dir_list.append(AUTOINDEX_END);
|
dir_list.append(AUTOINDEX_END);
|
||||||
closedir (dir);
|
closedir (dir);
|
||||||
client->status = 200;
|
client->status = 200;
|
||||||
|
|||||||
@@ -1,24 +1,21 @@
|
|||||||
|
|
||||||
#include "Webserv.hpp"
|
#include "Webserv.hpp"
|
||||||
|
|
||||||
|
|
||||||
void Webserv::_post(Client *client, const std::string &path)
|
|
||||||
{
|
|
||||||
/*
|
/*
|
||||||
https://www.rfc-editor.org/rfc/rfc9110.html#name-post
|
https://www.rfc-editor.org/rfc/rfc9110.html#name-post
|
||||||
*/
|
*/
|
||||||
|
void Webserv::_post(Client *client, const std::string &path)
|
||||||
|
{
|
||||||
(void)path; // unused, we use "assigned_location->upload_dir" instead
|
(void)path; // unused, we use "assigned_location->upload_dir" instead
|
||||||
std::cout << "_post()\n";
|
std::cerr << "_post()\n";
|
||||||
std::cerr << "upload_dir = " << client->assigned_location->upload_dir << "\n";
|
|
||||||
|
|
||||||
|
|
||||||
if (client->get_rq_abs_path() != client->assigned_location->path)
|
if (client->get_rq_abs_path() != client->assigned_location->path)
|
||||||
client->status = 404; // 404 ? J'ai un doute.
|
client->status = 404; // 404 or other status better ?
|
||||||
else if (client->assigned_location->upload_dir.empty())
|
else if (client->assigned_location->upload_dir.empty())
|
||||||
client->status = 404; // 404 ? J'ai un doute.
|
client->status = 404; // 404 or other status better ?
|
||||||
else if (client->get_rq_multi_bodys().empty())
|
else if (client->get_rq_multi_bodys().empty())
|
||||||
{
|
{
|
||||||
client->status = 415;
|
client->status = 415; // Unsupported Media Type
|
||||||
client->response.append("Accept: multipart/form-data"); // empty, no encoding accepted
|
client->response.append("Accept: multipart/form-data"); // empty, no encoding accepted
|
||||||
client->response.append(CRLF);
|
client->response.append(CRLF);
|
||||||
}
|
}
|
||||||
@@ -26,17 +23,18 @@ void Webserv::_post(Client *client, const std::string &path)
|
|||||||
_upload_files(client);
|
_upload_files(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// #include <ctime> // TODO: could add date to DEFAULT_NAME to avoid overwriting files
|
||||||
#define DEFAULT_NAME "unnamed_file"
|
#define DEFAULT_NAME "unnamed_file"
|
||||||
// TODO : Loop for multi body
|
|
||||||
void Webserv::_upload_files(Client *client)
|
void Webserv::_upload_files(Client *client)
|
||||||
{
|
{
|
||||||
std::cout << "_upload_files()\n";
|
std::cerr << "_upload_files()\n";
|
||||||
std::ofstream ofd;
|
std::ofstream ofd;
|
||||||
std::vector<MultipartBody>::const_iterator body_it = client->get_rq_multi_bodys().begin();
|
std::vector<MultipartBody>::const_iterator body_it = client->get_rq_multi_bodys().begin();
|
||||||
std::string path;
|
std::string path;
|
||||||
std::string filename;
|
std::string filename;
|
||||||
size_t pos;
|
size_t pos;
|
||||||
bool file_existed = false;
|
bool file_existed = false;
|
||||||
|
static int i_name = 0;
|
||||||
|
|
||||||
client->status = ::eval_file_access(client->assigned_location->upload_dir, W_OK);
|
client->status = ::eval_file_access(client->assigned_location->upload_dir, W_OK);
|
||||||
if (client->status)
|
if (client->status)
|
||||||
@@ -58,21 +56,18 @@ void Webserv::_upload_files(Client *client)
|
|||||||
{
|
{
|
||||||
filename = filename.substr(pos + sizeof("filename=")-1);
|
filename = filename.substr(pos + sizeof("filename=")-1);
|
||||||
std::cerr << "filename ="<< filename << "\n";
|
std::cerr << "filename ="<< filename << "\n";
|
||||||
// A l'arrache pour enlever les "
|
// Pour enlever les "
|
||||||
filename.erase(0, 1);
|
filename.erase(0, 1);
|
||||||
std::cerr << "filename ="<< filename << "\n";
|
std::cerr << "filename ="<< filename << "\n";
|
||||||
filename.erase(filename.size()-1, 1);
|
filename.erase(filename.size()-1, 1);
|
||||||
std::cerr << "filename ="<< filename << "\n";
|
std::cerr << "filename ="<< filename << "\n";
|
||||||
std::cerr << "filename ="<< filename << "\n";
|
std::cerr << "filename ="<< filename << "\n";
|
||||||
if (filename.empty())
|
|
||||||
filename = DEFAULT_NAME;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
filename = DEFAULT_NAME;
|
|
||||||
}
|
}
|
||||||
|
if (pos == NPOS || filename.empty())
|
||||||
|
filename = DEFAULT_NAME + ::itos(i_name++);
|
||||||
|
|
||||||
std::cerr << "filename ="<< filename << "\n";
|
std::cerr << "filename ="<< filename << "\n";
|
||||||
path = client->assigned_location->upload_dir; // Assume there a final '/'
|
path = client->assigned_location->upload_dir;
|
||||||
path.append(filename);
|
path.append(filename);
|
||||||
|
|
||||||
|
|
||||||
@@ -81,7 +76,6 @@ void Webserv::_upload_files(Client *client)
|
|||||||
else
|
else
|
||||||
file_existed = true;
|
file_existed = true;
|
||||||
|
|
||||||
// How to determine status 403 for file that dont already exist ? access() on the upload_dir ?
|
|
||||||
if (file_existed && ::access(path.c_str(), W_OK) == -1)
|
if (file_existed && ::access(path.c_str(), W_OK) == -1)
|
||||||
{
|
{
|
||||||
std::perror("err access()");
|
std::perror("err access()");
|
||||||
|
|||||||
@@ -25,8 +25,6 @@ void Webserv::_request(Client *client)
|
|||||||
}
|
}
|
||||||
else if (ret == READ_COMPLETE)
|
else if (ret == READ_COMPLETE)
|
||||||
{
|
{
|
||||||
if (client->body_complete && client->get_rq_multi_bodys().empty()) // DEBUG
|
|
||||||
std::cerr << "______BODY\n" << client->get_rq_body() << "\n______\n"; // DEBUG
|
|
||||||
_epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_MOD);
|
_epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_MOD);
|
||||||
client->request_complete = true;
|
client->request_complete = true;
|
||||||
}
|
}
|
||||||
@@ -38,28 +36,18 @@ int Webserv::_read_request(Client *client)
|
|||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
|
||||||
ret = ::recv(client->get_cl_fd(), buf, BUFSIZE, 0);
|
ret = ::recv(client->get_cl_fd(), buf, BUFSIZE, 0);
|
||||||
std::cerr << "recv() on fd(" << client->get_cl_fd() << ") returned = " << ret << "\n" ;
|
print_secure(client->get_cl_fd(), "recv() ret = " + ::itos(ret) + "\n");
|
||||||
if (ret == -1)
|
if (ret == -1)
|
||||||
{
|
{
|
||||||
std::perror("err recv()");
|
std::perror("err recv()");
|
||||||
return READ_CLOSE;
|
return READ_CLOSE;
|
||||||
}
|
}
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
{
|
|
||||||
std::cerr << "recv() read 0, then close client" << "\n"; // DEBUG
|
|
||||||
return READ_CLOSE;
|
return READ_CLOSE;
|
||||||
}
|
|
||||||
client->raw_request.append(buf, ret);
|
client->raw_request.append(buf, ret);
|
||||||
// ::print_special(client->raw_request);
|
|
||||||
// std::cerr << "__raw_request__\n" << client->raw_request << "\n______\n"; // DEBUG
|
|
||||||
|
|
||||||
print_special(client->raw_request);
|
|
||||||
|
|
||||||
std::cerr << "client header complete: " << client->header_complete << "\n"; // DEBUG
|
|
||||||
|
|
||||||
if (!client->header_complete)
|
if (!client->header_complete)
|
||||||
{
|
{
|
||||||
std::cout << "Header not complete\n"; // debug
|
|
||||||
client->parse_request_headers(_servers);
|
client->parse_request_headers(_servers);
|
||||||
if (client->status)
|
if (client->status)
|
||||||
return READ_COMPLETE;
|
return READ_COMPLETE;
|
||||||
@@ -78,8 +66,6 @@ int Webserv::_read_request(Client *client)
|
|||||||
}
|
}
|
||||||
if (client->header_complete)
|
if (client->header_complete)
|
||||||
{
|
{
|
||||||
std::cerr << "Client header Complete\n";
|
|
||||||
// client->read_body_size += ret; // Not accurate, part of body could have been read with headers, unused for now
|
|
||||||
client->parse_request_body();
|
client->parse_request_body();
|
||||||
if (client->status || client->body_complete)
|
if (client->status || client->body_complete)
|
||||||
return READ_COMPLETE;
|
return READ_COMPLETE;
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ void Webserv::_response(Client *client)
|
|||||||
{
|
{
|
||||||
int ret = _send_response(client);
|
int ret = _send_response(client);
|
||||||
|
|
||||||
|
print_secure(client->get_cl_fd(), "....._response()\n");
|
||||||
if (g_last_signal)
|
if (g_last_signal)
|
||||||
_handle_last_signal();
|
_handle_last_signal();
|
||||||
|
|
||||||
@@ -22,7 +23,7 @@ void Webserv::_response(Client *client)
|
|||||||
else if (ret == SEND_COMPLETE)
|
else if (ret == SEND_COMPLETE)
|
||||||
{
|
{
|
||||||
if (client->get_rq_headers("Connection") == "close"
|
if (client->get_rq_headers("Connection") == "close"
|
||||||
|| client->status == 400 // TODO: Refactoring
|
|| client->status == 400
|
||||||
|| client->status == 408
|
|| client->status == 408
|
||||||
|| client->status == 413)
|
|| client->status == 413)
|
||||||
_close_client(client->get_cl_fd());
|
_close_client(client->get_cl_fd());
|
||||||
@@ -38,48 +39,42 @@ int Webserv::_send_response(Client *client)
|
|||||||
{
|
{
|
||||||
ssize_t ret;
|
ssize_t ret;
|
||||||
|
|
||||||
std::cerr << "send()\n";
|
print_secure(client->get_cl_fd(), "....._send_response()\n");
|
||||||
|
|
||||||
if (client->response.empty())
|
if (client->response.empty())
|
||||||
{
|
{
|
||||||
_append_base_headers(client);
|
_append_base_headers(client);
|
||||||
|
print_secure(client->get_cl_fd(), "....>_send_response()\n");
|
||||||
|
}
|
||||||
|
|
||||||
if (!client->status)
|
if (!client->status)
|
||||||
{
|
{
|
||||||
_construct_response(client);
|
_construct_response(client);
|
||||||
if (client->cgi_pipe_rfd)
|
if (client->cgi_state == CGI_WAIT_TO_EXEC
|
||||||
|
|| client->cgi_state == CGI_OUTPUT_READING)
|
||||||
return SEND_IN_PROGRESS;
|
return SEND_IN_PROGRESS;
|
||||||
}
|
print_secure(client->get_cl_fd(), "....>_send_response()\n");
|
||||||
}
|
|
||||||
else if (!client->cgi_output.empty())
|
|
||||||
{
|
|
||||||
// /*DEBUG*/ std::cout << "\n" B_PURPLE "[response]:" RESET "\n"; ::print_special(client->response); std::cout << B_PURPLE "-----------" RESET "\n\n";
|
|
||||||
// /*DEBUG*/ std::cout << "\n" B_PURPLE "[script output]:" RESET "\n"; ::print_special(script_output); std::cout << B_PURPLE "-----------" RESET "\n\n";
|
|
||||||
_check_script_output(client, client->cgi_output); // FD_CGI : adjust for client->cgi_output;
|
|
||||||
if (client->status < 400)
|
|
||||||
client->response += client->cgi_output;
|
|
||||||
// /*DEBUG*/ std::cout << "\n" B_PURPLE "[response + output]:" RESET "\n"; ::print_special(client->response); std::cout << B_PURPLE "-----------" RESET "\n\n";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_insert_status_line(client);
|
_insert_status_line(client);
|
||||||
|
print_secure(client->get_cl_fd(), "....>_send_response()\n");
|
||||||
if (client->status >= 400)
|
if (client->status >= 400)
|
||||||
|
{
|
||||||
_error_html_response(client);
|
_error_html_response(client);
|
||||||
|
print_secure(client->get_cl_fd(), "....>_send_response()\n");
|
||||||
|
}
|
||||||
|
|
||||||
/*DEBUG*/ std::cout << "\n" B_PURPLE "[response + output + headers]:" RESET "\n"; ::print_special(client->response); std::cout << "\n" B_PURPLE "-----------" RESET "\n\n";
|
print_secure(client->get_cl_fd(), "send()\n");
|
||||||
|
|
||||||
// /* Debug */ std::cerr << "client->response.size() = " << client->response.size() << "\n"; // DEBUG
|
|
||||||
ret = ::send(client->get_cl_fd(), client->response.c_str(), client->response.size(), 0);
|
ret = ::send(client->get_cl_fd(), client->response.c_str(), client->response.size(), 0);
|
||||||
if (ret == -1)
|
if (ret == -1)
|
||||||
{
|
{
|
||||||
std::perror("err send()");
|
std::perror("err send()");
|
||||||
std::cerr << "client.fd =" << client->get_cl_fd() << "\n"; // DEBUG
|
|
||||||
return SEND_CLOSE;
|
return SEND_CLOSE;
|
||||||
}
|
}
|
||||||
if (ret == 0) // actually never happen ?
|
if (ret == 0)
|
||||||
{
|
{
|
||||||
std::cerr << "SEND RET 0 for client.fd =" << client->get_cl_fd() << "\n"; // DEBUG
|
std::cerr << "send() ret == 0 never happens ?" << "\n"; // Debug
|
||||||
return SEND_CLOSE;
|
return SEND_CLOSE;
|
||||||
}
|
}
|
||||||
// /* Debug */ std::cerr << "ret send() = " << ret << "\n"; // DEBUG
|
|
||||||
|
|
||||||
return SEND_COMPLETE;
|
return SEND_COMPLETE;
|
||||||
}
|
}
|
||||||
@@ -88,8 +83,9 @@ void Webserv::_append_base_headers(Client *client)
|
|||||||
{
|
{
|
||||||
client->response.append("Server: Webserv/0.1" CRLF);
|
client->response.append("Server: Webserv/0.1" CRLF);
|
||||||
|
|
||||||
|
print_secure(client->get_cl_fd(), "....._append_base_headers()\n");
|
||||||
if (client->get_rq_headers("Connection") == "close"
|
if (client->get_rq_headers("Connection") == "close"
|
||||||
|| client->status == 400 // TODO: Refactoring
|
|| client->status == 400
|
||||||
|| client->status == 408
|
|| client->status == 408
|
||||||
|| client->status == 413)
|
|| client->status == 413)
|
||||||
client->response.append("Connection: close" CRLF);
|
client->response.append("Connection: close" CRLF);
|
||||||
@@ -102,20 +98,33 @@ void Webserv::_construct_response(Client *client)
|
|||||||
std::string path;
|
std::string path;
|
||||||
std::string script_output;
|
std::string script_output;
|
||||||
|
|
||||||
|
print_secure(client->get_cl_fd(), "....._construct_response()\n");
|
||||||
path = _replace_url_root(client, client->get_rq_abs_path());
|
path = _replace_url_root(client, client->get_rq_abs_path());
|
||||||
if (_is_cgi(client, path))
|
print_secure(client->get_cl_fd(), "....>_construct_response()\n");
|
||||||
|
if (client->cgi_state == CGI_READY_TO_EXEC)
|
||||||
{
|
{
|
||||||
_exec_cgi(client);
|
_write_body_to_cgi(client);
|
||||||
|
print_secure(client->get_cl_fd(), "....>_construct_response()\n");
|
||||||
|
if (client->status)
|
||||||
return;
|
return;
|
||||||
|
_exec_cgi(client);
|
||||||
}
|
}
|
||||||
|
else if (client->cgi_state == CGI_OUTPUT_COMPLETE)
|
||||||
|
{
|
||||||
|
_check_script_output(client, client->cgi_output);
|
||||||
|
print_secure(client->get_cl_fd(), "....>_construct_response()\n");
|
||||||
|
if (client->status < 400 || client->status >= 600)
|
||||||
|
client->response += client->cgi_output;
|
||||||
|
}
|
||||||
|
else if (_is_cgi(client, path))
|
||||||
|
_cgi_open_pipes(client);
|
||||||
|
else
|
||||||
_process_method(client, path);
|
_process_method(client, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Webserv::_process_method(Client *client, std::string &path)
|
void Webserv::_process_method(Client *client, std::string &path)
|
||||||
{
|
{
|
||||||
// std::cerr << "allow_methods = " << http_methods_to_str(client->assigned_location->allow_methods) << "\n"; // debug
|
print_secure(client->get_cl_fd(), "....._process_method()\n");
|
||||||
std::cerr << "Path again: " << path << '\n'; // debug
|
|
||||||
|
|
||||||
switch (client->get_rq_method())
|
switch (client->get_rq_method())
|
||||||
{
|
{
|
||||||
case (GET):
|
case (GET):
|
||||||
@@ -131,13 +140,11 @@ void Webserv::_process_method(Client *client, std::string &path)
|
|||||||
|
|
||||||
std::string Webserv::_replace_url_root(Client *client, std::string path)
|
std::string Webserv::_replace_url_root(Client *client, std::string path)
|
||||||
{
|
{
|
||||||
// /* Debug */ std::cerr << "assigned_location->path = " << client->assigned_location->path << "\n"; // debug
|
print_secure(client->get_cl_fd(), "....._replace_url_root()\n");
|
||||||
// /* Debug */ std::cerr << "path before = " << path << "\n"; // DEBUG
|
|
||||||
if (client->assigned_location->path == "/")
|
if (client->assigned_location->path == "/")
|
||||||
path.insert(0, client->assigned_location->root);
|
path.insert(0, client->assigned_location->root);
|
||||||
else
|
else
|
||||||
path.replace(0, client->assigned_location->path.size(), client->assigned_location->root);
|
path.replace(0, client->assigned_location->path.size(), client->assigned_location->root);
|
||||||
// /* Debug */ std::cerr << "path after = " << path << "\n"; // DEBUG
|
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,6 +155,8 @@ void Webserv::_insert_status_line(Client *client)
|
|||||||
{
|
{
|
||||||
std::string status_line;
|
std::string status_line;
|
||||||
std::string status = _http_status[client->status];
|
std::string status = _http_status[client->status];
|
||||||
|
|
||||||
|
print_secure(client->get_cl_fd(), "....._insert_status_line()\n");
|
||||||
if (status.empty())
|
if (status.empty())
|
||||||
status = ::itos(client->status);
|
status = ::itos(client->status);
|
||||||
|
|
||||||
@@ -159,8 +168,9 @@ void Webserv::_insert_status_line(Client *client)
|
|||||||
|
|
||||||
void Webserv::_error_html_response(Client *client)
|
void Webserv::_error_html_response(Client *client)
|
||||||
{
|
{
|
||||||
std::cout << "_error_html_response()\n";
|
|
||||||
|
|
||||||
|
print_secure(client->get_cl_fd(), "....._error_html_response()\n");
|
||||||
|
std::cerr << "_error_html_response()\n";
|
||||||
if (client->assigned_server
|
if (client->assigned_server
|
||||||
&& !client->assigned_server->error_pages[client->status].empty()
|
&& !client->assigned_server->error_pages[client->status].empty()
|
||||||
&& ::eval_file_access(client->assigned_server->error_pages[client->status], R_OK) == 0 )
|
&& ::eval_file_access(client->assigned_server->error_pages[client->status], R_OK) == 0 )
|
||||||
@@ -174,6 +184,7 @@ void Webserv::_error_html_response(Client *client)
|
|||||||
status = "Error " + ::itos(client->status);
|
status = "Error " + ::itos(client->status);
|
||||||
std::string html_page = HTML_ERROR;
|
std::string html_page = HTML_ERROR;
|
||||||
::replace_all_substr(html_page, STATUS_PLACEHOLDER, status);
|
::replace_all_substr(html_page, STATUS_PLACEHOLDER, status);
|
||||||
|
print_secure(client->get_cl_fd(), "....>_error_html_response()\n");
|
||||||
_append_body(client, html_page, "html");
|
_append_body(client, html_page, "html");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -182,6 +193,7 @@ void Webserv::_append_body(Client *client, const std::string &body, const std::s
|
|||||||
{
|
{
|
||||||
const std::string &mime_type = _mime_types[file_extension];
|
const std::string &mime_type = _mime_types[file_extension];
|
||||||
|
|
||||||
|
print_secure(client->get_cl_fd(), "....._append_body()\n");
|
||||||
client->response.append("Content-Type: ");
|
client->response.append("Content-Type: ");
|
||||||
if (mime_type.empty())
|
if (mime_type.empty())
|
||||||
client->response.append(MIME_TYPE_DEFAULT);
|
client->response.append(MIME_TYPE_DEFAULT);
|
||||||
|
|||||||
@@ -4,98 +4,6 @@
|
|||||||
#define MAX_EVENTS 42 // arbitrary
|
#define MAX_EVENTS 42 // arbitrary
|
||||||
#define TIMEOUT 3000
|
#define TIMEOUT 3000
|
||||||
|
|
||||||
|
|
||||||
#define BUFSIZE 8192 // (8Ko)
|
|
||||||
#define STATUS_500 std::string("Status: 500" CRLF CRLF);
|
|
||||||
void Webserv::_read_cgi_output(Client *client)
|
|
||||||
{
|
|
||||||
char buf[BUFSIZE];
|
|
||||||
ssize_t ret;
|
|
||||||
std::cerr << "_read_cgi_output()" << "\n";
|
|
||||||
std::cerr << "cgi_pid = " << client->cgi_pid << "\n";
|
|
||||||
std::cerr << "client fd = " << client->get_cl_fd() << "\n";
|
|
||||||
std::cerr << "cgi fd = " << client->cgi_pipe_rfd << "\n";
|
|
||||||
|
|
||||||
ret = ::read(client->cgi_pipe_rfd, buf, BUFSIZE);
|
|
||||||
std::cerr << "cgi read ret = " << ret << "\n";
|
|
||||||
if (ret == -1)
|
|
||||||
{
|
|
||||||
std::perror("err read(cgi_fd)");
|
|
||||||
client->cgi_output = STATUS_500;
|
|
||||||
}
|
|
||||||
else if (ret == 0)
|
|
||||||
std::cerr << "Madame s'il vous plait, du Ketchup pour mon hamburger" << " (AKA:ret=0)" << "\n";
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::cerr << "NORMAL BEHAVIOR I THINK!\n"; // debug
|
|
||||||
client->cgi_output.append(buf, ret);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Webserv::_handle_epoll_error_cgi_fd(uint32_t events, Client *client)
|
|
||||||
{
|
|
||||||
(void)events;
|
|
||||||
std::cerr << "cgi EPOLLERR" << "\n";
|
|
||||||
std::cerr << "cgi_pid = " << client->cgi_pid << "\n";
|
|
||||||
std::cerr << "client fd = " << client->get_cl_fd() << "\n";
|
|
||||||
std::cerr << "cgi fd = " << client->cgi_pipe_rfd << "\n";
|
|
||||||
|
|
||||||
client->cgi_output = STATUS_500;
|
|
||||||
|
|
||||||
pid_t wait_ret;
|
|
||||||
wait_ret = ::waitpid(client->cgi_pid, NULL, WNOHANG);
|
|
||||||
std::cerr << "cgi EPOLLERR waitpid ret = " << wait_ret << "\n";
|
|
||||||
if (wait_ret == client->cgi_pid)
|
|
||||||
{
|
|
||||||
if (client->cgi_pipe_rfd)
|
|
||||||
{
|
|
||||||
if (::close(client->cgi_pipe_rfd) == -1)
|
|
||||||
std::perror("err close()");
|
|
||||||
}
|
|
||||||
client->cgi_pipe_rfd = 0;
|
|
||||||
_epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void Webserv::_cgi_epollhup(uint32_t events, Client *client)
|
|
||||||
{
|
|
||||||
(void)events;
|
|
||||||
(void)client;
|
|
||||||
|
|
||||||
/* std::cerr << "cgi EPOLLHUP" << "\n";
|
|
||||||
std::cerr << "cgi_pid = " << client->cgi_pid << "\n";
|
|
||||||
std::cerr << "client fd = " << client->get_cl_fd() << "\n";
|
|
||||||
std::cerr << "cgi fd = " << client->cgi_pipe_rfd << "\n"; */
|
|
||||||
|
|
||||||
pid_t wait_ret;
|
|
||||||
wait_ret = ::waitpid(client->cgi_pid, NULL, WNOHANG);
|
|
||||||
// std::cerr << "cgi EPOLLHUP waitpid ret = " << wait_ret << "\n";
|
|
||||||
if (wait_ret == client->cgi_pid)
|
|
||||||
{
|
|
||||||
if (client->cgi_pipe_rfd)
|
|
||||||
{
|
|
||||||
if (::close(client->cgi_pipe_rfd) == -1)
|
|
||||||
std::perror("err close()");
|
|
||||||
}
|
|
||||||
client->cgi_pipe_rfd = 0;
|
|
||||||
_epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Client *Webserv::_find_cgi_fd(int cgi_fd)
|
|
||||||
{
|
|
||||||
std::vector<Client>::iterator it = _clients.begin();
|
|
||||||
std::vector<Client>::iterator it_end = _clients.end();
|
|
||||||
while (it != it_end)
|
|
||||||
{
|
|
||||||
if (it->cgi_pipe_rfd == cgi_fd)
|
|
||||||
return (&(*it));
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
return (NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Webserv::run()
|
void Webserv::run()
|
||||||
{
|
{
|
||||||
std::cerr << "Server started\n";
|
std::cerr << "Server started\n";
|
||||||
@@ -104,14 +12,23 @@ void Webserv::run()
|
|||||||
int i;
|
int i;
|
||||||
int count_loop = 0;
|
int count_loop = 0;
|
||||||
std::vector<listen_socket>::iterator it_lsocket;
|
std::vector<listen_socket>::iterator it_lsocket;
|
||||||
Client *client_cgi = NULL;
|
std::vector<Client>::iterator it_client;
|
||||||
|
Client *client_cgi_input = NULL;
|
||||||
|
Client *client_cgi_output = NULL;
|
||||||
|
|
||||||
|
std::signal(SIGPIPE, signal_handler);
|
||||||
|
std::signal(SIGINT, signal_handler);
|
||||||
g_run = true;
|
g_run = true;
|
||||||
|
g_family = PARENT;
|
||||||
while (g_run)
|
while (g_run)
|
||||||
{
|
{
|
||||||
std::cerr << ++count_loop << "----loop epoll() ";
|
|
||||||
|
sem_wait(g_shmem); // protect output here
|
||||||
|
std::cout << g_family << "|" << ++count_loop << "-----loop epoll() ";
|
||||||
nfds = ::epoll_wait(_epfd, events, MAX_EVENTS, TIMEOUT);
|
nfds = ::epoll_wait(_epfd, events, MAX_EVENTS, TIMEOUT);
|
||||||
std::cerr << "(nfds=" << nfds << ")\n";
|
std::cerr << "(nfds=" << nfds << ")" << std::endl;
|
||||||
|
sem_post(g_shmem); // protect output here
|
||||||
|
|
||||||
if (nfds == -1)
|
if (nfds == -1)
|
||||||
{
|
{
|
||||||
int errno_copy = errno;
|
int errno_copy = errno;
|
||||||
@@ -119,8 +36,12 @@ void Webserv::run()
|
|||||||
if (errno_copy == EINTR)
|
if (errno_copy == EINTR)
|
||||||
g_run = false;
|
g_run = false;
|
||||||
else
|
else
|
||||||
|
{
|
||||||
|
std::signal(SIGPIPE, SIG_DFL);
|
||||||
|
std::signal(SIGINT, SIG_DFL);
|
||||||
throw std::runtime_error("Epoll wait");
|
throw std::runtime_error("Epoll wait");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (nfds == 0 && !_clients.empty())
|
else if (nfds == 0 && !_clients.empty())
|
||||||
_timeout();
|
_timeout();
|
||||||
i = 0;
|
i = 0;
|
||||||
@@ -128,7 +49,10 @@ void Webserv::run()
|
|||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
it_lsocket = std::find(_listen_sockets.begin(), _listen_sockets.end(), events[i].data.fd);
|
it_lsocket = std::find(_listen_sockets.begin(), _listen_sockets.end(), events[i].data.fd);
|
||||||
client_cgi = _find_cgi_fd(events[i].data.fd);
|
it_client = std::find(_clients.begin(), _clients.end(), events[i].data.fd);
|
||||||
|
client_cgi_input = _find_cgi_input_fd(events[i].data.fd);
|
||||||
|
client_cgi_output = _find_cgi_output_fd(events[i].data.fd);
|
||||||
|
|
||||||
if (it_lsocket != _listen_sockets.end())
|
if (it_lsocket != _listen_sockets.end())
|
||||||
{
|
{
|
||||||
if (events[i].events & EPOLLERR || events[i].events & EPOLLHUP)
|
if (events[i].events & EPOLLERR || events[i].events & EPOLLHUP)
|
||||||
@@ -136,23 +60,34 @@ void Webserv::run()
|
|||||||
else if (events[i].events & EPOLLIN)
|
else if (events[i].events & EPOLLIN)
|
||||||
_accept_connection(*it_lsocket);
|
_accept_connection(*it_lsocket);
|
||||||
}
|
}
|
||||||
else if (client_cgi)
|
else if (it_client != _clients.end())
|
||||||
{
|
|
||||||
if (events[i].events & EPOLLERR)
|
|
||||||
_handle_epoll_error_cgi_fd(events[i].events, client_cgi);
|
|
||||||
else if (events[i].events & EPOLLIN)
|
|
||||||
_read_cgi_output(client_cgi);
|
|
||||||
else if ( (events[i].events & EPOLLHUP) && !(events[i].events & EPOLLIN) )
|
|
||||||
_cgi_epollhup(events[i].events, client_cgi);
|
|
||||||
}
|
|
||||||
else if (std::find(_clients.begin(), _clients.end(), events[i].data.fd) != _clients.end()) // TODO: save the it in var to avoid multiples find()
|
|
||||||
{
|
{
|
||||||
if (events[i].events & EPOLLERR || events[i].events & EPOLLHUP)
|
if (events[i].events & EPOLLERR || events[i].events & EPOLLHUP)
|
||||||
_handle_epoll_error_client(events[i].events, events[i].data.fd);
|
_handle_epoll_error_client(events[i].events, events[i].data.fd);
|
||||||
else if (events[i].events & EPOLLIN)
|
else if (events[i].events & EPOLLIN)
|
||||||
_request( &(*std::find(_clients.begin(), _clients.end(), events[i].data.fd)) );
|
_request( &(*it_client) );
|
||||||
else if (events[i].events & EPOLLOUT)
|
else if (events[i].events & EPOLLOUT)
|
||||||
_response( &(*std::find(_clients.begin(), _clients.end(), events[i].data.fd)) );
|
_response( &(*it_client) );
|
||||||
|
}
|
||||||
|
else if (client_cgi_input)
|
||||||
|
{
|
||||||
|
if (events[i].events & EPOLLERR || events[i].events & EPOLLHUP)
|
||||||
|
_handle_epollerr_cgi_input(events[i].events, client_cgi_input);
|
||||||
|
else if (events[i].events & EPOLLOUT)
|
||||||
|
_cgi_input_ready(client_cgi_input);
|
||||||
|
}
|
||||||
|
else if (client_cgi_output)
|
||||||
|
{
|
||||||
|
if (events[i].events & EPOLLERR)
|
||||||
|
_handle_epollerr_cgi_output(events[i].events, client_cgi_output);
|
||||||
|
else if (events[i].events & EPOLLIN)
|
||||||
|
_read_cgi_output(client_cgi_output);
|
||||||
|
else if ( (events[i].events & EPOLLHUP) && !(events[i].events & EPOLLIN) )
|
||||||
|
_handle_epollhup_cgi_output(events[i].events, client_cgi_output);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cerr << "NOTHING FOR FD = " << events[i].data.fd << "\n"; // DEBUG
|
||||||
}
|
}
|
||||||
++i;
|
++i;
|
||||||
if (!g_run)
|
if (!g_run)
|
||||||
@@ -177,4 +112,6 @@ void Webserv::run()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
std::signal(SIGPIPE, SIG_DFL);
|
||||||
|
std::signal(SIGINT, SIG_DFL);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,16 +14,10 @@ void Webserv::_handle_last_signal()
|
|||||||
if (g_last_signal == SIGPIPE)
|
if (g_last_signal == SIGPIPE)
|
||||||
{
|
{
|
||||||
std::cerr << "SIGPIPE\n";
|
std::cerr << "SIGPIPE\n";
|
||||||
// if (_actual_client)
|
|
||||||
// {
|
|
||||||
// _close_client(_actual_client->fd);
|
|
||||||
// _actual_client = NULL;
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
else if (g_last_signal == SIGINT)
|
else if (g_last_signal == SIGINT)
|
||||||
{
|
{
|
||||||
g_run = false;
|
g_run = false;
|
||||||
// maybe a throw here instead of "g_run" ?
|
|
||||||
}
|
}
|
||||||
g_last_signal = 0;
|
g_last_signal = 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,12 +12,7 @@ void Webserv::_timeout()
|
|||||||
std::cerr << "timeout request fd " << it->get_cl_fd() << "\n";
|
std::cerr << "timeout request fd " << it->get_cl_fd() << "\n";
|
||||||
it->status = 408;
|
it->status = 408;
|
||||||
_epoll_update(it->get_cl_fd(), EPOLLOUT, EPOLL_CTL_MOD);
|
_epoll_update(it->get_cl_fd(), EPOLLOUT, EPOLL_CTL_MOD);
|
||||||
|
|
||||||
// DEBUG, close without repsonse 408
|
|
||||||
/* _close_client(it->get_cl_fd());
|
|
||||||
it = _clients.begin(); */
|
|
||||||
}
|
}
|
||||||
// else // DEBUG
|
|
||||||
++it;
|
++it;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
47
temp_memo_debug_fork.txt
Normal file
47
temp_memo_debug_fork.txt
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
//// RECREATE EPOLL //
|
||||||
|
std::cerr << "epfd from parent = " << _epfd << "\n";
|
||||||
|
if (::close(_epfd) == -1)
|
||||||
|
std::perror("err close");
|
||||||
|
_epfd = ::epoll_create1(EPOLL_CLOEXEC); // (EPOLL_CLOEXEC) for CGI fork ?
|
||||||
|
if (_epfd == -1)
|
||||||
|
{
|
||||||
|
std::perror("err epoll_create1()");
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<listen_socket>::iterator it_ls = _listen_sockets.begin();
|
||||||
|
std::vector<listen_socket>::iterator it_ls_end = _listen_sockets.end();
|
||||||
|
while (it_ls != it_ls_end)
|
||||||
|
{
|
||||||
|
_epoll_update(it_ls->fd, EPOLLIN, EPOLL_CTL_ADD);
|
||||||
|
++it_ls;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<Client>::iterator it = _clients.begin();
|
||||||
|
std::vector<Client>::iterator it_end = _clients.end();
|
||||||
|
while (it != it_end)
|
||||||
|
{
|
||||||
|
if (it->cgi_state == CGI_WAIT_TO_EXEC)
|
||||||
|
_epoll_update(it->cgi_pipe_w_to_child, EPOLLOUT, EPOLL_CTL_ADD);
|
||||||
|
else if (it->cgi_state == CGI_OUTPUT_READING)
|
||||||
|
_epoll_update(it->cgi_pipe_r_from_child, EPOLLIN, EPOLL_CTL_ADD);
|
||||||
|
else if (client->request_complete)
|
||||||
|
_epoll_update(it->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD);
|
||||||
|
else
|
||||||
|
_epoll_update(it->get_cl_fd(), EPOLLIN, EPOLL_CTL_ADD);
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
//// */
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//// DEBUG, MINIMAL ACTIONS //
|
||||||
|
// ::sleep(1); // rescue team
|
||||||
|
client->status = 442; // rescue_team
|
||||||
|
_close_client_cgi_pipes(client);// rescue_team
|
||||||
|
// _epoll_update(client->get_cl_fd(), EPOLLOUT, EPOLL_CTL_ADD); // rescue_team
|
||||||
|
client->cgi_state = CGI_NO_CGI; // rescue_team
|
||||||
|
return; // rescue_team
|
||||||
|
////
|
||||||
|
|
||||||
1
urls.txt
1
urls.txt
@@ -6,4 +6,3 @@ http://localhost:4040/test
|
|||||||
http://localhost:4040/test/test_deeper/
|
http://localhost:4040/test/test_deeper/
|
||||||
http://localhost:4040/test/test_deeper/super_deep/
|
http://localhost:4040/test/test_deeper/super_deep/
|
||||||
http://localhost:4040/test/index1.html
|
http://localhost:4040/test/index1.html
|
||||||
|
|
||||||
|
|||||||
1
urls_cgi.txt
Normal file
1
urls_cgi.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
http://localhost:4040/cgi-bin/cgi_cpp.out?fname=John&lname=Doe
|
||||||
BIN
www/Kermit_the_Frog.jpg
Normal file
BIN
www/Kermit_the_Frog.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
@@ -279,18 +279,13 @@
|
|||||||
<br>
|
<br>
|
||||||
|
|
||||||
<form method="get" action="/cgi-bin/cgi_cpp_download.out">
|
<form method="get" action="/cgi-bin/cgi_cpp_download.out">
|
||||||
<h1>WIP</h1>
|
|
||||||
<p><mark>get</mark> form</p>
|
<p><mark>get</mark> form</p>
|
||||||
<p>to <mark>/cgi-bin/cgi_cpp_download.out</mark></p>
|
<p>to <mark>/cgi-bin/cgi_cpp_download.out</mark></p>
|
||||||
<label for="fdownload">download file:</label><br>
|
<label for="fdownload">download file:</label><br>
|
||||||
<input type="file" id="fupload" name="fupload">
|
<input type="file" id="fupload" name="fupload">
|
||||||
<select name="file">
|
<select name="file">
|
||||||
<option value="Cagneyc_intro.gif" >Cagneyc_intro.gif </option>
|
<option value="Kermit_the_Frog.jpg" selected >Kermit_the_Frog.jpg</option>
|
||||||
<option value="file.md" >file.md </option>
|
<option value="kermit_tea.jpg" >kermit_tea.jpg</option>
|
||||||
<option value="index.html" >index.html </option>
|
|
||||||
<option value="kermit.ico" >kermit.ico </option>
|
|
||||||
<option value="punpun.png" selected>punpun.png </option>
|
|
||||||
<option value="subject.pdf" >subject.pdf </option>
|
|
||||||
<option value="Van_Eyck_Portrait_Arnolfini.jpg" >Van_Eyck_Portrait_Arnolfini.jpg</option>
|
<option value="Van_Eyck_Portrait_Arnolfini.jpg" >Van_Eyck_Portrait_Arnolfini.jpg</option>
|
||||||
<option value="directory" >directory </option>
|
<option value="directory" >directory </option>
|
||||||
<option value="DOESNT_EXIST.BAD" >DOESNT_EXIST.BAD </option>
|
<option value="DOESNT_EXIST.BAD" >DOESNT_EXIST.BAD </option>
|
||||||
@@ -528,18 +523,6 @@
|
|||||||
<h3>expectation:</h3>
|
<h3>expectation:</h3>
|
||||||
<p>error 500</p>
|
<p>error 500</p>
|
||||||
</form>
|
</form>
|
||||||
<br>
|
|
||||||
|
|
||||||
<form method="post" action="/cgi-bin/cgi_cpp_upload.out" enctype="multipart/form-data">
|
|
||||||
<h1>WIP</h1>
|
|
||||||
<p><mark>post</mark> form</p>
|
|
||||||
<p>to <mark>/cgi-bin/cgi_cpp_upload.out</mark></p>
|
|
||||||
<label for="fupload">Upload file:</label><br>
|
|
||||||
<input type="file" id="fupload" name="fupload">
|
|
||||||
<input type="submit" value="submit">
|
|
||||||
<h3>expectation:</h3>
|
|
||||||
<p>upload file in ./www/user_files/</p>
|
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
BIN
www/kermit_greaser.webp
Normal file
BIN
www/kermit_greaser.webp
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
BIN
www/kermit_le_lait.jpg
Normal file
BIN
www/kermit_le_lait.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
BIN
www/kermit_study.jpg
Normal file
BIN
www/kermit_study.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 41 KiB |
BIN
www/kermit_tea.jpg
Normal file
BIN
www/kermit_tea.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 110 KiB |
1
www/to_delete.txt
Normal file
1
www/to_delete.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
we will delete
|
||||||
BIN
www/user_files/pepe.jpg
Normal file
BIN
www/user_files/pepe.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 54 KiB |
Reference in New Issue
Block a user