Compare commits
144 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f7b31c7db7 | ||
|
|
5225e3258b | ||
|
|
469eca8aa9 | ||
|
|
9b0fcc1520 | ||
|
|
dda0103fb8 | ||
|
|
3d17db996a | ||
|
|
a008c12058 | ||
|
|
6694ffeb66 | ||
|
|
3530595b01 | ||
|
|
b34e49311b | ||
|
|
2613ca2e1a | ||
|
|
e537e9bb78 | ||
|
|
3763249a3e | ||
|
|
366178303f | ||
|
|
df24de46c7 | ||
|
|
72b12132d4 | ||
|
|
da5d1f38b0 | ||
|
|
875810c992 | ||
|
|
c6ebb95dc5 | ||
|
|
4fdbb1e0eb | ||
|
|
b45ed52a2a | ||
|
|
1a99c6cc84 | ||
|
|
9f3903d497 | ||
|
|
ccc542f52b | ||
|
|
19a9d3b464 | ||
|
|
4dc70373f8 | ||
|
|
1b7d388231 | ||
|
|
517f5dfc8a | ||
|
|
2c6bc096cc | ||
|
|
5c5f298493 | ||
|
|
1ed4128afc | ||
|
|
ff443c80b1 | ||
|
|
4602844f5a | ||
|
|
2a1aec8f1d | ||
|
|
4a0c0ee238 | ||
|
|
5627b6d1a2 | ||
|
|
5e403fc71c | ||
|
|
f8c6923c6d | ||
|
|
8c2aff6c6b | ||
|
|
e691c517e8 | ||
|
|
973388bf97 | ||
|
|
48af92b3bc | ||
|
|
c05536ca01 | ||
|
|
008b2a635f | ||
|
|
54b6d1f6d6 | ||
|
|
c9c8946e70 | ||
|
|
19da59ecf8 | ||
|
|
fe89be65f6 | ||
|
|
1c13e254d5 | ||
|
|
3fe37ea451 | ||
|
|
6ad6ec7d63 | ||
|
|
036256522a | ||
|
|
a284e400c1 | ||
|
|
9ac84f706d | ||
|
|
b9d4317f51 | ||
|
|
aa03880601 | ||
|
|
a6bfea3b56 | ||
|
|
f6f63931ad | ||
|
|
8000668b36 | ||
|
|
21efbef86a | ||
|
|
076f46fb85 | ||
|
|
683dbadb91 | ||
|
|
8d4961c9b5 | ||
|
|
d663a4c7e6 | ||
|
|
37c5be9ffc | ||
|
|
ce0a004d28 | ||
|
|
84babec82b | ||
|
|
ddafa229c6 | ||
|
|
be499328f6 | ||
|
|
41db4fc12b | ||
|
|
a20a5eff27 | ||
|
|
db4c7468cc | ||
|
|
dda32c759a | ||
|
|
b0949615c8 | ||
|
|
285f2d049f | ||
|
|
defb2ada61 | ||
|
|
ebd0fda52c | ||
|
|
c3240b8618 | ||
|
|
3495ff19a8 | ||
|
|
058701f657 | ||
|
|
a69273b88e | ||
|
|
f17bc9fa58 | ||
|
|
4d395088d0 | ||
|
|
c7bbf29a1b | ||
|
|
b44acafefe | ||
|
|
cade79c37f | ||
|
|
52824f30bd | ||
|
|
2a70c6b26d | ||
|
|
71c07140e2 | ||
|
|
de09c2357c | ||
|
|
c225063361 | ||
|
|
400efbe720 | ||
|
|
f7c0ff1a8a | ||
|
|
3a58b5d921 | ||
|
|
a1fff0f8c2 | ||
|
|
ad2b5a629a | ||
|
|
ff77dfd298 | ||
|
|
ab0bc2c4c0 | ||
|
|
08f6929db9 | ||
|
|
c32fc2c8a2 | ||
|
|
27b4f96618 | ||
|
|
0b51d13f13 | ||
|
|
1d67e6988d | ||
|
|
11f71ea74f | ||
|
|
9a379c835d | ||
|
|
360c27df5f | ||
|
|
c7905ebd19 | ||
|
|
17230ccc42 | ||
|
|
69c1a6f6bf | ||
|
|
86f7740984 | ||
|
|
58f67bf42e | ||
|
|
f7f3e42b15 | ||
|
|
8e90221058 | ||
|
|
f393aa46bf | ||
|
|
1eb989a3fd | ||
|
|
56f4cf7e15 | ||
|
|
482a38952e | ||
|
|
ef034a356b | ||
|
|
1d3cdef7a6 | ||
|
|
97c90236b9 | ||
|
|
643b09c4f7 | ||
|
|
a44b9b493a | ||
|
|
7fdc81f5f4 | ||
|
|
0a72778c8c | ||
|
|
02cfdf43bc | ||
|
|
f87024c32f | ||
|
|
9ee7205b95 | ||
|
|
cf69168a84 | ||
|
|
94852babc6 | ||
|
|
f777441edf | ||
|
|
1ccf61bc68 | ||
|
|
4ab099ee4d | ||
|
|
4870b2c05d | ||
|
|
8ec1353723 | ||
|
|
4b1baca126 | ||
|
|
6f0c3b4d6d | ||
|
|
f7dc5ccde4 | ||
|
|
9ac14aa1aa | ||
|
|
f7e6b61811 | ||
|
|
fce1bcbece | ||
|
|
ca8427262d | ||
|
|
3d46505411 | ||
|
|
b0c524a8bd | ||
|
|
fef26aee5b |
4
.gitignore
vendored
@@ -20,3 +20,7 @@ ubuntu_cgi_tester
|
||||
webserv
|
||||
!**/webserv/
|
||||
*.log
|
||||
|
||||
large.jpg
|
||||
webserv_tester
|
||||
webserv_tester2
|
||||
|
||||
23
42.config
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
server {
|
||||
|
||||
|
||||
server_name server1;
|
||||
listen 0.0.0.0:4040;
|
||||
client_body_limit 1000;
|
||||
|
||||
index youpi.bla; # this is another comment
|
||||
|
||||
root ./YoupiBanane/;
|
||||
|
||||
error_page 404 ./www/error_pages/error_404.html;
|
||||
|
||||
location / {
|
||||
allow_methods GET;
|
||||
}
|
||||
|
||||
location /directory {
|
||||
index youpi.bad_extention;
|
||||
}
|
||||
|
||||
}
|
||||
74
Makefile
@@ -1,13 +1,13 @@
|
||||
|
||||
NAME = webserv
|
||||
CXX = c++
|
||||
CXX = clang++
|
||||
|
||||
CXXFLAGS = -Wall -Wextra #-Werror
|
||||
CXXFLAGS = -Wall -Wextra -Werror
|
||||
CXXFLAGS += $(HEADERS_D:%=-I%)
|
||||
CXXFLAGS += -std=c++98
|
||||
CXXFLAGS += -g3
|
||||
CXXFLAGS += -MMD -MP #header dependencie
|
||||
#CXXFLAGS += -O3
|
||||
CXXFLAGS += -g
|
||||
CXXFLAGS += -MMD -MP # header dependencie
|
||||
# for debug
|
||||
|
||||
VPATH = $(SRCS_D)
|
||||
|
||||
@@ -17,44 +17,61 @@ HEADERS_D = srcs \
|
||||
|
||||
SRCS_D = srcs \
|
||||
srcs/webserv \
|
||||
srcs/config
|
||||
srcs/config \
|
||||
|
||||
SRCS = main.cpp \
|
||||
base.cpp init.cpp close.cpp epoll_update.cpp signal.cpp \
|
||||
accept.cpp request.cpp response.cpp \
|
||||
run_loop.cpp \
|
||||
ConfigParser.cpp \
|
||||
ConfigParserUtils.cpp \
|
||||
ConfigParserPost.cpp \
|
||||
method_get.cpp method_post.cpp method_delete.cpp \
|
||||
run_loop.cpp timeout.cpp \
|
||||
parser.cpp extraConfig.cpp postProcessing.cpp \
|
||||
utils.cpp \
|
||||
cgi_script.cpp \
|
||||
Client.cpp \
|
||||
parsing_message_http.cpp \
|
||||
cgi.cpp cgi_epoll.cpp \
|
||||
Client.cpp Client_multipart_body.cpp \
|
||||
|
||||
OBJS_D = builds
|
||||
OBJS = $(SRCS:%.cpp=$(OBJS_D)/%.o)
|
||||
DEPS = $(OBJS:.o=.d) #header dependencie
|
||||
|
||||
# --------------------
|
||||
# ------ RULES -------
|
||||
# --------------------
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
|
||||
# . target: prerequisites . $@ : target #
|
||||
# RULES . recipe . $< : 1st prerequisite #
|
||||
# . @recipe (silent) . $^ : all prerequisites #
|
||||
# . target: VAR = assignment . | : order-only prereq. #
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
|
||||
|
||||
all: $(NAME)
|
||||
|
||||
$(OBJS_D)/%.o: %.cpp | $(OBJS_D)
|
||||
$(CXX) $(CXXFLAGS) -c $< -o $@
|
||||
$(CXX) -c $< -o $@ $(CXXFLAGS)
|
||||
printf "$(_CYAN)\r\33[2K\rCompling $@$(_END)"
|
||||
|
||||
$(OBJS_D):
|
||||
mkdir $@
|
||||
|
||||
$(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)"
|
||||
|
||||
# CGI
|
||||
cgi:
|
||||
make -C srcs/cgi-bin
|
||||
cgiclean:
|
||||
make clean -C srcs/cgi-bin
|
||||
cgifclean:
|
||||
make fclean -C srcs/cgi-bin
|
||||
cgire:
|
||||
make re -C srcs/cgi-bin
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJS_D)
|
||||
echo "$(_CYAN).o Files Deleted 🤫$(_END)"
|
||||
|
||||
fclean: clean
|
||||
rm -f $(NAME)
|
||||
echo "$(_CYAN)$(NAME) Deleted 🤫$(_END)"
|
||||
|
||||
re: fclean all
|
||||
|
||||
@@ -62,3 +79,24 @@ re: fclean all
|
||||
|
||||
-include $(DEPS) # header dependencie
|
||||
|
||||
.SILENT:
|
||||
|
||||
# ------------------
|
||||
# ----- COLORS -----
|
||||
# ------------------
|
||||
|
||||
_GREY=$ \033[30m
|
||||
_RED=$ \033[31m
|
||||
_GREEN=$ \033[32m
|
||||
_YELLOW=$ \033[33m
|
||||
_BLUE=$ \033[34m
|
||||
_PURPLE=$ \033[35m
|
||||
_CYAN=$ \033[36m
|
||||
_WHITE=$ \033[37m
|
||||
_END=$ \033[0m
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
156
README.md
@@ -1,85 +1,6 @@
|
||||
|
||||
## work together
|
||||
|
||||
#### message
|
||||
- err access line response.cpp:169
|
||||
- g pas fini la gestion de sortie du cgi (comparaison des headers fields pour supprimer les doublons)
|
||||
- g rendu independantes les fonctions qui parses un message http (requete ou response) dans `parsing_http_message.cpp`
|
||||
- il y a une erreur importante dans la fonction qui parse les headers d'un message http : ca ne verifie pas si la premier ligne est un header ou la "first line"
|
||||
|
||||
#### TODO
|
||||
- `_is_cgi()` and `_fill_cgi_path()`
|
||||
- `_cgi_output()` change status in `client->status`
|
||||
- two cgi tests :
|
||||
? - a basic form with "name" and "something", that return a html page with that
|
||||
? - for GET and POST
|
||||
? - a script called by a file extension in URI
|
||||
|
||||
#### output cgi script :
|
||||
! TODO : change all the '\n' by '\r\n'
|
||||
! TODO : there is at least one header field followed by '\r\n\r\n' :
|
||||
- "Content-Type"
|
||||
- "Location"
|
||||
- "Status"
|
||||
! TODO : there is no space between filed name and ":"
|
||||
! TODO?: handle Location field, either :
|
||||
- local : start with '/' --> rerun the request with new uri
|
||||
- client : start with '<scheme>:' --> send back status code 302
|
||||
-> TODO : there is no field duplicate (resolve conflicts)
|
||||
-> TODO : if status field, change server status for this one
|
||||
-> TODO : if no Location field && no Status field -> status code = 200
|
||||
|
||||
#### questions
|
||||
- in client.cpp i fill the port, is there a default one in case it's not in the request ?
|
||||
- timeout server but still works ?
|
||||
- path contains double "//" from `Webserv::_get()` in response.cpp
|
||||
- cgi path ? defined in config ? and root path ? :
|
||||
- `Client.cpp : fill_script_path()`
|
||||
- `cgi.cpp : is_cgi()`
|
||||
- `cgi.cpp : set_env()`
|
||||
- what if the uri contains a php file, and the config said php must be handled by cgi, but the path to this php in the uri is wrong ?
|
||||
- is it ok ? `http://my_site.com/cgi-bin/php-cgi` (real path)
|
||||
- is it ok ? `http://my_site.com/php-cgi` (reconstruct path ?)
|
||||
- is it ok ? `http://my_site.com/something/php-cgi` (what about 'something' ?)
|
||||
- is it ok ? `http://my_site.com/something/cgi-bin/php-cgi` (real path with 'something' before ? )
|
||||
- I don't save the STDIN and STDOUT before dup2 in child process, is it wrong ?
|
||||
- the response page is received long after the cgi-script is done, why ?
|
||||
|
||||
#### notifications
|
||||
- i changed the Client getters in two categories :
|
||||
- getters for requests infos : `get_rq_<info>`
|
||||
- getters for client sides infos : `get_cl_<info>` (such as ip of client)
|
||||
- i changed the variables in request struct in Client :
|
||||
- `path` become `uri` (ex. `/path/to/file?var=val`)
|
||||
- add `abs_path` (ex. `/path/to/file` )
|
||||
- add `query` (ex. `var=val`)
|
||||
- the header fields names, as key in map, are stored in lowercase, and getters are case-insensitives
|
||||
|
||||
|
||||
respsonse.cpp
|
||||
```
|
||||
_response()
|
||||
{
|
||||
_determine_process_server()
|
||||
_send_response()
|
||||
{
|
||||
_append_base_headers()
|
||||
_construct_response()
|
||||
{
|
||||
_process_method()
|
||||
{
|
||||
_get()
|
||||
{
|
||||
_exec_cgi()
|
||||
}
|
||||
}
|
||||
_insert_status_line()
|
||||
::send(headers)
|
||||
::send(body)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
## man
|
||||
@@ -159,6 +80,8 @@ _response()
|
||||
## cgi rfc
|
||||
[rfc 3875](https://www.rfc-editor.org/rfc/rfc3875)
|
||||
|
||||
#### output cgi script :
|
||||
|
||||
#### summary :
|
||||
- the cgi-script will send back at least one header field followed by an empty line
|
||||
- this header field will be one of three :
|
||||
@@ -167,13 +90,18 @@ _response()
|
||||
- "Status"
|
||||
- the cgi-script may send back more header fields
|
||||
- the server must check and modify few things :
|
||||
- there is no duplicate in headers fields (if there is, resolve conflict)
|
||||
- there is no space between the field name and the ":"
|
||||
- the newlines are of form "\r\n", and not "\n" only
|
||||
- if the location field is not present, then if the status field is not present either, then the status code is 200
|
||||
- the cgi-script can return a location field, of two types :
|
||||
- local redirection : start with a "/", the server must answer as if this was the request uri
|
||||
- client redirection : start with <name-of-cheme>":", the server must send back a status 302 with this uri to the client
|
||||
- there is no field duplicate (resolve conflicts)
|
||||
- there is no space between filed name and ":"
|
||||
- change all the '\n' by '\r\n'
|
||||
- if no Location field && no Status field -> status code = 200
|
||||
- handle Location field, either :
|
||||
- local : start with '/' --> rerun the request with new uri
|
||||
- client : start with '<scheme>:' --> send back status code 302
|
||||
- there is at least one header field followed by '\r\n\r\n' :
|
||||
- "Content-Type"
|
||||
- "Location"
|
||||
- "Status"
|
||||
- if status field, change server status for this one
|
||||
- to pass the body-message to the cgi-script, we write it into the temporary fd on which the script read it's standard input
|
||||
|
||||
[3.1: server responsabilities](https://www.rfc-editor.org/rfc/rfc3875#section-3.1)
|
||||
@@ -304,6 +232,62 @@ SERVER_SOFTWARE : the server software you're using (e.g. Apache 1.3)
|
||||
REDIRECT_STATUS : for exemple, 200
|
||||
```
|
||||
|
||||
g 50 34 48
|
||||
p 30 23 32
|
||||
l 20 14 20
|
||||
71
|
||||
|
||||
---
|
||||
## http status
|
||||
[rfc 2616](https://datatracker.ietf.org/doc/html/rfc2616#section-10)
|
||||
|
||||
#### Informational
|
||||
- 100 Continue
|
||||
- 101 Switching Protocols
|
||||
#### Successful
|
||||
- 200 OK
|
||||
- 201 Created
|
||||
- 202 Accepted
|
||||
- 203 Non-Authoritative Information
|
||||
- 204 No Content
|
||||
- 205 Reset Content
|
||||
- 206 Partial Content
|
||||
#### Redirection
|
||||
- 300 Multiple Choices
|
||||
- 301 Moved Permanently
|
||||
- 302 Found
|
||||
- 303 See Other
|
||||
- 304 Not Modified
|
||||
- 305 Use Proxy
|
||||
- 306 (Unused)
|
||||
- 307 Temporary Redirect
|
||||
#### Client Error
|
||||
- 400 Bad Request
|
||||
- 401 Unauthorized
|
||||
- 402 Payment Required
|
||||
- 403 Forbidden
|
||||
- 404 Not Found
|
||||
- 405 Method Not Allowed
|
||||
- 406 Not Acceptable
|
||||
- 407 Proxy Authentication Required
|
||||
- 408 Request Timeout
|
||||
- 409 Conflict
|
||||
- 410 Gone
|
||||
- 411 Length Required
|
||||
- 412 Precondition Failed
|
||||
- 413 Request Entity Too Large
|
||||
- 414 Request-URI Too Long
|
||||
- 415 Unsupported Media Type
|
||||
- 416 Requested Range Not Satisfiable
|
||||
- 417 Expectation Failed
|
||||
#### Server Error
|
||||
- 500 Internal Server Error
|
||||
- 501 Not Implemented
|
||||
- 502 Bad Gateway
|
||||
- 503 Service Unavailable
|
||||
- 504 Gateway Timeout
|
||||
- 505 HTTP Version Not Supported
|
||||
|
||||
---
|
||||
## ressources
|
||||
|
||||
|
||||
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
@@ -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
@@ -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>
|
||||
112
Tester/expected_results/expected_path_test.txt
Normal file
@@ -0,0 +1,112 @@
|
||||
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/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: 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 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>
|
||||
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>
|
||||
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
|
||||
|
||||
95
Tester/telnet_test.sh
Executable file
@@ -0,0 +1,95 @@
|
||||
#! /bin/bash
|
||||
|
||||
|
||||
# DO I EVEN NEED THIS FILE ? could i just put this stuff in maint_test.sh? or would it not modify the vars...
|
||||
|
||||
|
||||
# you need to put absolutely everything in ""
|
||||
|
||||
|
||||
#test_file=$1
|
||||
#source $test_file
|
||||
|
||||
connect_to_telnet="open $host $port"
|
||||
|
||||
|
||||
start_telnet()
|
||||
{
|
||||
echo "open $host $port"
|
||||
sleep 1
|
||||
}
|
||||
|
||||
|
||||
run()
|
||||
{
|
||||
echo "$connect_to_telnet"
|
||||
sleep 1
|
||||
|
||||
run_this_test
|
||||
|
||||
}
|
||||
|
||||
|
||||
#### DEPRICATED ######
|
||||
|
||||
run_telnet()
|
||||
{
|
||||
echo "$connect_to_telnet"
|
||||
sleep 1
|
||||
echo -e "$request"
|
||||
echo
|
||||
sleep 1
|
||||
|
||||
# ret = $(arg | telnet)
|
||||
|
||||
}
|
||||
|
||||
run_a_test()
|
||||
{
|
||||
{
|
||||
echo "----- $test_name -----"
|
||||
echo -e "$_RED$request$_END"
|
||||
} &> test.log
|
||||
|
||||
echo -e "$request" | telnet
|
||||
}
|
||||
|
||||
|
||||
#######
|
||||
# This is where stuff is launched
|
||||
#######
|
||||
|
||||
#rm -rf telnet.out
|
||||
|
||||
#./webserv $config_file 2>&1 > webserv.log & run_all
|
||||
#./webserv $config_file 2>&1 > webserv.log &
|
||||
#./webserv $config_file &> /dev/null &
|
||||
#./webserv $config_file 1>&1 > webserv.log &
|
||||
|
||||
#./webserv $config_file &> webserv.log &
|
||||
|
||||
#run_all
|
||||
#run_this_test
|
||||
|
||||
#echo -e "${_GREEN}Running Telnet Test on '$test_name'${_END}"
|
||||
|
||||
#sleep 1
|
||||
|
||||
#run | telnet >> telnet.out
|
||||
#run | telnet
|
||||
|
||||
#pkill webserv
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
16
Tester/telnet_test2.sh
Executable file
@@ -0,0 +1,16 @@
|
||||
#! /bin/bash
|
||||
|
||||
echo "open duckduckgo.com 80"
|
||||
sleep 1
|
||||
echo "GET / HTTP/1.1"
|
||||
echo "Host: duckduckgo.com"
|
||||
echo
|
||||
echo
|
||||
sleep 2
|
||||
|
||||
#(
|
||||
#echo open duckduckgo.com 80
|
||||
#echo "GET / HTTP/1.1"
|
||||
#echo "Host: duckduckgo.com"
|
||||
#echo "exit"
|
||||
#) | telnet
|
||||
107
Tester/test1.config
Normal file
@@ -0,0 +1,107 @@
|
||||
|
||||
server {
|
||||
|
||||
# this is a comment
|
||||
|
||||
server_name server1;
|
||||
|
||||
listen 0.0.0.0:4040;
|
||||
|
||||
# client_body_limit asdfa;
|
||||
client_body_limit 5000;
|
||||
# Max == 18446744073709551615 / 1024 == 18014398509481984
|
||||
|
||||
index index.html; # this is another comment
|
||||
#index mdr.html; # this is another comment
|
||||
|
||||
root ./Tester/www/;
|
||||
|
||||
error_page 404 ./Tester/www/error_pages/error_404.html;
|
||||
|
||||
|
||||
|
||||
location / {
|
||||
allow_methods GET;
|
||||
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/ {
|
||||
root ./srcs/cgi-bin/;
|
||||
allow_methods POST;
|
||||
cgi_ext php;
|
||||
}
|
||||
|
||||
location /list {
|
||||
autoindex on;
|
||||
}
|
||||
|
||||
location /cgi-bin {
|
||||
root ./srcs/cgi-bin/;
|
||||
cgi_ext out php sh;
|
||||
}
|
||||
|
||||
location /upload {
|
||||
allow_methods POST;
|
||||
autoindex on;
|
||||
upload_dir ./Tester/www/user_files/;
|
||||
# root doesn’t matter if used only with POST and no CGI
|
||||
}
|
||||
|
||||
location /the_dump {
|
||||
allow_methods GET DELETE;
|
||||
root ./Tester/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 ./Tester/www/test/;
|
||||
}
|
||||
|
||||
location /stylesheet {
|
||||
root ./stylesheet/;
|
||||
}
|
||||
|
||||
location /test/index1.html {
|
||||
root ./Tester/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 ./Tester/www/test/something.html;
|
||||
}
|
||||
|
||||
location /test/test_deeper/ {
|
||||
# allow_methods
|
||||
root ./Tester/www/test/test_deeper/;
|
||||
}
|
||||
|
||||
location /test/test_deeper/super_deep {
|
||||
root ./Tester/www/test/test_deeper/super_deep/;
|
||||
}
|
||||
|
||||
# location /test/test_deeper/something.html {
|
||||
# allow_methods DELETE;
|
||||
# }
|
||||
|
||||
}
|
||||
95
Tester/test2.config
Normal file
@@ -0,0 +1,95 @@
|
||||
|
||||
server {
|
||||
|
||||
# this is a comment
|
||||
|
||||
server_name server1;
|
||||
|
||||
listen 0.0.0.0:8080;
|
||||
|
||||
client_body_limit 1;
|
||||
# Max == 18446744073709551615 / 1024 == 18014398509481984
|
||||
|
||||
index index.html; # this is another comment
|
||||
|
||||
root ./Tester/www/;
|
||||
|
||||
error_page 404 ./Tester/www/error_pages/error_404.html;
|
||||
|
||||
|
||||
|
||||
location / {
|
||||
allow_methods GET;
|
||||
root ./Tester/www/;
|
||||
}
|
||||
|
||||
location /srcs/cgi-bin/ {
|
||||
root ./srcs/cgi-bin/;
|
||||
allow_methods POST;
|
||||
cgi_ext php;
|
||||
}
|
||||
|
||||
location /list {
|
||||
autoindex on;
|
||||
}
|
||||
|
||||
location /cgi-bin {
|
||||
root ./srcs/cgi-bin/;
|
||||
cgi_ext out php sh;
|
||||
}
|
||||
|
||||
location /upload {
|
||||
allow_methods POST;
|
||||
autoindex on;
|
||||
upload_dir ./Tester/www/user_files/;
|
||||
# root doesn’t matter if used only with POST and no CGI
|
||||
}
|
||||
|
||||
location /the_dump {
|
||||
allow_methods GET DELETE;
|
||||
root ./Tester/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 ./Tester/www/test/;
|
||||
}
|
||||
|
||||
location /stylesheet {
|
||||
root ./stylesheet/;
|
||||
}
|
||||
|
||||
location /test/index1.html {
|
||||
root ./Tester/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 ./Tester/www/test/something.html;
|
||||
}
|
||||
|
||||
location /test/test_deeper/ {
|
||||
# allow_methods
|
||||
root ./Tester/www/test/test_deeper/;
|
||||
}
|
||||
|
||||
location /test/test_deeper/super_deep {
|
||||
root ./Tester/www/test/test_deeper/super_deep/;
|
||||
}
|
||||
|
||||
# location /test/test_deeper/something.html {
|
||||
# allow_methods DELETE;
|
||||
# }
|
||||
|
||||
}
|
||||
98
Tester/test3.config
Normal file
@@ -0,0 +1,98 @@
|
||||
|
||||
server {
|
||||
|
||||
# this is a comment
|
||||
|
||||
server_name server1;
|
||||
|
||||
listen 8080;
|
||||
# listen 70000;
|
||||
|
||||
# client_body_limit asdfa;
|
||||
client_body_limit 1000;
|
||||
# Max == 18446744073709551615 / 1024 == 18014398509481984
|
||||
|
||||
index index.html; # this is another comment
|
||||
#index mdr.html; # this is another comment
|
||||
|
||||
root ./Tester/www/;
|
||||
|
||||
error_page 404 ./Tester/www/error_pages/error_404.html;
|
||||
|
||||
|
||||
|
||||
location / {
|
||||
allow_methods GET;
|
||||
root ./Tester/www/;
|
||||
}
|
||||
|
||||
location /srcs/cgi-bin/ {
|
||||
root ./srcs/cgi-bin/;
|
||||
allow_methods POST;
|
||||
cgi_ext php;
|
||||
}
|
||||
|
||||
location /list {
|
||||
autoindex on;
|
||||
}
|
||||
|
||||
location /cgi-bin {
|
||||
root ./srcs/cgi-bin/;
|
||||
cgi_ext out php sh;
|
||||
}
|
||||
|
||||
location /upload {
|
||||
allow_methods POST;
|
||||
autoindex on;
|
||||
upload_dir ./Tester/www/user_files/;
|
||||
# root doesn’t matter if used only with POST and no CGI
|
||||
}
|
||||
|
||||
location /the_dump {
|
||||
allow_methods GET DELETE;
|
||||
root ./Tester/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 ./Tester/www/test/;
|
||||
}
|
||||
|
||||
location /stylesheet {
|
||||
root ./stylesheet/;
|
||||
}
|
||||
|
||||
location /test/index1.html {
|
||||
root ./Tester/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 ./Tester/www/test/something.html;
|
||||
}
|
||||
|
||||
location /test/test_deeper/ {
|
||||
# allow_methods
|
||||
root ./Tester/www/test/test_deeper/;
|
||||
}
|
||||
|
||||
location /test/test_deeper/super_deep {
|
||||
root ./Tester/www/test/test_deeper/super_deep/;
|
||||
}
|
||||
|
||||
# location /test/test_deeper/something.html {
|
||||
# allow_methods DELETE;
|
||||
# }
|
||||
|
||||
}
|
||||
88
Tester/test_body.sh
Normal file
@@ -0,0 +1,88 @@
|
||||
#! /bin/bash
|
||||
|
||||
test_name="Body Test"
|
||||
|
||||
config_file="./Tester/test2.config"
|
||||
port=8080
|
||||
host="localhost"
|
||||
|
||||
#paths=("/" "/test" "/test/" "/list" "list" "/wrong") # you can add many
|
||||
paths=("/") # you can add many
|
||||
#methods=("GET" "POST" "DELETE")
|
||||
methods=("GET")
|
||||
httpz=("HTTP/1.1")
|
||||
|
||||
|
||||
|
||||
l1="${methods[0]} ${paths[0]} ${httpz[0]}"
|
||||
|
||||
header="Host: $host\n"
|
||||
body="this is a message \n"
|
||||
body+="this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message this is a message \n"
|
||||
|
||||
# turns out this does nothing...
|
||||
#header_cycle=("Content-Length: 17\n" "Content-Length: 14" "Content-Length: 25")
|
||||
#header_cycle=("Content-Length: 17\n" "\n")
|
||||
#header_cycle=("Content-Length: 17\n")
|
||||
#header_cycle=()
|
||||
header+="Content-Length: 8\n"
|
||||
|
||||
run_this_test()
|
||||
{
|
||||
echo size is ${#body} >> telnet.log
|
||||
|
||||
# for i in "${header_cycle[@]}"
|
||||
for i in "${paths[@]}"
|
||||
do
|
||||
# l1="${methods[0]} ${paths[0]} ${httpz[0]}"
|
||||
l1="${methods[0]} $i ${httpz[0]}"
|
||||
# header_send="$header$i"
|
||||
header_send="$header"
|
||||
## if you add an extra \n after header send you get a status code 200 OK and 400 bad request, but like both
|
||||
# request="$l1\n$header_send\n$body\n"
|
||||
request="$l1\n$header_send\n$body"
|
||||
{
|
||||
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_body_test.txt"
|
||||
files+=("expected_body_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
|
||||
|
||||
|
||||
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
||||
|
||||
83
Tester/test_header.sh
Normal file
@@ -0,0 +1,83 @@
|
||||
#! /bin/bash
|
||||
|
||||
test_name="Header Test"
|
||||
|
||||
config_file="./Tester/test1.config"
|
||||
port=4040
|
||||
host="localhost"
|
||||
|
||||
paths=("/") # you can add many
|
||||
#methods=("GET" "POST" "DELETE")
|
||||
methods=("GET")
|
||||
httpz=("HTTP/1.1")
|
||||
|
||||
|
||||
|
||||
|
||||
# the parts we will send to webserv
|
||||
|
||||
|
||||
# let main.sh handle the l1
|
||||
|
||||
l1="${methods[0]} ${paths[0]} ${httpz[0]}"
|
||||
|
||||
header="Host: $host\n"
|
||||
header+="Nonsense: fu\n"
|
||||
|
||||
header_cycle=("Transfer-encoding: fu" "Content-encoding: fu")
|
||||
|
||||
#header+="Transfer-encoding: fu\n"
|
||||
#header+="Content-endcoding: fu\n"
|
||||
body=
|
||||
|
||||
|
||||
run_this_test()
|
||||
{
|
||||
|
||||
for i in "${header_cycle[@]}"
|
||||
do
|
||||
header_send="$header$i"
|
||||
request="$l1\n$header_send\n$body\n"
|
||||
{
|
||||
echo "----- $test_name -----"
|
||||
echo -e "$_RED$request$_END"
|
||||
} >> telnet.log
|
||||
echo -e "$request"
|
||||
sleep 1
|
||||
echo -e "\n\n" >> telnet.log
|
||||
done
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
# expected result...
|
||||
|
||||
files=()
|
||||
|
||||
file="expected_header_test.txt"
|
||||
files+=("expected_header_test.txt")
|
||||
#files+=("expected_path_root_test.txt")
|
||||
|
||||
|
||||
local_expected_test_files=()
|
||||
test_path=""
|
||||
|
||||
add_path()
|
||||
{
|
||||
for i in "${files[@]}"
|
||||
do
|
||||
local_expected_test_files+=("$test_path$i")
|
||||
done
|
||||
}
|
||||
|
||||
#add_path
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
80
Tester/test_method.sh
Normal file
@@ -0,0 +1,80 @@
|
||||
#! /bin/bash
|
||||
|
||||
test_name="Method Test"
|
||||
|
||||
config_file="./Tester/test1.config"
|
||||
port=4040
|
||||
host="localhost"
|
||||
|
||||
paths=("/") # you can add many
|
||||
methods=("GET" "POST" "DELETE" "GUMBALL")
|
||||
#methods=("GET")
|
||||
httpz=("HTTP/1.1")
|
||||
|
||||
|
||||
|
||||
|
||||
# the parts we will send to webserv
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
header="Host: $host\n"
|
||||
header+="Nonsense: fu\n"
|
||||
|
||||
#header_cycle=("Transfer-encoding: fu" "Content-encoding: fu")
|
||||
|
||||
body=
|
||||
|
||||
|
||||
run_this_test()
|
||||
{
|
||||
|
||||
for i in "${methods[@]}"
|
||||
do
|
||||
l1="$i ${paths[0]} ${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\n" >> telnet.log
|
||||
done
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
# expected result...
|
||||
|
||||
files=()
|
||||
|
||||
file="expected_method_test.txt"
|
||||
files+=("expected_method_test.txt")
|
||||
#files+=("expected_path_root_test.txt")
|
||||
|
||||
|
||||
local_expected_test_files=()
|
||||
test_path=""
|
||||
|
||||
add_path()
|
||||
{
|
||||
for i in "${files[@]}"
|
||||
do
|
||||
local_expected_test_files+=("$test_path$i")
|
||||
done
|
||||
}
|
||||
|
||||
#add_path
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
74
Tester/test_path.sh
Normal file
@@ -0,0 +1,74 @@
|
||||
#! /bin/bash
|
||||
|
||||
test_name="Path Test"
|
||||
|
||||
config_file="./Tester/test1.config"
|
||||
port=4040
|
||||
host="localhost"
|
||||
|
||||
paths=("/" "/test" "/test/" "/list" "list" "/wrong") # you can add many
|
||||
#paths=("/") # you can add many
|
||||
#methods=("GET" "POST" "DELETE")
|
||||
methods=("GET")
|
||||
httpz=("HTTP/1.1")
|
||||
|
||||
|
||||
|
||||
l1="${methods[0]} ${paths[0]} ${httpz[0]}"
|
||||
|
||||
header="Host: $host\n"
|
||||
body=
|
||||
|
||||
|
||||
run_this_test()
|
||||
{
|
||||
|
||||
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_path_test.txt"
|
||||
files+=("expected_path_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
|
||||
|
||||
|
||||
|
||||
|
||||
73
Tester/test_port.sh
Normal file
@@ -0,0 +1,73 @@
|
||||
#! /bin/bash
|
||||
|
||||
test_name="Port Test"
|
||||
|
||||
config_file="./Tester/test3.config"
|
||||
port=8080
|
||||
host="localhost"
|
||||
|
||||
#paths=("/" "/test" "/test/" "/list" "list" "/wrong") # you can add many
|
||||
paths=("/") # you can add many
|
||||
#methods=("GET" "POST" "DELETE")
|
||||
methods=("GET")
|
||||
httpz=("HTTP/1.1")
|
||||
|
||||
|
||||
|
||||
l1="${methods[0]} ${paths[0]} ${httpz[0]}"
|
||||
|
||||
header="Host: $host"
|
||||
body=
|
||||
|
||||
|
||||
run_this_test()
|
||||
{
|
||||
|
||||
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_port_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
|
||||
|
||||
|
||||
|
||||
|
||||
62
Tester/test_template.sh
Normal file
@@ -0,0 +1,62 @@
|
||||
#! /bin/bash
|
||||
|
||||
test_name="Template test all good"
|
||||
|
||||
config_file="./Tester/test1.config"
|
||||
port=4040
|
||||
host="localhost"
|
||||
|
||||
paths=("/") # you can add many
|
||||
methods=("GET" "POST" "DELETE")
|
||||
#methods=("GET")
|
||||
httpz=("HTTP/1.1")
|
||||
|
||||
|
||||
|
||||
|
||||
# the parts we will send to webserv
|
||||
|
||||
|
||||
# let main.sh handle the l1
|
||||
|
||||
l1="${methods[0]} ${paths[0]} ${httpz[0]}"
|
||||
|
||||
header="Host: $host"
|
||||
body=
|
||||
|
||||
|
||||
run_this_test()
|
||||
{
|
||||
|
||||
for i in "${methods[@]}"
|
||||
do
|
||||
l1="$i ${paths[0]} ${httpz[0]}"
|
||||
request="$l1\n$header\n$body\n"
|
||||
{
|
||||
echo "----- $test_name -----"
|
||||
echo -e "$_RED$request$_END"
|
||||
} >> telnet.log
|
||||
# } &>> test.log
|
||||
# } 2>>&1
|
||||
# } &>> /dev/stdout
|
||||
echo -e "$request"
|
||||
# echo
|
||||
sleep 1
|
||||
# {
|
||||
# echo -e "\n------\n"
|
||||
# } > /dev/stdout
|
||||
# echo -e "\n\n\n------\n\n\n" >> telnet.out
|
||||
# echo -e "\n\n\n------\n\n\n" &> /dev/stdout
|
||||
echo -e "\n\n" >> telnet.log
|
||||
# echo -e "\n\n------\n\n" >> telnet.out
|
||||
# echo -e "\n------\n" > /dev/stdout
|
||||
# run_a_test
|
||||
# echo
|
||||
done
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
# expected result...
|
||||
|
||||
66
Tester/test_valid_uri.sh
Normal file
@@ -0,0 +1,66 @@
|
||||
#! /bin/bash
|
||||
|
||||
test_name="Valid URIs Test"
|
||||
|
||||
config_file="./Tester/test1.config"
|
||||
port=4040
|
||||
host="localhost"
|
||||
|
||||
paths=("/" "/stylesheet/style.css" "/test/something.html" "/test/something.html/" "/test/" "/list" "/hilarious_404" "/redirect") # you can add many
|
||||
#paths=("/") # you can add many
|
||||
#methods=("GET" "POST" "DELETE")
|
||||
methods=("GET")
|
||||
httpz=("HTTP/1.1")
|
||||
|
||||
|
||||
|
||||
l1="${methods[0]} ${paths[0]} ${httpz[0]}"
|
||||
|
||||
header="Host: $host"
|
||||
body=
|
||||
|
||||
|
||||
run_this_test()
|
||||
{
|
||||
|
||||
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_valid_uri_test.txt"
|
||||
files+=("expected_valid_files_test.txt")
|
||||
|
||||
local_expected_test_files=()
|
||||
test_path=""
|
||||
|
||||
add_path()
|
||||
{
|
||||
for i in "${files[@]}"
|
||||
do
|
||||
local_expected_test_files+=("$test_path$i")
|
||||
done
|
||||
}
|
||||
|
||||
#add_path
|
||||
|
||||
|
||||
|
||||
|
||||
BIN
Tester/www/Cagneyc_intro.gif
Normal file
|
After Width: | Height: | Size: 2.1 MiB |
BIN
Tester/www/Van_Eyck_Portrait_Arnolfini.jpg
Normal file
|
After Width: | Height: | Size: 2.0 MiB |
BIN
Tester/www/drill.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
11
Tester/www/error_pages/error_404.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<!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>
|
||||
BIN
Tester/www/favicon.ico
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
84
Tester/www/form_get.html
Normal file
@@ -0,0 +1,84 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title></title>
|
||||
<style>
|
||||
body {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
margin: auto;
|
||||
}
|
||||
form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1px solid red;
|
||||
margin: 20px auto;
|
||||
padding: 5px;
|
||||
}
|
||||
form > * {
|
||||
display: flex;
|
||||
margin: 5px auto 5px 5px;
|
||||
}
|
||||
mark {
|
||||
margin: 0px 3px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<form method="get" action="/cgi-bin/cgi_cpp.out">
|
||||
|
||||
<p><mark>get</mark> form</p>
|
||||
<p>to <mark>/cgi-bin/cgi_cpp.out</mark></p>
|
||||
<label for="fname">First name:</label><br>
|
||||
<input type="text" id="fname" name="fname" value="John"><br>
|
||||
<label for="lname">Last name:</label><br>
|
||||
<input type="text" id="lname" name="lname" value="Doe"><br><br>
|
||||
|
||||
<input type="submit" value="submit">
|
||||
</form>
|
||||
<br>
|
||||
|
||||
<form method="post" action="/cgi-bin/cgi_cpp.out">
|
||||
|
||||
<p><mark>post</mark> form</p>
|
||||
<p>to <mark>/cgi-bin/cgi_cpp.out</mark></p>
|
||||
<label for="fname">First name:</label><br>
|
||||
<input type="text" id="fname" name="fname" value="John"><br>
|
||||
<label for="lname">Last name:</label><br>
|
||||
<input type="text" id="lname" name="lname" value="Doe"><br><br>
|
||||
|
||||
<input type="submit" value="submit">
|
||||
</form>
|
||||
<br>
|
||||
|
||||
<form method="get" action="/cgi-bin/cgi_cpp_content_length.out">
|
||||
|
||||
<p><mark>get</mark> form</p>
|
||||
<p>to <mark>/cgi-bin/cgi_cpp_content_length.out</mark></p>
|
||||
<label for="fname">First name:</label><br>
|
||||
<input type="text" id="fname" name="fname" value="John"><br>
|
||||
<label for="lname">Last name:</label><br>
|
||||
<input type="text" id="lname" name="lname" value="Doe"><br><br>
|
||||
|
||||
<input type="submit" value="submit">
|
||||
</form>
|
||||
<br>
|
||||
|
||||
<form method="post" action="/cgi-bin/cgi_cpp_content_length.out">
|
||||
|
||||
<p><mark>post</mark> form</p>
|
||||
<p>to <mark>/cgi-bin/cgi_cpp_content_length.out</mark></p>
|
||||
<label for="fname">First name:</label><br>
|
||||
<input type="text" id="fname" name="fname" value="John"><br>
|
||||
<label for="lname">Last name:</label><br>
|
||||
<input type="text" id="lname" name="lname" value="Doe"><br><br>
|
||||
|
||||
<input type="submit" value="submit">
|
||||
</form>
|
||||
<br>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
11
Tester/www/index.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<!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>
|
||||
BIN
Tester/www/kermit.ico
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
Tester/www/punpun.png
Normal file
|
After Width: | Height: | Size: 310 KiB |
312
Tester/www/rfc2119.html
Normal file
@@ -0,0 +1,312 @@
|
||||
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||
<!-- saved from url=(0057)https://www.rfc-editor.org/rfc/inline-errata/rfc2119.html -->
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en"><head profile="http://dublincore.org/documents/2008/08/04/dc-html/"><meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||
|
||||
<meta name="robots" content="index,follow">
|
||||
|
||||
<link rel="icon" href="https://www.rfc-editor.org/rfc/inline-errata/css/images/rfc.png" type="image/png">
|
||||
<link rel="shortcut icon" href="https://www.rfc-editor.org/rfc/inline-errata/css/images/rfc.png" type="image/png">
|
||||
<title>rfc2119</title>
|
||||
|
||||
<link rel="stylesheet" type="text/css" href="./rfc2119_files/errata-base.css">
|
||||
<link rel="stylesheet" type="text/css" href="./rfc2119_files/errata-color.css" title="Default: Basic Colors">
|
||||
<link rel="alternative stylesheet" type="text/css" href="./rfc2119_files/errata-monochrome.css" title="Monochrome">
|
||||
<link rel="alternative stylesheet" type="text/css" href="./rfc2119_files/errata-printer.css" title="Printer">
|
||||
|
||||
<script src="./rfc2119_files/errata.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="Verified-headnote-styling">
|
||||
<span style="font-weight: bold;">This is a purely informative rendering of an RFC that includes verified errata. This rendering may not be used as a reference.</span>
|
||||
<br>
|
||||
<br>
|
||||
The following 'Verified' errata have been incorporated in this document:
|
||||
<a href="https://www.rfc-editor.org/rfc/inline-errata/rfc2119.html#eid493">EID 493</a>, <a href="https://www.rfc-editor.org/rfc/inline-errata/rfc2119.html#btn_494">EID 494</a>, <a href="https://www.rfc-editor.org/rfc/inline-errata/rfc2119.html#btn_495">EID 495</a>, <a href="https://www.rfc-editor.org/rfc/inline-errata/rfc2119.html#btn_494">EID 496</a>, <a href="https://www.rfc-editor.org/rfc/inline-errata/rfc2119.html#eid498">EID 498</a>, <a href="https://www.rfc-editor.org/rfc/inline-errata/rfc2119.html#btn_499">EID 499</a>, <a href="https://www.rfc-editor.org/rfc/inline-errata/rfc2119.html#eid500">EID 500</a>, <a href="https://www.rfc-editor.org/rfc/inline-errata/rfc2119.html#btn_5101">EID 5101</a>
|
||||
</div>
|
||||
|
||||
<pre>Network Working Group S. Bradner
|
||||
Request for Comments: 2119 Harvard University
|
||||
BCP: 14 March 1997
|
||||
Category: Best Current Practice
|
||||
|
||||
|
||||
Key words for use in RFCs to Indicate Requirement Levels
|
||||
|
||||
Status of this Memo
|
||||
|
||||
This document specifies an Internet Best Current Practices for the
|
||||
Internet Community, and requests discussion and suggestions for
|
||||
improvements. Distribution of this memo is unlimited.
|
||||
|
||||
Abstract
|
||||
|
||||
In many standards track documents several words are used to signify
|
||||
the requirements in the specification. These words are often
|
||||
capitalized. This document defines these words as they should be
|
||||
interpreted in IETF documents. Authors who follow these guidelines
|
||||
should incorporate this phrase near the beginning of their document:
|
||||
|
||||
<span class="Verified-inline-styling" id="inline-499"> The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL <button id="btn_499" target="expand_499" onclick="hideFunction("expand_499")">Expand</button>
|
||||
NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT
|
||||
RECOMMENDED", "MAY", and "OPTIONAL" in this document are to
|
||||
be interpreted as described in RFC 2119.</span>
|
||||
<div class="nodeCloseClass" id="expand_499"><div class="Verified-endnote-styling" id="eid499">
|
||||
<pre><b><i><a href="https://www.rfc-editor.org/errata/eid499">EID 499</a> (Verified) is as follows:</i></b>
|
||||
|
||||
<b>Section:</b> Abstract
|
||||
|
||||
<b>Original Text:</b>
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL
|
||||
NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and
|
||||
"OPTIONAL" in this document are to be interpreted as described in
|
||||
RFC 2119.
|
||||
|
||||
<b>Corrected Text:</b>
|
||||
|
||||
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL
|
||||
NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT
|
||||
RECOMMENDED", "MAY", and "OPTIONAL" in this document are to
|
||||
be interpreted as described in RFC 2119.
|
||||
</pre>
|
||||
<b>Notes:</b><br>
|
||||
The phrase "NOT RECOMMENDED" is missing from this sentence.
|
||||
</div>
|
||||
</div>
|
||||
Note that the force of these words is modified by the requirement
|
||||
level of the document in which they are used.
|
||||
|
||||
<span class="Verified-inline-styling" id="inline-495">1. MUST This word, or the terms "REQUIRED" or "SHALL", means that the <button id="btn_495" target="expand_495" onclick="hideFunction("expand_495")">Expand</button>
|
||||
definition is an absolute requirement of the specification.
|
||||
<div class="Verified-endnote-styling" id="eid493">
|
||||
<pre><b><i><a href="https://www.rfc-editor.org/errata/eid493">EID 493</a> (Verified) is as follows:</i></b>
|
||||
|
||||
<b>Section:</b> 1
|
||||
|
||||
<b>Original Text:</b>
|
||||
|
||||
2. MUST NOT This phrase, or the phrase "SHALL NOT", mean that the
|
||||
definition is an absolute prohibition of the specification.
|
||||
|
||||
<b>Corrected Text:</b>
|
||||
|
||||
2. MUST NOT This phrase, or the phrase "SHALL NOT", means that the
|
||||
definition is an absolute prohibition of the specification.
|
||||
</pre>
|
||||
<b>Notes:</b><br>
|
||||
|
||||
</div>
|
||||
<div class="Verified-endnote-styling" id="eid498">
|
||||
<pre><b><i><a href="https://www.rfc-editor.org/errata/eid498">EID 498</a> (Verified) is as follows:</i></b>
|
||||
|
||||
<b>Section:</b> 1
|
||||
|
||||
<b>Original Text:</b>
|
||||
|
||||
4. SHOULD NOT This phrase, or the phrase "NOT RECOMMENDED" mean that
|
||||
there may exist valid reasons in particular circumstances when the
|
||||
particular behavior is acceptable or even useful, but the full
|
||||
implications should be understood and the case carefully weighed
|
||||
before implementing any behavior described with this label.
|
||||
|
||||
<b>Corrected Text:</b>
|
||||
|
||||
4. SHOULD NOT This phrase, or the phrase "NOT RECOMMENDED", means that
|
||||
there may exist valid reasons in particular circumstances when the
|
||||
particular behavior is acceptable or even useful, but the full
|
||||
implications should be understood and the case carefully weighed
|
||||
before implementing any behavior described with this label.
|
||||
</pre>
|
||||
<b>Notes:</b><br>
|
||||
|
||||
</div>
|
||||
<div class="Verified-endnote-styling" id="eid500">
|
||||
<pre><b><i><a href="https://www.rfc-editor.org/errata/eid500">EID 500</a> (Verified) is as follows:</i></b>
|
||||
|
||||
<b>Section:</b> 1
|
||||
|
||||
<b>Original Text:</b>
|
||||
|
||||
3. SHOULD This word, or the adjective "RECOMMENDED", mean that there
|
||||
may exist valid reasons in particular circumstances to ignore a
|
||||
particular item, but the full implications must be understood and
|
||||
carefully weighed before choosing a different course.
|
||||
|
||||
<b>Corrected Text:</b>
|
||||
|
||||
3. SHOULD This word, or the adjective "RECOMMENDED", means that there
|
||||
may exist valid reasons in particular circumstances to ignore a
|
||||
particular item, but the full implications must be understood and
|
||||
carefully weighed before choosing a different course.
|
||||
</pre>
|
||||
<b>Notes:</b><br>
|
||||
|
||||
</div>
|
||||
</span>
|
||||
<div class="nodeCloseClass" id="expand_495"><div class="Verified-endnote-styling" id="eid495">
|
||||
<pre><b><i><a href="https://www.rfc-editor.org/errata/eid495">EID 495</a> (Verified) is as follows:</i></b>
|
||||
|
||||
<b>Section:</b> 1
|
||||
|
||||
<b>Original Text:</b>
|
||||
|
||||
1. MUST This word, or the terms "REQUIRED" or "SHALL", mean that the
|
||||
definition is an absolute requirement of the specification.
|
||||
|
||||
|
||||
<b>Corrected Text:</b>
|
||||
|
||||
1. MUST This word, or the terms "REQUIRED" or "SHALL", means that the
|
||||
definition is an absolute requirement of the specification.
|
||||
</pre>
|
||||
<b>Notes:</b><br>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
2. MUST NOT This phrase, or the phrase "SHALL NOT", mean that the
|
||||
definition is an absolute prohibition of the specification.
|
||||
|
||||
3. SHOULD This word, or the adjective "RECOMMENDED", mean that there
|
||||
may exist valid reasons in particular circumstances to ignore a
|
||||
particular item, but the full implications must be understood and
|
||||
carefully weighed before choosing a different course.
|
||||
|
||||
4. SHOULD NOT This phrase, or the phrase "NOT RECOMMENDED" mean that
|
||||
there may exist valid reasons in particular circumstances when the
|
||||
particular behavior is acceptable or even useful, but the full
|
||||
implications should be understood and the case carefully weighed
|
||||
before implementing any behavior described with this label.
|
||||
|
||||
<span class="Verified-inline-styling" id="inline-5101">5. MAY This word, or the adjective "OPTIONAL", mean that an item is <button id="btn_5101" target="expand_5101" onclick="hideFunction("expand_5101")">Expand</button>
|
||||
truly optional. One vendor may choose to include the item because a
|
||||
particular marketplace requires it or because the vendor feels that
|
||||
it enhances the product while another vendor may omit the same item.
|
||||
An implementation which does not include a particular option MUST be
|
||||
prepared to interoperate with another implementation which does
|
||||
include the option, though perhaps with reduced functionality. In the
|
||||
same vein an implementation which does include a particular option
|
||||
MUST be prepared to interoperate with another implementation which
|
||||
does not include the option (except, of course, for the feature the
|
||||
option provides).</span>
|
||||
<div class="nodeCloseClass" id="expand_5101"><div class="Verified-endnote-styling" id="eid5101">
|
||||
<pre><b><i><a href="https://www.rfc-editor.org/errata/eid5101">EID 5101</a> (Verified) is as follows:</i></b>
|
||||
|
||||
<b>Section:</b> 5
|
||||
|
||||
<b>Original Text:</b>
|
||||
|
||||
5. MAY This word, or the adjective "OPTIONAL", mean that an item is
|
||||
truly optional. One vendor may choose to include the item because a
|
||||
particular marketplace requires it or because the vendor feels that
|
||||
it enhances the product while another vendor may omit the same item.
|
||||
An implementation which does not include a particular option MUST be
|
||||
prepared to interoperate with another implementation which does
|
||||
include the option, though perhaps with reduced functionality. In the
|
||||
same vein an implementation which does include a particular option
|
||||
MUST be prepared to interoperate with another implementation which
|
||||
does not include the option (except, of course, for the feature the
|
||||
option provides.)
|
||||
|
||||
<b>Corrected Text:</b>
|
||||
|
||||
5. MAY This word, or the adjective "OPTIONAL", mean that an item is
|
||||
truly optional. One vendor may choose to include the item because a
|
||||
particular marketplace requires it or because the vendor feels that
|
||||
it enhances the product while another vendor may omit the same item.
|
||||
An implementation which does not include a particular option MUST be
|
||||
prepared to interoperate with another implementation which does
|
||||
include the option, though perhaps with reduced functionality. In the
|
||||
same vein an implementation which does include a particular option
|
||||
MUST be prepared to interoperate with another implementation which
|
||||
does not include the option (except, of course, for the feature the
|
||||
option provides).
|
||||
</pre>
|
||||
<b>Notes:</b><br>
|
||||
Full stop should appear outside the parentheses in the last sentence.
|
||||
</div>
|
||||
</div>
|
||||
6. Guidance in the use of these Imperatives
|
||||
|
||||
Imperatives of the type defined in this memo must be used with care
|
||||
and sparingly. In particular, they MUST only be used where it is
|
||||
actually required for interoperation or to limit behavior which has
|
||||
potential for causing harm <span class="Verified-inline-styling" id="inline-494">(e.g., limiting retransmissions)</span> For <button id="btn_494" target="expand_494" onclick="hideFunction("expand_494")">Expand Multiple</button>
|
||||
<div class="nodeCloseClass" id="expand_494"><div class="Verified-endnote-styling" id="eid494">
|
||||
<pre><b><i><a href="https://www.rfc-editor.org/errata/eid494">EID 494</a> (Verified) is as follows:</i></b>
|
||||
|
||||
<b>Section:</b> 6
|
||||
|
||||
<b>Original Text:</b>
|
||||
|
||||
(e.g., limiting retransmisssions)
|
||||
|
||||
<b>Corrected Text:</b>
|
||||
|
||||
(e.g., limiting retransmissions)
|
||||
</pre>
|
||||
<b>Notes:</b><br>
|
||||
|
||||
</div>
|
||||
<div class="Verified-endnote-styling" id="eid496">
|
||||
<pre><b><i><a href="https://www.rfc-editor.org/errata/eid496">EID 496</a> (Verified) is as follows:</i></b>
|
||||
|
||||
<b>Section:</b> 6
|
||||
|
||||
<b>Original Text:</b>
|
||||
|
||||
In particular, they MUST only be used where it is actually required
|
||||
for interoperation or to limit behavior which has potential for
|
||||
causing harm (e.g., limiting retransmisssions) For example, they
|
||||
must not be used to try to impose a particular method on
|
||||
implementors where the method is not required for interoperability.
|
||||
|
||||
<b>Corrected Text:</b>
|
||||
|
||||
In particular, they MUST only be used where it is actually required
|
||||
for interoperation or to limit behavior which has potential for
|
||||
causing harm (e.g., limiting retransmissions). For example, they
|
||||
must not be used to try to impose a particular method on
|
||||
implementors where the method is not required for interoperability.
|
||||
</pre>
|
||||
<b>Notes:</b><br>
|
||||
|
||||
</div>
|
||||
</div> example, they must not be used to try to impose a particular method
|
||||
on implementors where the method is not required for
|
||||
interoperability.
|
||||
|
||||
7. Security Considerations
|
||||
|
||||
These terms are frequently used to specify behavior with security
|
||||
implications. The effects on security of not implementing a MUST or
|
||||
SHOULD, or doing something the specification says MUST NOT or SHOULD
|
||||
NOT be done may be very subtle. Document authors should take the time
|
||||
to elaborate the security implications of not following
|
||||
recommendations or requirements as most implementors will not have
|
||||
had the benefit of the experience and discussion that produced the
|
||||
specification.
|
||||
|
||||
8. Acknowledgments
|
||||
|
||||
The definitions of these terms are an amalgam of definitions taken
|
||||
from a number of RFCs. In addition, suggestions have been
|
||||
incorporated from a number of people including Robert Ullmann, Thomas
|
||||
Narten, Neal McBurnett, and Robert Elz.
|
||||
|
||||
9. Author's Address
|
||||
|
||||
Scott Bradner
|
||||
Harvard University
|
||||
1350 Mass. Ave.
|
||||
Cambridge, MA 02138
|
||||
|
||||
phone - +1 617 495 3864
|
||||
|
||||
email - sob@harvard.edu
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</pre></body></html>
|
||||
139
Tester/www/rfc2119_files/errata-base.css
Normal file
@@ -0,0 +1,139 @@
|
||||
<style type="text/css">
|
||||
@media only screen
|
||||
and (min-width: 992px)
|
||||
and (max-width: 1199px) {
|
||||
body { font-size: 14pt; }
|
||||
div.content { width: 96ex; margin: 0 auto; }
|
||||
}
|
||||
@media only screen
|
||||
and (min-width: 768px)
|
||||
and (max-width: 991px) {
|
||||
body { font-size: 14pt; }
|
||||
div.content { width: 96ex; margin: 0 auto; }
|
||||
}
|
||||
@media only screen
|
||||
and (min-width: 480px)
|
||||
and (max-width: 767px) {
|
||||
body { font-size: 11pt; }
|
||||
div.content { width: 96ex; margin: 0 auto; }
|
||||
}
|
||||
@media only screen
|
||||
and (max-width: 479px) {
|
||||
body { font-size: 8pt; }
|
||||
div.content { width: 96ex; margin: 0 auto; }
|
||||
}
|
||||
@media only screen
|
||||
and (min-device-width : 375px)
|
||||
and (max-device-width : 667px) {
|
||||
body { font-size: 9.5pt; }
|
||||
div.content { width: 96ex; margin: 0; }
|
||||
}
|
||||
@media only screen
|
||||
and (min-device-width: 1200px) {
|
||||
body { font-size: 10pt; margin: 0 4em; }
|
||||
div.content { width: 96ex; margin: 0; }
|
||||
}
|
||||
h1, h2, h3, h4, h5, h6, .h1, .h2, .h3, .h4, .h5, .h6 {
|
||||
font-weight: bold;
|
||||
line-height: 0pt;
|
||||
display: inline;
|
||||
white-space: pre;
|
||||
font-family: monospace;
|
||||
font-size: 1em;
|
||||
font-weight: bold;
|
||||
}
|
||||
pre {
|
||||
font-size: 1em;
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
.pre {
|
||||
white-space: pre;
|
||||
font-family: monospace;
|
||||
}
|
||||
.header{
|
||||
font-weight: bold;
|
||||
}
|
||||
.newpage {
|
||||
page-break-before: always;
|
||||
}
|
||||
.invisible {
|
||||
text-decoration: none;
|
||||
color: white;
|
||||
}
|
||||
a.selflink {
|
||||
color: black;
|
||||
text-decoration: none;
|
||||
}
|
||||
@media print {
|
||||
body {
|
||||
font-family: monospace;
|
||||
font-size: 10.5pt;
|
||||
}
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
a:link, a:visited {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
.noprint {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@media screen {
|
||||
.grey, .grey a:link, .grey a:visited {
|
||||
color: #777;
|
||||
}
|
||||
.docinfo {
|
||||
background-color: #EEE;
|
||||
}
|
||||
.top {
|
||||
border-top: 7px solid #EEE;
|
||||
}
|
||||
.bgwhite { background-color: white; }
|
||||
.bgred { background-color: #F44; }
|
||||
.bggrey { background-color: #666; }
|
||||
.bgbrown { background-color: #840; }
|
||||
.bgorange { background-color: #FA0; }
|
||||
.bgyellow { background-color: #EE0; }
|
||||
.bgmagenta{ background-color: #F4F; }
|
||||
.bgblue { background-color: #66F; }
|
||||
.bgcyan { background-color: #4DD; }
|
||||
.bggreen { background-color: #4F4; }
|
||||
|
||||
.legend { font-size: 90%; }
|
||||
.cplate { font-size: 70%; border: solid grey 1px; }
|
||||
}
|
||||
|
||||
|
||||
.Verified-headnote-styling, .Held-headnote-styling, .Reported-headnote-styling, .Rejected-headnote-styling {
|
||||
border:dashed;
|
||||
margin:8px;
|
||||
padding;24px;
|
||||
overflow-wrap: normal;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.Verified-endnote-styling, .Held-endnote-styling, .Reported-endnote-styling, .Rejected-endnote-styling {
|
||||
border:dashed;
|
||||
margin:8px;
|
||||
padding:24px;
|
||||
overflow:auto;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.Verified-ineline-styling, .Held-ineline-styling, .Reported-ineline-styling, .Rejected-ineline-styling {
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.nodeCloseClass {
|
||||
display:none;
|
||||
}
|
||||
|
||||
.nodeOpenClass {
|
||||
display:inline;
|
||||
}
|
||||
|
||||
</style>
|
||||
43
Tester/www/rfc2119_files/errata-color.css
Normal file
@@ -0,0 +1,43 @@
|
||||
<style type="text/css">
|
||||
.verified {color: green}
|
||||
.supplementary-styling {
|
||||
background-color: yellow
|
||||
}
|
||||
.old-text {color: red}
|
||||
|
||||
.Verified-headnote-styling, .Verified-endnote-styling {
|
||||
background-color: LightGreen;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.Verified-inline-styling {
|
||||
color: Green;
|
||||
}
|
||||
|
||||
.Held-headnote-styling, .Held-endnote-styling {
|
||||
background-color: LightBlue;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.Held-inline-styling {
|
||||
color: Blue;
|
||||
}
|
||||
|
||||
.Reported-headnote-styling, .Reported-endnote-styling {
|
||||
background-color: Beige;
|
||||
}
|
||||
|
||||
.Reported-inline-styling {
|
||||
color:GoldenRod;
|
||||
}
|
||||
|
||||
.Rejected-headnote-styling, .Rejected-endnote-styling {
|
||||
background-color: LightPink;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.Rejected-inline-styling {
|
||||
color: red;
|
||||
}
|
||||
|
||||
</style>
|
||||
34
Tester/www/rfc2119_files/errata-monochrome.css
Normal file
@@ -0,0 +1,34 @@
|
||||
<style type="text/css">
|
||||
.Verified-headnote-styling, .Verified-endnote-styling {
|
||||
font-wieght: bold;
|
||||
}
|
||||
.Verified-inline-styling {
|
||||
font-wieght: bold;
|
||||
background-color: lightGrey;
|
||||
}
|
||||
|
||||
.Held-headnote-styling, .Held-endnote-styling {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.Held-inline-styling {
|
||||
font-style: italic;
|
||||
background-color: lightGrey;
|
||||
}
|
||||
|
||||
.Reported-headnote-styling, .Reported-endnote-styling {
|
||||
background-color: Beige;
|
||||
}
|
||||
|
||||
.Reported-inline-styling {
|
||||
color: Yellow;
|
||||
}
|
||||
|
||||
.Rejected-headnote-styling, .Rejected-endnote-styling {
|
||||
background-color: LightPink;
|
||||
}
|
||||
|
||||
.Rejected-inline-styling {
|
||||
color: red;
|
||||
}
|
||||
</style>
|
||||
43
Tester/www/rfc2119_files/errata-printer.css
Normal file
@@ -0,0 +1,43 @@
|
||||
<style type="text/css">
|
||||
.Verified-headnote-styling, .Verified-endnote-styling {
|
||||
font-wieght: bold;
|
||||
}
|
||||
.Verified-inline-styling {
|
||||
font-wieght: bold;
|
||||
background-color: lightGrey;
|
||||
}
|
||||
|
||||
.Held-headnote-styling, .Held-endnote-styling {
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.Held-inline-styling {
|
||||
font-style: italic;
|
||||
background-color: lightGrey;
|
||||
}
|
||||
|
||||
.Reported-headnote-styling, .Reported-endnote-styling {
|
||||
background-color: Beige;
|
||||
}
|
||||
|
||||
.Reported-inline-styling {
|
||||
color: Yellow;
|
||||
}
|
||||
|
||||
.Rejected-headnote-styling, .Rejected-endnote-styling {
|
||||
background-color: LightPink;
|
||||
}
|
||||
|
||||
.Rejected-inline-styling {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.nodeCloseClass {
|
||||
display:inline;
|
||||
}
|
||||
|
||||
.nodeOpenClass {
|
||||
display:inline;
|
||||
}
|
||||
|
||||
</style>
|
||||
4
Tester/www/rfc2119_files/errata.js
Normal file
@@ -0,0 +1,4 @@
|
||||
function hideFunction(nodeId) {
|
||||
var ul = document.getElementById(nodeId)
|
||||
ul.className = (ul.className=="nodeOpenClass") ? "nodeCloseClass" : "nodeOpenClass"
|
||||
}
|
||||
4
Tester/www/rfc2119_files/errata.js.téléchargement
Normal file
@@ -0,0 +1,4 @@
|
||||
function hideFunction(nodeId) {
|
||||
var ul = document.getElementById(nodeId)
|
||||
ul.className = (ul.className=="nodeOpenClass") ? "nodeCloseClass" : "nodeOpenClass"
|
||||
}
|
||||
BIN
Tester/www/root.png
Normal file
|
After Width: | Height: | Size: 446 KiB |
12
Tester/www/test/index1.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<!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>
|
||||
11
Tester/www/test/something.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<!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>
|
||||
17
Tester/www/test/submit_form.html
Normal file
@@ -0,0 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Webserv test Something</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1 style="text-align:center">Webserv in Test</h1>
|
||||
<hr>
|
||||
<p style="text-align:center">Time to submit something:</p>
|
||||
<!-- <form action="./srcs/cgi-bin/upload_file.php" method="post" enctype="multipart/form-data"> -->
|
||||
<form action="/uploaded" method="post" enctype="multipart/form-data">
|
||||
<!-- <input type="hidden" name="upload_dir" value="./www/uploaded/"> -->
|
||||
<input type="file" id="fileToUpload" name="myFile">
|
||||
<input type="submit" value="Upload File">
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
11
Tester/www/test/test_deeper/index1.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Webserv Test Deeper Index</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1 style="text-align:center">Webserv Test Deeper Index</h1>
|
||||
<hr>
|
||||
<p style="text-align:center">(˚3˚)</p>
|
||||
</body>
|
||||
</html>
|
||||
11
Tester/www/test/test_deeper/something.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Webserv test deeper Something</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1 style="text-align:center">Webserv Test Deeper Something</h1>
|
||||
<hr>
|
||||
<p style="text-align:center">(˚3˚)</p>
|
||||
</body>
|
||||
</html>
|
||||
11
Tester/www/test/test_deeper/super_deep/something.html
Normal file
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Webserv test deeper Something</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1 style="text-align:center">Webserv Test Super Deep Something</h1>
|
||||
<hr>
|
||||
<p style="text-align:center">(˚3˚)</p>
|
||||
</body>
|
||||
</html>
|
||||
12
Tester/www/upload_form.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<!--
|
||||
https://www.w3schools.com/howto/howto_html_file_upload_button.asp
|
||||
https://www.filestack.com/fileschool/html/html-file-upload-tutorial-example/
|
||||
https://www.rfc-editor.org/rfc/rfc9110#name-multipart-types
|
||||
https://www.rfc-editor.org/rfc/rfc2046#section-5.1.1
|
||||
-->
|
||||
<form action="/upload" method="post" enctype="multipart/form-data">
|
||||
<input type="file" name="upload_file1">
|
||||
<input type="file" name="upload_file2">
|
||||
<input type="file" name="upload_file3">
|
||||
<input type="submit">
|
||||
</form>
|
||||
10
Tester/www/upload_form_single.html
Normal file
@@ -0,0 +1,10 @@
|
||||
<!--
|
||||
https://www.w3schools.com/howto/howto_html_file_upload_button.asp
|
||||
https://www.filestack.com/fileschool/html/html-file-upload-tutorial-example/
|
||||
https://www.rfc-editor.org/rfc/rfc9110#name-multipart-types
|
||||
https://www.rfc-editor.org/rfc/rfc2046#section-5.1.1
|
||||
-->
|
||||
<form action="/upload" method="post" enctype="multipart/form-data">
|
||||
<input type="file" name="upload_file1">
|
||||
<input type="submit">
|
||||
</form>
|
||||
@@ -0,0 +1 @@
|
||||
inside YoupiBanane/Yeah/not_happy.bad_extension
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
inside YoupiBanane/nop/other.pouic
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
inside YoupiBanane/nop/youpi.bad_extension
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
inside YoupiBanane/youpi.bad_extension
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
inside YoupiBanane/youpi.bla
|
||||
|
||||
29
compare.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>
|
||||
@@ -1,23 +1,109 @@
|
||||
|
||||
server {
|
||||
|
||||
# this is a comment
|
||||
|
||||
server_name our_server;
|
||||
server_name server1;
|
||||
|
||||
listen 0.0.0.0:4040;
|
||||
|
||||
# client_body_limit asdfa;
|
||||
# client_body_limit 400;
|
||||
client_body_limit 5000;
|
||||
# Max == 18446744073709551615 / 1024 == 18014398509481984
|
||||
|
||||
|
||||
index index.html; # this is another comment
|
||||
#index mdr.html; # this is another comment
|
||||
|
||||
root ./www/;
|
||||
|
||||
# If not explicitly set, ConfigParser need to genererate a location block
|
||||
# like this for path "/" (based on field "root" and "index" of the server)
|
||||
# error_page 404 ./www/error_pages/error_404.html;
|
||||
# error_page 403 ./www/error_pages/error_404.html;
|
||||
|
||||
|
||||
# location /kapouet {
|
||||
# root /tmp/www;
|
||||
# }
|
||||
|
||||
location / {
|
||||
allow_methods GET;
|
||||
root ./www/;
|
||||
index index.html;
|
||||
}
|
||||
|
||||
allow_methods GET;
|
||||
# location /srcs/cgi-bin/ {
|
||||
# root ./srcs/cgi-bin/;
|
||||
# allow_methods POST;
|
||||
# cgi_ext php;
|
||||
# }
|
||||
#
|
||||
# location /list {
|
||||
# autoindex on;
|
||||
# }
|
||||
|
||||
|
||||
location /cgi-bin {
|
||||
root ./srcs/cgi-bin/;
|
||||
cgi_ext out php sh;
|
||||
}
|
||||
|
||||
# location /upload {
|
||||
# allow_methods POST;
|
||||
# upload_dir ./www/user_files/;
|
||||
# # 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;
|
||||
# }
|
||||
#
|
||||
#}
|
||||
#
|
||||
#server {
|
||||
# server_name server2;
|
||||
#
|
||||
# listen 0.0.0.0:8080;
|
||||
#
|
||||
# index index.html;
|
||||
# root ./www2/;
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>404 Not Found</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1 style="text-align:center">404 Not Found</h1>
|
||||
<hr>
|
||||
<p style="text-align:center">Le Webserv/0.1</p>
|
||||
</body>
|
||||
</html>
|
||||
117
main_test.sh
Executable file
@@ -0,0 +1,117 @@
|
||||
#! /bin/bash
|
||||
|
||||
|
||||
# import and run all tests
|
||||
|
||||
|
||||
##########
|
||||
# Colors
|
||||
##########
|
||||
|
||||
|
||||
_GREY='\033[30m'
|
||||
_RED='\033[0;31m'
|
||||
_GREEN='\033[32m'
|
||||
_YELLOW='\033[33m'
|
||||
_BLUE='\033[34m'
|
||||
_PURPLE='\033[35m'
|
||||
_CYAN='\033[36m'
|
||||
_WHITE='\033[37m'
|
||||
_END='\033[0m'
|
||||
|
||||
|
||||
#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_valid_uri.sh" "test_delete.sh")
|
||||
|
||||
# Run this separately cuz of the content length subtlty
|
||||
#test_file_names=("test_body.sh")
|
||||
|
||||
# kinda fucking useless, easier to test IRL
|
||||
#test_file_names=("test_port.sh")
|
||||
|
||||
test_files=()
|
||||
expected_result_files=()
|
||||
|
||||
fill_test_files()
|
||||
{
|
||||
for i in "${test_file_names[@]}"
|
||||
do
|
||||
test_files+=("./Tester/$i")
|
||||
done
|
||||
}
|
||||
|
||||
# needs to be invoked for each test_file!
|
||||
# acutally kinda useless...
|
||||
fill_expected_files()
|
||||
{
|
||||
for i in "${local_expected_test_files[@]}"
|
||||
do
|
||||
expected_result_files+=("./Tester/expected_results/$i")
|
||||
done
|
||||
}
|
||||
|
||||
|
||||
|
||||
test_all()
|
||||
{
|
||||
|
||||
arg=${1}
|
||||
|
||||
make
|
||||
|
||||
rm -rf telnet.log
|
||||
rm -rf webserv.log
|
||||
rm -rf compare.txt
|
||||
rm -rf expected.txt
|
||||
|
||||
fill_test_files
|
||||
|
||||
for i in "${test_files[@]}"
|
||||
do
|
||||
source $i
|
||||
source ./Tester/telnet_test.sh
|
||||
|
||||
./webserv $config_file &>> webserv.log &
|
||||
echo -e "${_GREEN}Running Telnet Test on '$test_name'${_END}"
|
||||
sleep 1
|
||||
run | telnet | tee compare.txt >> telnet.log
|
||||
# run | telnet > compare.txt >> telnet.log
|
||||
# run | telnet >> telnet.log
|
||||
pkill webserv
|
||||
echo -e "\n\n------\n" &>> webserv.log
|
||||
|
||||
fill_expected_files
|
||||
expected_result_file="./Tester/expected_results/$file"
|
||||
|
||||
if [ "$arg" = "diff" ];
|
||||
then
|
||||
DIFF=$(diff -q compare.txt $expected_result_file)
|
||||
if [ "$DIFF" == "" ];
|
||||
then
|
||||
echo "Good diff"
|
||||
else
|
||||
diff compare.txt $expected_result_file
|
||||
fi
|
||||
elif [ "$arg" = "create" ];
|
||||
then
|
||||
if ! test -f $expected_result_file;
|
||||
then
|
||||
cat compare.txt > $expected_result_file
|
||||
fi
|
||||
elif [ "$arg" = "replace" ];
|
||||
then
|
||||
cat compare.txt > $expected_result_file
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
if [ "$arg" = "" ];
|
||||
then
|
||||
cat telnet.log
|
||||
fi
|
||||
|
||||
|
||||
}
|
||||
|
||||
test_all $1
|
||||
|
||||
59
memo.txt
@@ -1,21 +1,56 @@
|
||||
----Priorité élevée------------------------
|
||||
|
||||
- curl --resolve, for testing hostname
|
||||
curl -v --resolve server1:4040:127.0.0.1 --resolve server2:4040:127.0.0.1 server1:4040
|
||||
- test limit de connexions sur listen()
|
||||
|
||||
- handle redirection (Work, but weird behavior need deeper test)
|
||||
- Ecrire des tests !
|
||||
|
||||
----Priorité modérée------------------------
|
||||
- namespace utils ?
|
||||
- change "std::string" to reference "std::string &" in most functions
|
||||
and add "const" if apropriate.
|
||||
- peut-être check si ip > 32bits
|
||||
|
||||
----Priorité faible------------------------
|
||||
- idealy, we should not clear() raw_request after a response,
|
||||
but just the part we actually parsed for this 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 only for HTTP/2 adn HTTP/3 raw_request could contain more than the first request we handle.
|
||||
- chunked request (need testing)
|
||||
- client_body_limit 0 valeur special pour desactiver dans config
|
||||
- gerer le champ "Accept" du client
|
||||
- gerer les ".." dans un URL (verifier que l'on ne sort pas du dossier "root")
|
||||
- do correct handling of special character in url (/rfc2119_files/errata.js.t%C3%A9l%C3%A9chargement -> /rfc2119_files/errata.js.téléchargement)
|
||||
- handle redirection
|
||||
- maybe add a "last_action_time" in Client for timeout handling
|
||||
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)}
|
||||
- add headers "Date" and "Last-Modified" to response
|
||||
- change "std::string" to reference "std::string &" in most functions
|
||||
and add "const" if apropriate.
|
||||
- http_method en mode binary flags. "std::vector<http_method> allow_methods" -> "unsigned int allow_methods;"
|
||||
- Dans le parsing, trier les "locations" par ordre de precision.
|
||||
Compter les "/" dans le chemin, les locations avec le plus de "/" seront en premier dans le vector.
|
||||
- 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 ! :
|
||||
==847174== 1,314 bytes in 1 blocks are definitely lost in loss record 1 of 1
|
||||
==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 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_r_from_child&) (run_loop.cpp:39) // (LUKE: its an string.append() call)
|
||||
==847174== by 0x427962: Webserv::run() (run_loop.cpp:153)
|
||||
==847174== by 0x4052E9: main (main.cpp:38)
|
||||
|
||||
__________________________
|
||||
--------------------------
|
||||
|
||||
----Discord 42------------
|
||||
Un truc cool et surtout bien utile ici c'est d'utiliser un proxy entre ton navigateur et ton serveur pour vérifier ce qui est envoyé en raw. Les navigateurs peuvent avoir des comportements différents.
|
||||
Vous avez des modules sur vos navigateur ou des logiciels externe. C'est assez rapide et gratuit.
|
||||
RESOLVED, AGAIN :D !
|
||||
--loop epoll()
|
||||
EPOLLHUP on client fd 8
|
||||
47067----loop epoll()
|
||||
EPOLLHUP on client fd 8
|
||||
47068----loop epoll()
|
||||
EPOLLHUP on client fd 8
|
||||
47069----loop epoll()
|
||||
EPOLLHUP on client fd 8
|
||||
47070----loop epoll()
|
||||
EPOLLHUP on client fd 8
|
||||
47071----loop epoll()
|
||||
EPOLLHUP on client fd 8
|
||||
47072----loop epoll()
|
||||
EPOLLHUP on client fd 8
|
||||
47073----loop epoll()
|
||||
|
||||
53
multipart_request.txt
Normal file
@@ -0,0 +1,53 @@
|
||||
POST /upload HTTP/1.1
|
||||
Host: localhost:4040
|
||||
Connection: keep-alive
|
||||
Content-Length: 364
|
||||
Cache-Control: max-age=0
|
||||
sec-ch-ua: "Chromium";v="104", " Not A;Brand";v="99", "Google Chrome";v="104"
|
||||
sec-ch-ua-mobile: ?0
|
||||
sec-ch-ua-platform: "Windows"
|
||||
Upgrade-Insecure-Requests: 1
|
||||
Origin: http://localhost:4040
|
||||
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryeIV4xrEzThmNUcJf
|
||||
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36
|
||||
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
|
||||
Sec-Fetch-Site: same-origin
|
||||
Sec-Fetch-Mode: navigate
|
||||
Sec-Fetch-User: ?1
|
||||
Sec-Fetch-Dest: document
|
||||
Referer: http://localhost:4040/upload_form.html
|
||||
Accept-Encoding: gzip, deflate, br
|
||||
Accept-Language: fr-FR,fr;q=0.9,en-US;q=0.8,en;q=0.7
|
||||
dnt: 1
|
||||
sec-gpc: 1
|
||||
|
||||
------WebKitFormBoundaryeIV4xrEzThmNUcJf
|
||||
Content-Disposition: form-data; name="upload_file"; filename=".gitignore"
|
||||
Content-Type: text/plain
|
||||
|
||||
.DS_Store
|
||||
Thumbs.db
|
||||
*.o
|
||||
*.d
|
||||
*.swp
|
||||
*.out
|
||||
*.exe
|
||||
*.stackdump
|
||||
*.a
|
||||
*.so
|
||||
*.dSYM
|
||||
.vscode
|
||||
*.lnk
|
||||
*.zip
|
||||
|
||||
builds
|
||||
|
||||
ubuntu_tester
|
||||
ubuntu_cgi_tester
|
||||
webserv
|
||||
!**/webserv/
|
||||
*.log
|
||||
|
||||
large.jpg
|
||||
|
||||
------WebKitFormBoundaryeIV4xrEzThmNUcJf--
|
||||
1
siege.txt
Normal file
@@ -0,0 +1 @@
|
||||
http://localhost:4040/cgi-bin/cgi_cpp_empty.out?fname=John&lname=Doe
|
||||
488
srcs/Client.cpp
@@ -1,29 +1,48 @@
|
||||
|
||||
#include "Client.hpp"
|
||||
|
||||
char Client::buf[MAX_FILESIZE+1];
|
||||
|
||||
|
||||
/*********************************************
|
||||
* COPLIENS
|
||||
*********************************************/
|
||||
|
||||
Client::Client()
|
||||
: body_size(0)
|
||||
, status(0)
|
||||
, _fd(0)
|
||||
: status(0),
|
||||
header_complete(false),
|
||||
body_complete(false),
|
||||
request_complete(false),
|
||||
assigned_server(NULL),
|
||||
assigned_location(NULL),
|
||||
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),
|
||||
_fd(-1),
|
||||
_port(""),
|
||||
_ip(""),
|
||||
_lsocket(NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
//Client::Client(int afd, listen_socket *lsocket, struct sockaddr_in addr)
|
||||
Client::Client(int afd, listen_socket *lsocket, std::string aport, std::string aip)
|
||||
: body_size(0)
|
||||
, status(0)
|
||||
, _fd(afd)
|
||||
, _port(aport)
|
||||
, _ip(aip)
|
||||
, _lsocket(lsocket)
|
||||
: status(0),
|
||||
header_complete(false),
|
||||
body_complete(false),
|
||||
request_complete(false),
|
||||
assigned_server(NULL),
|
||||
assigned_location(NULL),
|
||||
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),
|
||||
_fd(afd),
|
||||
_port(aport),
|
||||
_ip(aip),
|
||||
_lsocket(lsocket)
|
||||
{
|
||||
return;
|
||||
}
|
||||
@@ -32,24 +51,25 @@ Client::~Client() {
|
||||
return;
|
||||
}
|
||||
|
||||
// WIP placeholder because of const values
|
||||
/* // WIP not sure fo what is more logic here
|
||||
Client::Client( Client const & src )
|
||||
: body_size(0)
|
||||
, status(0)
|
||||
, _fd ( src._fd )
|
||||
, _port ( src._port )
|
||||
, _ip ( src._ip )
|
||||
, _lsocket ( src._lsocket )
|
||||
: status ( src.status ),
|
||||
header_complete ( src.header_complete ),
|
||||
assigned_server ( src.assigned_server ),
|
||||
assigned_location ( src.assigned_location ),
|
||||
_fd ( src._fd ),
|
||||
_port ( src._port ),
|
||||
_ip ( src._ip ),
|
||||
_lsocket ( src._lsocket )
|
||||
{
|
||||
raw_request = src.raw_request;
|
||||
response = src.response;
|
||||
// buf = strdup(src.buf); // TODO: this doesn't work
|
||||
body_size = src.body_size;
|
||||
status = src.status;
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
// WIP placeholder because of const values
|
||||
/* // WIP placeholder because of const values
|
||||
Client & Client::operator=( Client const & rhs )
|
||||
{
|
||||
if ( this != &rhs )
|
||||
@@ -58,70 +78,187 @@ Client & Client::operator=( Client const & rhs )
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
/*********************************************
|
||||
* PUBLIC MEMBER FUNCTIONS
|
||||
*********************************************/
|
||||
|
||||
// http headers :
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers
|
||||
// https://www.ibm.com/docs/en/cics-ts/5.3?topic=protocol-http-requests
|
||||
// https://www.tutorialspoint.com/http/http_requests.htm
|
||||
void Client::parse_request()
|
||||
/* HTTP Headers :
|
||||
https://www.iana.org/assignments/http-fields/http-fields.xhtml
|
||||
https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers
|
||||
https://www.ibm.com/docs/en/cics-ts/5.3?topic=protocol-http-requests
|
||||
https://www.tutorialspoint.com/http/http_requests.htm
|
||||
*/
|
||||
void Client::parse_request_headers(std::vector<ServerConfig> &servers)
|
||||
{
|
||||
std::map<std::string, std::string> headers;
|
||||
std::string body;
|
||||
|
||||
// DEBUG
|
||||
std::cout << "\nREQUEST ____________\n" << raw_request << "\n_____________\n";
|
||||
if (raw_request.find(CRLF CRLF) == NPOS)
|
||||
return ;
|
||||
header_complete = true;
|
||||
clear_request_vars(); // not mandatory
|
||||
|
||||
_parse_request_line();
|
||||
_parse_request_headers();
|
||||
_parse_request_body();
|
||||
_parse_port_hostname(this->get_rq_headers("Host"));
|
||||
raw_request.clear();
|
||||
if (status)
|
||||
return;
|
||||
_parse_request_fields();
|
||||
|
||||
// DEBUG
|
||||
// print_client("headers");
|
||||
|
||||
if (status)
|
||||
return;
|
||||
assigned_server = _determine_process_server(this, servers);
|
||||
assigned_location = _determine_location(*assigned_server, _request.abs_path);
|
||||
_check_request_errors();
|
||||
if (status)
|
||||
return;
|
||||
|
||||
// DEBUG
|
||||
// std::cerr << get_rq_method_str() << " " << get_rq_target() << " " << get_rq_version() << "\n";
|
||||
|
||||
// dont clear raw_request, we need it for future reparsing of body
|
||||
// see call of parse_request() in _read_request()
|
||||
// raw_request.clear();
|
||||
}
|
||||
|
||||
bool Client::fill_script_path(std::string script)
|
||||
void Client::parse_request_body()
|
||||
{
|
||||
std::cerr << "parse_request_body()\n";
|
||||
size_t pos;
|
||||
|
||||
pos = raw_request.find(CRLF CRLF);
|
||||
if (pos == NPOS)
|
||||
{
|
||||
std::cerr << "parse_request_body() bad call, header incomplete\n";
|
||||
// QUESTION from hugo : don't we change the status here ?
|
||||
// RESPONSE from luke : C'est vrai. Peut-être mettre un 500, c'etait plus du debug à la base.
|
||||
// C'est seulement si on appelle la fonction au mauvais endroit, avant d'avoir un header complet, que ça arrive.
|
||||
return;
|
||||
}
|
||||
|
||||
if (!get_rq_headers("Transfer-Encoding").empty()
|
||||
&& get_rq_headers("Transfer-Encoding") == "chunked")
|
||||
{
|
||||
// Chunked decoding WIP. How to test this ? dont know how to send chunks with telnet.
|
||||
_parse_chunked_body(pos + CRLF_SIZE*2);
|
||||
}
|
||||
else if (raw_request.size() - pos >= std::strtoul(get_rq_headers("Content-Length").c_str(), NULL, 10))
|
||||
{
|
||||
std::cerr << "Content-Length = " << std::strtoul(get_rq_headers("Content-Length").c_str(), NULL, 10) << "\n";
|
||||
if (get_rq_headers("Content-Type").find("multipart/form-data") != NPOS)
|
||||
_parse_multipart_body(pos);
|
||||
else
|
||||
_request.body = raw_request.substr(pos + CRLF_SIZE*2);
|
||||
body_complete = true;
|
||||
}
|
||||
|
||||
std::cerr << "Content-Length = " << std::strtoul(get_rq_headers("Content-Length").c_str(), NULL, 10) << "\n";
|
||||
std::cerr << "raw_request.size() - pos = " << raw_request.size() - pos << "\n";
|
||||
_request.body = raw_request.substr(pos);
|
||||
std::cerr << "_request.body.size() = " << _request.body.size() << "\n";
|
||||
|
||||
///////////////
|
||||
// Body checks
|
||||
if (_request.body.size() > assigned_server->client_body_limit)
|
||||
status = 413; // HTTP Client Errors
|
||||
}
|
||||
|
||||
void Client::_parse_chunked_body(size_t pos)
|
||||
{
|
||||
size_t chunk_size = 1;
|
||||
size_t chunk_field_end = 0;
|
||||
char *endptr = NULL;
|
||||
char *endptr_copy = NULL;
|
||||
/* TODO: verify if last chunk in raw_request (to avoid multiples complete parsing)
|
||||
but how ? with "raw_request.rfind("0" CRLF CRLF)", there no confirmation
|
||||
that we have found the last last-chunk OR just some data */
|
||||
|
||||
_request.body = raw_request.substr(pos);
|
||||
|
||||
std::cerr << "______Chunked\n" << _request.body << "\n______\n";
|
||||
pos = 0;
|
||||
while (chunk_size != 0)
|
||||
{
|
||||
/* if (pos > _request.body.size())
|
||||
{
|
||||
std::cerr << "parse_request_body(), pos > size()\n";
|
||||
// status = 400;
|
||||
return;
|
||||
} */
|
||||
/*
|
||||
if (pos == _request.body.size())
|
||||
{
|
||||
std::cerr << "parse_request_body(), will reread till last chunk\n";
|
||||
return;
|
||||
} */
|
||||
|
||||
/* endptr_copy = endptr; */
|
||||
(void)endptr_copy;
|
||||
chunk_size = std::strtoul(&_request.body[pos], &endptr, 16);
|
||||
if (errno == ERANGE)
|
||||
{
|
||||
status = 413;
|
||||
return ;
|
||||
}
|
||||
/* if (endptr == endptr_copy)
|
||||
{
|
||||
std::cerr << "parse_request_body(), no conversion possible\n";
|
||||
return;
|
||||
} */
|
||||
|
||||
|
||||
chunk_field_end = _request.body.find(CRLF, pos);
|
||||
if (chunk_field_end == NPOS)
|
||||
{
|
||||
std::cerr << "parse_request_body(), chunk_field no CRLF\n";
|
||||
// status = 400;
|
||||
return;
|
||||
}
|
||||
|
||||
chunk_field_end += CRLF_SIZE;
|
||||
_request.body.erase(pos, chunk_field_end);
|
||||
pos += chunk_size + CRLF_SIZE;
|
||||
}
|
||||
|
||||
_request.headers.erase("Transfer-Encoding");
|
||||
body_complete = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void Client::fill_script_path(std::string &path, size_t pos)
|
||||
{
|
||||
size_t pos;
|
||||
int len = script.size();
|
||||
std::string path = this->get_rq_abs_path();
|
||||
std::string tmp;
|
||||
|
||||
pos = path.find(script);
|
||||
if (pos == 0)
|
||||
{
|
||||
tmp = path.substr(0, pos + len);
|
||||
_request.script.path = "./srcs" + tmp; // TODO: root path ?
|
||||
_request.script.info = path.substr(pos + len);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
_request.script.path = path.substr(0, pos);
|
||||
_request.script.info = path.substr(pos);
|
||||
}
|
||||
|
||||
void Client::clear()
|
||||
{
|
||||
clear_request();
|
||||
clear_request_vars();
|
||||
raw_request.clear();
|
||||
response.clear();
|
||||
body_size = 0;
|
||||
status = 0;
|
||||
header_complete = false;
|
||||
body_complete = false;
|
||||
request_complete = false;
|
||||
assigned_server = NULL;
|
||||
assigned_location = NULL;
|
||||
clear_cgi_vars();
|
||||
}
|
||||
|
||||
void Client::clear_request()
|
||||
void Client::clear_request_vars()
|
||||
{
|
||||
clear_script();
|
||||
_request.method = UNKNOWN;
|
||||
_request.uri.clear();
|
||||
_request.target.clear();
|
||||
_request.version.clear();
|
||||
_request.headers.clear();
|
||||
_request.body.clear();
|
||||
_request.multi_bodys.clear();
|
||||
_request.abs_path.clear();
|
||||
_request.query.clear();
|
||||
_request.port.clear();
|
||||
_request.hostname.clear();
|
||||
}
|
||||
|
||||
void Client::clear_script()
|
||||
@@ -130,6 +267,41 @@ void Client::clear_script()
|
||||
_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
|
||||
void Client::print_client(std::string message)
|
||||
{
|
||||
std::map<std::string, std::string>::iterator it;
|
||||
std::cerr << "\n=== DEBUG PRINT CLIENT ===\n";
|
||||
std::cerr << message << ":\n----------\n\n" << "raw_request:\n__\n";
|
||||
::print_special(raw_request);
|
||||
std::cerr << "\n__\n"
|
||||
<< "get_cl_fd() : [" << get_cl_fd() << "]\n"
|
||||
<< "get_cl_port() : [" << get_cl_port() << "]\n"
|
||||
<< "get_cl_ip() : [" << get_cl_ip() << "]\n"
|
||||
<< "get_rq_method_str() : [" << get_rq_method_str() << "]\n"
|
||||
<< "get_rq_target() : [" << get_rq_target() << "]\n"
|
||||
<< "get_rq_abs_path() : [" << get_rq_abs_path() << "]\n"
|
||||
<< "get_rq_query() : [" << get_rq_query() << "]\n"
|
||||
<< "get_rq_version() : [" << get_rq_version() << "]\n"
|
||||
<< "get_rq_body() : [" << get_rq_body() << "]\n"
|
||||
<< "get_rq_script_path() : [" << get_rq_script_path() << "]\n"
|
||||
<< "get_rq_script_info() : [" << get_rq_script_info() << "]\n"
|
||||
<< "headers :\n";
|
||||
for (it = _request.headers.begin(); it != _request.headers.end(); it++)
|
||||
std::cerr << " " << it->first << ": [" << it->second << "]\n";
|
||||
std::cerr << "\n=== END PRINT CLIENT ===\n\n";
|
||||
}
|
||||
|
||||
/*********************************************
|
||||
* GETTERS
|
||||
@@ -145,15 +317,14 @@ const listen_socket * Client::get_cl_lsocket() const { return _lsocket; }
|
||||
http_method Client::get_rq_method() const { return _request.method; }
|
||||
std::string Client::get_rq_method_str() const
|
||||
{ return ::http_methods_to_str(_request.method); }
|
||||
std::string Client::get_rq_uri() const { return _request.uri; }
|
||||
std::string Client::get_rq_target() const { return _request.target; }
|
||||
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_version() const { return _request.version; }
|
||||
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_info()const { return _request.script.info; }
|
||||
|
||||
std::string Client::get_rq_headers(const std::string & key) const
|
||||
{
|
||||
std::map<std::string, std::string>::const_iterator it;
|
||||
@@ -172,66 +343,203 @@ std::string Client::get_rq_headers(const std::string & key) const
|
||||
void Client::_parse_request_line()
|
||||
{
|
||||
std::vector<std::string> line;
|
||||
int ret;
|
||||
std::string raw_line;
|
||||
|
||||
ret = ::parse_http_first_line(raw_request, line);
|
||||
if (ret != 3)
|
||||
raw_line = ::get_line(raw_request, 0, CRLF);
|
||||
line = ::split_trim(raw_line, " ");
|
||||
if (line.size() != 3)
|
||||
{
|
||||
std::cerr << "err _parse_first_line(): wrong number of elements (" << ret << " instead of 3)\n";
|
||||
std::cerr << "err _parse_first_line(): wrong number of elements (" << line.size() << " instead of 3)\n";
|
||||
status = 400; // "bad request"
|
||||
// if the header is fucked up, then this will be triggered, but for some reason in test_body.sh case another response 200 OK is sent first?
|
||||
}
|
||||
else
|
||||
{
|
||||
_request.method = str_to_http_method(line[0]);
|
||||
_request.uri = line[1];
|
||||
_parse_request_uri(line[1]);
|
||||
_request.target = line[1];
|
||||
_parse_request_target(line[1]);
|
||||
_request.version = line[2];
|
||||
}
|
||||
}
|
||||
|
||||
void Client::_parse_request_uri( std::string uri )
|
||||
void Client::_parse_request_target( std::string target )
|
||||
{
|
||||
size_t pos;
|
||||
|
||||
pos = uri.find("?");
|
||||
if (pos != std::string::npos)
|
||||
_request.query = uri.substr(pos + 1);
|
||||
pos = target.find("?");
|
||||
if (pos != NPOS)
|
||||
_request.query = target.substr(pos + 1);
|
||||
else
|
||||
_request.query = "";
|
||||
_request.abs_path = uri.substr(0, pos);
|
||||
_request.abs_path = target.substr(0, pos);
|
||||
if (_request.abs_path[_request.abs_path.size() - 1] == '/')
|
||||
_request.abs_path.erase(_request.abs_path.size() - 1);
|
||||
}
|
||||
|
||||
void Client::_parse_request_headers()
|
||||
void Client::_parse_request_fields()
|
||||
{
|
||||
// TODO: check error and adjust status
|
||||
_request.headers = ::parse_http_headers(raw_request);
|
||||
std::string headers;
|
||||
size_t pos;
|
||||
int ret;
|
||||
|
||||
headers = raw_request;
|
||||
// delete first line
|
||||
pos = headers.find(CRLF);
|
||||
if (pos != NPOS)
|
||||
headers.erase(0, pos + CRLF_SIZE);
|
||||
// delete body part
|
||||
pos = headers.find(CRLF CRLF);
|
||||
if (pos != NPOS)
|
||||
headers.erase(pos);
|
||||
else {
|
||||
std::cerr << "err _parse_request_fields(): request header doesn't end with empty line\n";
|
||||
status = 400; // "bad request"
|
||||
}
|
||||
// copy result of parser into headers
|
||||
ret = ::parse_http_headers(headers, _request.headers);
|
||||
if (ret > 0) {
|
||||
std::cerr << "err _parse_request_fields(): " << ret << " fields are bad formated\n";
|
||||
status = 400; // "bad request"
|
||||
}
|
||||
::str_map_key_tolower(_request.headers);
|
||||
}
|
||||
|
||||
void Client::_parse_request_body()
|
||||
void Client::_check_request_errors()
|
||||
{
|
||||
// TODO: check error and adjust status
|
||||
_request.body = ::parse_http_body(raw_request);
|
||||
// /* 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 << "client_body_limit=" << assigned_server->client_body_limit << "\n";
|
||||
///////////////////////
|
||||
// Request line checks
|
||||
if (_request.method == UNKNOWN)
|
||||
status = 501; // HTTP Client Errors
|
||||
else if (_request.version.compare(0, sizeof("HTTP/1") - 1, "HTTP/1") != 0)
|
||||
status = 505; // HTTP Client Errors
|
||||
else if (!(assigned_location->allow_methods & _request.method))
|
||||
{
|
||||
status = 405; // HTTP Client Errors
|
||||
response.append("Allow: ");
|
||||
response.append(::http_methods_to_str(assigned_location->allow_methods));
|
||||
response.append(CRLF);
|
||||
}
|
||||
else if (assigned_location->redirect_status)
|
||||
{ // Weird behavior. Sometimes, the web browser seems to wait for a complete response until timeout.
|
||||
// (for codes 301, 302, 303, 307, and 308)
|
||||
status = assigned_location->redirect_status;
|
||||
response.append("Location: ");
|
||||
response.append(assigned_location->redirect_uri);
|
||||
response.append(CRLF CRLF);
|
||||
}
|
||||
|
||||
//////////////////
|
||||
// Headers checks
|
||||
else if (!get_rq_headers("Content-Length").empty()
|
||||
&& std::strtoul(get_rq_headers("Content-Length").c_str(), NULL, 10) > assigned_server->client_body_limit)
|
||||
status = 413;
|
||||
else if (!get_rq_headers("Transfer-Encoding").empty()
|
||||
&& get_rq_headers("Transfer-Encoding") != "chunked" )
|
||||
status = 501;
|
||||
else if (!get_rq_headers("Content-Encoding").empty())
|
||||
{
|
||||
status = 415;
|
||||
response.append("Accept-Encoding:"); // empty, no encoding accepted
|
||||
response.append(CRLF);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void Client::_parse_port_hostname(std::string host)
|
||||
ServerConfig *Client::_determine_process_server(Client *client, std::vector<ServerConfig> &servers)
|
||||
{
|
||||
size_t pos;
|
||||
/*
|
||||
Behavior like this :
|
||||
http://nginx.org/en/docs/http/request_processing.html
|
||||
*/
|
||||
|
||||
if (host == "")
|
||||
std::cerr << "no host\n";
|
||||
std::string server_name = client->get_rq_headers("Host");
|
||||
// /* Debug */ std::cerr << "server_name = " << server_name << "\n";
|
||||
size_t pos = server_name.rfind(':');
|
||||
if (pos != NPOS)
|
||||
server_name.erase(pos);
|
||||
// /* Debug */ std::cerr << "server_name = " << server_name << "\n";
|
||||
|
||||
pos = host.find(':');
|
||||
// port :
|
||||
if (pos == std::string::npos)
|
||||
_request.port = "4040"; // TODO: make equal to default port in config
|
||||
std::vector<ServerConfig>::iterator it = servers.begin();
|
||||
std::vector<ServerConfig>::iterator default_server = servers.end();
|
||||
|
||||
while (it != servers.end())
|
||||
{
|
||||
if (it->host == client->get_cl_lsocket()->host
|
||||
&& it->port == client->get_cl_lsocket()->port)
|
||||
{
|
||||
if ( std::find(it->server_name.begin(), it->server_name.end(), server_name) != it->server_name.end() )
|
||||
break;
|
||||
else if (default_server == servers.end())
|
||||
default_server = it;
|
||||
}
|
||||
++it;
|
||||
}
|
||||
if (it != servers.end())
|
||||
return (&(*it));
|
||||
else
|
||||
_request.port = host.substr(pos);
|
||||
if (_request.port == ":")
|
||||
_request.port = "";
|
||||
// hostname :
|
||||
_request.hostname = host.substr(0, pos);
|
||||
return (&(*default_server));
|
||||
}
|
||||
|
||||
// const?
|
||||
const LocationConfig *Client::_determine_location(const ServerConfig &server, const std::string &path)
|
||||
{
|
||||
/* RULES ***
|
||||
|
||||
If a path coresponds exactly to a location, use that one
|
||||
if no path coresponds then use the most correct one
|
||||
most correct means the most precise branch that is still above
|
||||
the point we are aiming for
|
||||
|
||||
New Rule for location paths, they never end in /
|
||||
Sooo
|
||||
If we get a url that ends in / ignore the last /
|
||||
|
||||
*/
|
||||
|
||||
// TODO: technically i think this is useless...
|
||||
std::string uri = path;
|
||||
if (uri[uri.size() - 1] == '/' && uri.size() != 1)
|
||||
uri.erase(uri.size() - 1);
|
||||
|
||||
|
||||
for (std::vector<LocationConfig>::const_iterator it = server.locations.begin(); it != server.locations.end(); it++)
|
||||
{
|
||||
if (it->path.size() > uri.size())
|
||||
continue ;
|
||||
|
||||
if (uri.compare(0, it->path.size(), it->path) == 0)
|
||||
{
|
||||
if (it->path.size() == uri.size())
|
||||
return (&(*it));
|
||||
else if (uri[it->path.size()] == '/')
|
||||
return (&(*it));
|
||||
// this works cuz only ever looking for a / burried in a longer path
|
||||
}
|
||||
}
|
||||
return (&(server.locations.back()));
|
||||
|
||||
|
||||
// /test/mdr
|
||||
// /test/mdr/
|
||||
// /test/mdrBST
|
||||
|
||||
/////// More stuff to check this still works with
|
||||
|
||||
// /test/test_
|
||||
// /test/test_/
|
||||
// /test/test_deeper
|
||||
// /test/test_deeper/
|
||||
// /test/test_deepei
|
||||
// /test/test_deepei/
|
||||
// /test/test_deeperi
|
||||
// /test/test_deeper/super_deep/
|
||||
// /test/aaaaaaaaaaa/super_deep/
|
||||
|
||||
}
|
||||
|
||||
/*********************************************
|
||||
* OVERLOAD
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
# define CLIENT_HPP
|
||||
|
||||
# include <iostream>
|
||||
# include <iomanip> // setw
|
||||
# include <string>
|
||||
# include <map>
|
||||
# include <vector>
|
||||
@@ -10,7 +11,8 @@
|
||||
# include <netinet/in.h> // sockaddr_in, struct in_addr
|
||||
# include <arpa/inet.h> // htonl, htons, ntohl, ntohs, inet_addr, inet_ntoa
|
||||
# include "utils.hpp"
|
||||
# include "parsing_message_http.hpp"
|
||||
# include "ServerConfig.hpp"
|
||||
# include "colors.h"
|
||||
|
||||
struct Script
|
||||
{
|
||||
@@ -18,35 +20,60 @@ struct Script
|
||||
std::string info;
|
||||
};
|
||||
|
||||
struct MultipartBody
|
||||
{
|
||||
std::map<std::string, std::string> headers;
|
||||
std::string body;
|
||||
};
|
||||
|
||||
struct Request
|
||||
{
|
||||
http_method method;
|
||||
std::string uri;
|
||||
std::string target;
|
||||
std::string abs_path;
|
||||
std::string query;
|
||||
std::string version;
|
||||
std::map<std::string, std::string> headers;
|
||||
std::string body;
|
||||
std::string port;
|
||||
std::string hostname;
|
||||
std::vector<MultipartBody> multi_bodys;
|
||||
struct Script script;
|
||||
};
|
||||
|
||||
# define MAX_FILESIZE 1000000 // (1Mo)
|
||||
enum cgi_states
|
||||
{
|
||||
CGI_NO_CGI = 0,
|
||||
CGI_WAIT_TO_EXEC,
|
||||
CGI_READY_TO_EXEC,
|
||||
CGI_OUTPUT_READING,
|
||||
CGI_OUTPUT_COMPLETE
|
||||
};
|
||||
|
||||
class Client
|
||||
{
|
||||
public:
|
||||
Client();
|
||||
Client(int afd, listen_socket *lsocket, std::string aport, std::string aip);
|
||||
~Client();
|
||||
Client(Client const &src);
|
||||
Client &operator=(Client const &rhs);
|
||||
// Client(Client const &src);
|
||||
// Client &operator=(Client const &rhs);
|
||||
|
||||
std::string raw_request;
|
||||
std::string response;
|
||||
static char buf[MAX_FILESIZE+1];
|
||||
size_t body_size;
|
||||
unsigned int status;
|
||||
std::string raw_request;
|
||||
std::string response;
|
||||
unsigned int status;
|
||||
bool header_complete;
|
||||
bool body_complete;
|
||||
bool request_complete;
|
||||
ServerConfig *assigned_server; // cant be const cause of error_pages.operator[]
|
||||
const LocationConfig *assigned_location;
|
||||
|
||||
// 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;
|
||||
std::string cgi_output;
|
||||
|
||||
// getters
|
||||
int get_cl_fd() const;
|
||||
@@ -57,22 +84,27 @@ class Client
|
||||
// requests getters
|
||||
http_method get_rq_method() const;
|
||||
std::string get_rq_method_str() const;
|
||||
std::string get_rq_uri() const;
|
||||
std::string get_rq_target() const;
|
||||
std::string get_rq_abs_path() const;
|
||||
std::string get_rq_query() const;
|
||||
std::string get_rq_version() 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_info() const;
|
||||
std::string get_rq_headers(const std::string & key) const;
|
||||
|
||||
void parse_request();
|
||||
const std::vector<MultipartBody> &get_rq_multi_bodys() const;
|
||||
const std::string get_rq_multi_bodys_headers(const std::string & key, std::vector<MultipartBody>::const_iterator body_it) const;
|
||||
|
||||
void parse_request_headers(std::vector<ServerConfig> &servers);
|
||||
void parse_request_body();
|
||||
void clear();
|
||||
void clear_request();
|
||||
void clear_request_vars();
|
||||
void clear_cgi_vars();
|
||||
void clear_script();
|
||||
bool fill_script_path(std::string script);
|
||||
void fill_script_path(std::string &path, size_t pos);
|
||||
// DEBUG
|
||||
void print_client(std::string message = "");
|
||||
|
||||
private:
|
||||
int _fd;
|
||||
@@ -82,11 +114,16 @@ class Client
|
||||
struct Request _request;
|
||||
|
||||
void _parse_request_line();
|
||||
void _parse_request_headers();
|
||||
void _parse_request_body();
|
||||
void _parse_request_uri( std::string uri );
|
||||
void _parse_port_hostname(std::string host);
|
||||
void _parse_request_fields();
|
||||
void _parse_request_target( std::string target );
|
||||
void _parse_chunked_body(size_t pos);
|
||||
void _parse_multipart_body(size_t pos);
|
||||
void _check_request_errors();
|
||||
|
||||
ServerConfig*
|
||||
_determine_process_server(Client *client, std::vector<ServerConfig> &servers);
|
||||
const LocationConfig*
|
||||
_determine_location(const ServerConfig &server, const std::string &path);
|
||||
};
|
||||
|
||||
bool operator==(const Client& lhs, const Client& rhs);
|
||||
@@ -94,4 +131,3 @@ bool operator==(const Client& lhs, int fd);
|
||||
bool operator==(int fd, const Client& rhs);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
92
srcs/Client_multipart_body.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
|
||||
#include "Client.hpp"
|
||||
|
||||
const std::vector<MultipartBody> &Client::get_rq_multi_bodys() const { return _request.multi_bodys; }
|
||||
const std::string Client::get_rq_multi_bodys_headers(const std::string & key, std::vector<MultipartBody>::const_iterator body_it) const
|
||||
{
|
||||
std::map<std::string, std::string>::const_iterator it;
|
||||
|
||||
it = body_it->headers.find(::str_tolower(key));
|
||||
if (it == body_it->headers.end())
|
||||
return ""; // IF return reference compiler "warning: returning reference to local temporary"
|
||||
return it->second;
|
||||
}
|
||||
|
||||
void Client::_parse_multipart_body(size_t pos)
|
||||
{
|
||||
/*
|
||||
** Parsing roughly like described in :
|
||||
** https://www.rfc-editor.org/rfc/rfc2046#section-5.1.1
|
||||
*/
|
||||
MultipartBody new_body;
|
||||
std::string boundary;
|
||||
size_t start_pos;
|
||||
size_t end_pos;
|
||||
std::string tmp;
|
||||
size_t tmp_pos;
|
||||
size_t ret;
|
||||
|
||||
// Get boundary
|
||||
boundary = get_rq_headers("Content-Type");
|
||||
start_pos = boundary.find("boundary=");
|
||||
if (start_pos == NPOS)
|
||||
{
|
||||
status = 400; std::cerr << "_parse_multipart_body() error 1\n";
|
||||
return;
|
||||
}
|
||||
start_pos += sizeof("boundary=")-1;
|
||||
boundary = boundary.substr(start_pos);
|
||||
|
||||
// Search boundary
|
||||
start_pos = raw_request.find("--" + boundary, pos);
|
||||
if (start_pos == NPOS || start_pos + sizeof("--")-1 + boundary.size() > raw_request.size())
|
||||
{
|
||||
status = 400; std::cerr << "_parse_multipart_body() error 2\n";
|
||||
return;
|
||||
}
|
||||
start_pos += sizeof("--")-1 + boundary.size() + CRLF_SIZE;
|
||||
|
||||
while (1)
|
||||
{
|
||||
end_pos = raw_request.find("--" + boundary, start_pos);
|
||||
if (end_pos == NPOS)
|
||||
{
|
||||
status = 400; std::cerr << "_parse_multipart_body() error 3\n";
|
||||
return;
|
||||
}
|
||||
new_body.body = raw_request.substr(start_pos, end_pos - start_pos - CRLF_SIZE);
|
||||
|
||||
// Split headers from body
|
||||
tmp_pos = new_body.body.find(CRLF CRLF);
|
||||
if (tmp_pos != NPOS)
|
||||
{
|
||||
ret = ::parse_http_headers(new_body.body.substr(0, tmp_pos), new_body.headers);
|
||||
::str_map_key_tolower(new_body.headers);
|
||||
if (ret)
|
||||
{
|
||||
status = 400; std::cerr << "_parse_multipart_body() error 4\n";
|
||||
return;
|
||||
}
|
||||
tmp_pos += CRLF_SIZE*2;
|
||||
new_body.body.erase(0, tmp_pos);
|
||||
}
|
||||
else
|
||||
{ // No headers case
|
||||
tmp_pos = new_body.body.find(CRLF);
|
||||
if (tmp_pos != 0)
|
||||
{
|
||||
status = 400; std::cerr << "_parse_multipart_body() error 5\n";
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_request.multi_bodys.push_back(new_body);
|
||||
|
||||
// Move start for next loop
|
||||
start_pos = end_pos + sizeof("--")-1 + boundary.size();
|
||||
if ( start_pos + 2 + CRLF_SIZE == raw_request.size()
|
||||
&& raw_request[start_pos] == '-'
|
||||
&& raw_request[start_pos+1] == '-')
|
||||
break;
|
||||
}
|
||||
}
|
||||
94
srcs/cgi-bin/Makefile
Normal file
@@ -0,0 +1,94 @@
|
||||
|
||||
# - - - - - - #
|
||||
# #
|
||||
# COLORS #
|
||||
# #
|
||||
# - - - - - - #
|
||||
|
||||
GRAY = "\e[0;30m"
|
||||
RED = "\e[0;31m"
|
||||
GREEN = "\e[0;32m"
|
||||
YELLOW = "\e[0;33m"
|
||||
BLUE = "\e[0;34m"
|
||||
PURPLE = "\e[0;35m"
|
||||
CYAN = "\e[0;36m"
|
||||
WHITE = "\e[0;37m"
|
||||
|
||||
B_GRAY = "\e[1;30m"
|
||||
B_RED = "\e[1;31m"
|
||||
B_GREEN = "\e[1;32m"
|
||||
B_YELLOW = "\e[1;33m"
|
||||
B_BLUE = "\e[1;34m"
|
||||
B_PURPLE = "\e[1;35m"
|
||||
B_CYAN = "\e[1;36m"
|
||||
B_WHITE = "\e[1;37m"
|
||||
|
||||
RESET = "\e[0m"
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
|
||||
# . name = value \ . += append to a variable #
|
||||
# VARIABLES . value . != set result of command #
|
||||
# . name is case sensitive . ?= set if not already set #
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
|
||||
|
||||
NAME = $(SRCS_X:.cpp=.out)
|
||||
|
||||
CXX = c++
|
||||
CXXFLAGS = -Wall -Wextra #-Werror
|
||||
CXXFLAGS += $(HEADERS_D:%=-I%)
|
||||
CXXFLAGS += -std=c++98
|
||||
CXXFLAGS += -g
|
||||
|
||||
VPATH = $(SRCS_D)
|
||||
HEADERS_D = .
|
||||
SRCS_D = .
|
||||
|
||||
SRCS = cgi_utils.cpp
|
||||
SRCS_X = \
|
||||
cgi_cpp.cpp \
|
||||
cgi_cpp_bad_headers.cpp \
|
||||
cgi_cpp_empty.cpp \
|
||||
cgi_cpp_empty_lines.cpp \
|
||||
cgi_cpp_len.cpp \
|
||||
cgi_cpp_len_big.cpp \
|
||||
cgi_cpp_len_small.cpp \
|
||||
cgi_cpp_no_body.cpp \
|
||||
cgi_cpp_no_headers.cpp \
|
||||
cgi_cpp_only_crlf.cpp \
|
||||
cgi_cpp_sleep.cpp \
|
||||
cgi_cpp_status.cpp \
|
||||
cgi_cpp_download.cpp \
|
||||
|
||||
OBJS_D = builds
|
||||
OBJS = $(SRCS:%.cpp=$(OBJS_D)/%.o)
|
||||
OBJS_X = $(SRCS_X:%.cpp=$(OBJS_D)/%.o)
|
||||
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
|
||||
# . target: prerequisites . $@ : target #
|
||||
# RULES . recipe . $< : 1st prerequisite #
|
||||
# . recipe . $^ : all prerequisites #
|
||||
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #
|
||||
|
||||
all: $(NAME)
|
||||
|
||||
$(OBJS_D)/%.o: %.cpp | $(OBJS_D)
|
||||
@echo $(B_GREEN)"compilation :" $@ $(RESET)
|
||||
$(CXX) $(CXXFLAGS) -c $< -o $@
|
||||
|
||||
$(OBJS_D):
|
||||
mkdir $@
|
||||
|
||||
$(NAME): $(OBJS) $(OBJS_X)
|
||||
$(NAME):
|
||||
@echo $(B_YELLOW)"linkage :" $@ $(RESET)
|
||||
$(CXX) $(OBJS) $(@:%.out=$(OBJS_D)/%.o) -o $@
|
||||
|
||||
clean:
|
||||
rm -rf $(OBJS_D)
|
||||
|
||||
fclean: clean
|
||||
rm -f $(NAME)
|
||||
|
||||
re: fclean all
|
||||
|
||||
.PHONY : all clean fclean re
|
||||
4
srcs/cgi-bin/cgi
Executable file
@@ -0,0 +1,4 @@
|
||||
#! /bin/bash
|
||||
echo "status: 100\r\n"
|
||||
echo "\r\n\r\n"
|
||||
echo "hiii"
|
||||
@@ -1,41 +0,0 @@
|
||||
# include <iostream>
|
||||
# include <string>
|
||||
# include <sstream>
|
||||
|
||||
int main (int ac, char **av) {
|
||||
std::string to_send;
|
||||
std::string header;
|
||||
std::string end_header = "\r\n\r\n";
|
||||
std::string response;
|
||||
std::stringstream strs;
|
||||
|
||||
header = "HTTP/1.1 200 OK\n";
|
||||
header += "Content-Type: text/html; charset=UTF-8\n";
|
||||
header += "Content-Length: ";
|
||||
|
||||
response = "<!DOCTYPE html>\n";
|
||||
response += "<html>\n";
|
||||
response += "<head>\n";
|
||||
response += "<title>CGI</title>\n";
|
||||
response += "</head>\n";
|
||||
response += "<body>\n";
|
||||
response += "<h2>CGI request :</h2>\n";
|
||||
for (int i = 1; i < ac; i++)
|
||||
{
|
||||
response += "<p>";
|
||||
response += av[i];
|
||||
response += "</p>\n";
|
||||
}
|
||||
response += "</body>\n";
|
||||
response += "</html>\n";
|
||||
|
||||
strs << response.size();
|
||||
header += strs.str();
|
||||
header += end_header;
|
||||
to_send = header;
|
||||
to_send += response;
|
||||
|
||||
std::cout << to_send;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
#! /usr/bin/php
|
||||
|
||||
<?php
|
||||
echo "Status: 200\r\n";
|
||||
echo "false: 300\r\n";
|
||||
echo "server: Webserv/0.2\r\n";
|
||||
echo "Status: 300\r\n";
|
||||
echo "\r\n";
|
||||
echo "BEGIN PHP-CGI\n-----------\n\n";
|
||||
echo "AUTH_TYPE: " . getenv("AUTH_TYPE");
|
||||
@@ -26,4 +27,3 @@
|
||||
// echo $_POST['REQUEST_METHOD'];
|
||||
echo "\n\n-----------\nEND PHP-CGI\n\n";
|
||||
?>
|
||||
|
||||
4
srcs/cgi-bin/cgi.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
#! /bin/bash
|
||||
echo "status: 100\r\n"
|
||||
echo "\r\n\r\n"
|
||||
echo "hiii"
|
||||
25
srcs/cgi-bin/cgi_cpp.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
# include "cgi_utils.hpp"
|
||||
# include <unistd.h>
|
||||
# include <cstdio>
|
||||
|
||||
int main (int ac, char **av, char ** env)
|
||||
{
|
||||
std::string http_header;
|
||||
std::string http_body;
|
||||
std::string rq_body;
|
||||
|
||||
std::cin >> rq_body;
|
||||
|
||||
(void)ac;
|
||||
(void)av;
|
||||
|
||||
http_header = "Content-Type: text/html; charset=UTF-8" CRLF;
|
||||
|
||||
fill_body_basic(env, http_body, rq_body);
|
||||
|
||||
std::cout << http_header << CRLF << http_body;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
24
srcs/cgi-bin/cgi_cpp_bad_headers.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
# include "cgi_utils.hpp"
|
||||
|
||||
int main (int ac, char **av, char ** env)
|
||||
{
|
||||
std::string http_header;
|
||||
std::string http_body;
|
||||
std::string http_status;
|
||||
std::string rq_body;
|
||||
|
||||
std::cin >> rq_body;
|
||||
|
||||
(void)ac;
|
||||
(void)av;
|
||||
|
||||
http_header = "Bad-Headers: wrong";
|
||||
|
||||
fill_body_basic(env, http_body, rq_body);
|
||||
|
||||
std::cout << http_header << CRLF << http_body;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
55
srcs/cgi-bin/cgi_cpp_download.cpp
Normal file
@@ -0,0 +1,55 @@
|
||||
|
||||
# include "cgi_utils.hpp"
|
||||
|
||||
int main (int ac, char **av, char ** env)
|
||||
{
|
||||
std::string http_header;
|
||||
std::string http_body;
|
||||
std::string rq_body;
|
||||
std::string form_infos;
|
||||
std::string path;
|
||||
std::ifstream ifd;
|
||||
std::stringstream buf;
|
||||
size_t status;
|
||||
|
||||
std::cin >> rq_body;
|
||||
|
||||
(void)ac;
|
||||
(void)av;
|
||||
(void)env;
|
||||
|
||||
http_header = "Content-Type: image/jpeg" CRLF;
|
||||
|
||||
form_infos = get_form_infos(rq_body);
|
||||
path = get_value("file", rq_body);
|
||||
path = "./www/" + path;
|
||||
|
||||
status = ::eval_file_access(path, R_OK);
|
||||
if (status)
|
||||
{
|
||||
std::cout << "Status: " << status << CRLF CRLF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
ifd.open(path.c_str());
|
||||
if (!ifd)
|
||||
{
|
||||
std::cout << "Status: " << 500 << CRLF CRLF;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
buf << ifd.rdbuf();
|
||||
if (!ifd || !buf)
|
||||
{
|
||||
std::cout << "Status: " << 500 << CRLF CRLF;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << http_header << CRLF << buf.str();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
12
srcs/cgi-bin/cgi_cpp_empty.cpp
Normal file
@@ -0,0 +1,12 @@
|
||||
|
||||
# include "cgi_utils.hpp"
|
||||
|
||||
int main (int ac, char **av, char ** env)
|
||||
{
|
||||
(void)ac;
|
||||
(void)av;
|
||||
(void)env;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
23
srcs/cgi-bin/cgi_cpp_empty_lines.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
# include "cgi_utils.hpp"
|
||||
|
||||
int main (int ac, char **av, char ** env)
|
||||
{
|
||||
std::string http_header;
|
||||
std::string http_body;
|
||||
std::string rq_body;
|
||||
|
||||
std::cin >> rq_body;
|
||||
|
||||
(void)ac;
|
||||
(void)av;
|
||||
|
||||
http_header = "Content-Type: text/html; charset=UTF-8" CRLF;
|
||||
|
||||
fill_body_basic(env, http_body, rq_body);
|
||||
|
||||
std::cout << http_header << CRLF CRLF CRLF CRLF CRLF << http_body;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
25
srcs/cgi-bin/cgi_cpp_len.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
# include "cgi_utils.hpp"
|
||||
|
||||
int main (int ac, char **av, char ** env)
|
||||
{
|
||||
std::string http_header;
|
||||
std::string http_body;
|
||||
std::string rq_body;
|
||||
|
||||
std::cin >> rq_body;
|
||||
|
||||
(void)ac;
|
||||
(void)av;
|
||||
|
||||
http_header = "Content-Type: text/html; charset=UTF-8" CRLF;
|
||||
http_header += "Content-Length: " + itos(http_body.size()) + CRLF;
|
||||
|
||||
fill_body_basic(env, http_body, rq_body);
|
||||
|
||||
|
||||
std::cout << http_header << CRLF << http_body;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
25
srcs/cgi-bin/cgi_cpp_len_big.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
# include "cgi_utils.hpp"
|
||||
|
||||
int main (int ac, char **av, char ** env)
|
||||
{
|
||||
std::string http_header;
|
||||
std::string http_body;
|
||||
std::string rq_body;
|
||||
|
||||
std::cin >> rq_body;
|
||||
|
||||
(void)ac;
|
||||
(void)av;
|
||||
|
||||
http_header = "Content-Type: text/html; charset=UTF-8" CRLF;
|
||||
http_header += "Content-Length: " + itos(http_body.size() + 100) + CRLF;
|
||||
|
||||
fill_body_basic(env, http_body, rq_body);
|
||||
|
||||
|
||||
std::cout << http_header << CRLF << http_body;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
24
srcs/cgi-bin/cgi_cpp_len_small.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
# include "cgi_utils.hpp"
|
||||
|
||||
int main (int ac, char **av, char ** env)
|
||||
{
|
||||
std::string http_header;
|
||||
std::string http_body;
|
||||
std::string rq_body;
|
||||
|
||||
std::cin >> rq_body;
|
||||
|
||||
(void)ac;
|
||||
(void)av;
|
||||
|
||||
http_header = "Content-Type: text/html; charset=UTF-8" CRLF;
|
||||
http_header += "Content-Length: " + itos(http_body.size() - 100) + CRLF;
|
||||
|
||||
fill_body_basic(env, http_body, rq_body);
|
||||
|
||||
std::cout << http_header << CRLF << http_body;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
22
srcs/cgi-bin/cgi_cpp_no_body.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
|
||||
# include "cgi_utils.hpp"
|
||||
|
||||
int main (int ac, char **av, char ** env)
|
||||
{
|
||||
std::string http_header;
|
||||
std::string http_status;
|
||||
std::string rq_body;
|
||||
|
||||
std::cin >> rq_body;
|
||||
|
||||
(void)ac;
|
||||
(void)av;
|
||||
(void)env;
|
||||
|
||||
http_header = "Content-Type: text/html; charset=UTF-8" CRLF;
|
||||
|
||||
std::cout << http_header << CRLF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
24
srcs/cgi-bin/cgi_cpp_no_headers.cpp
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
# include "cgi_utils.hpp"
|
||||
|
||||
int main (int ac, char **av, char ** env)
|
||||
{
|
||||
std::string http_header;
|
||||
std::string http_body;
|
||||
std::string http_status;
|
||||
std::string rq_body;
|
||||
|
||||
std::cin >> rq_body;
|
||||
|
||||
(void)ac;
|
||||
(void)av;
|
||||
|
||||
http_header = CRLF;
|
||||
|
||||
fill_body_basic(env, http_body, rq_body);
|
||||
|
||||
std::cout << CRLF << http_body;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
15
srcs/cgi-bin/cgi_cpp_only_crlf.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
# include "cgi_utils.hpp"
|
||||
|
||||
int main (int ac, char **av, char ** env)
|
||||
{
|
||||
(void)ac;
|
||||
(void)av;
|
||||
(void)env;
|
||||
|
||||
std::cout << CRLF CRLF;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
29
srcs/cgi-bin/cgi_cpp_sleep.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
|
||||
# include "cgi_utils.hpp"
|
||||
|
||||
int main (int ac, char **av, char ** env)
|
||||
{
|
||||
std::string http_header;
|
||||
std::string http_body;
|
||||
std::string rq_body;
|
||||
size_t time;
|
||||
std::stringstream ss;
|
||||
|
||||
std::cin >> rq_body;
|
||||
|
||||
(void)ac;
|
||||
(void)av;
|
||||
|
||||
http_header = "Content-Type: text/html; charset=UTF-8" CRLF;
|
||||
|
||||
fill_body_basic(env, http_body, rq_body);
|
||||
|
||||
ss << get_value("sleep", rq_body);
|
||||
ss >> time;
|
||||
sleep(time);
|
||||
|
||||
std::cout << http_header << CRLF << http_body;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
27
srcs/cgi-bin/cgi_cpp_status.cpp
Normal file
@@ -0,0 +1,27 @@
|
||||
|
||||
# include "cgi_utils.hpp"
|
||||
|
||||
int main (int ac, char **av, char ** env)
|
||||
{
|
||||
std::string http_header;
|
||||
std::string http_body;
|
||||
std::string http_status;
|
||||
std::string rq_body;
|
||||
|
||||
std::cin >> rq_body;
|
||||
|
||||
(void)ac;
|
||||
(void)av;
|
||||
|
||||
http_header = "Content-Type: text/html; charset=UTF-8" CRLF;
|
||||
|
||||
fill_body_basic(env, http_body, rq_body);
|
||||
|
||||
http_status = get_value("Status", rq_body);
|
||||
http_header += "Status: " + http_status + CRLF;
|
||||
|
||||
std::cout << http_header << CRLF CRLF << http_body;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
29
srcs/cgi-bin/cgi_second/cgi.php
Executable file
@@ -0,0 +1,29 @@
|
||||
#! /usr/bin/php
|
||||
<?php
|
||||
echo "false: 300\r\n";
|
||||
echo "server: Webserv/0.2\r\n";
|
||||
echo "Status: 300\r\n";
|
||||
echo "\r\n";
|
||||
echo "BEGIN PHP-CGI\n-----------\n\n";
|
||||
echo "AUTH_TYPE: " . getenv("AUTH_TYPE");
|
||||
echo "\nCONTENT_LENGTH: " . getenv("CONTENT_LENGTH");
|
||||
echo "\nCONTENT_TYPE: " . getenv("CONTENT_TYPE");
|
||||
echo "\nGATEWAY_INTERFACE: " . getenv("GATEWAY_INTERFACE");
|
||||
echo "\nPATH_INFO: " . getenv("PATH_INFO");
|
||||
echo "\nPATH_TRANSLATED: " . getenv("PATH_TRANSLATED");
|
||||
echo "\nQUERY_STRING: " . getenv("QUERY_STRING");
|
||||
echo "\nREMOTE_ADDR: " . getenv("REMOTE_ADDR");
|
||||
echo "\nREMOTE_HOST: " . getenv("REMOTE_HOST");
|
||||
echo "\nREMOTE_IDENT: " . getenv("REMOTE_IDENT");
|
||||
echo "\nREMOTE_USER: " . getenv("REMOTE_USER");
|
||||
echo "\nREQUEST_METHOD: " . getenv("REQUEST_METHOD");
|
||||
echo "\nSCRIPT_NAME: " . getenv("SCRIPT_NAME");
|
||||
echo "\nSERVER_NAME: " . getenv("SERVER_NAME");
|
||||
echo "\nSERVER_PORT: " . getenv("SERVER_PORT");
|
||||
echo "\nSERVER_PROTOCOL: " . getenv("SERVER_PROTOCOL");
|
||||
echo "\nSERVER_SOFTWARE: " . getenv("SERVER_SOFTWARE");
|
||||
echo "\nREDIRECT_STATUS: " . getenv("REDIRECT_STATUS");
|
||||
|
||||
// echo $_POST['REQUEST_METHOD'];
|
||||
echo "\n\n-----------\nEND PHP-CGI\n\n";
|
||||
?>
|
||||
3
srcs/cgi-bin/cgi_style.css
Normal file
@@ -0,0 +1,3 @@
|
||||
h1, h2, h3, p {
|
||||
display: inline;
|
||||
}
|
||||
199
srcs/cgi-bin/cgi_utils.cpp
Normal file
@@ -0,0 +1,199 @@
|
||||
#include "cgi_utils.hpp"
|
||||
|
||||
std::string str_tolower(std::string str)
|
||||
{
|
||||
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
|
||||
return str;
|
||||
}
|
||||
|
||||
std::string trim(std::string str, char del)
|
||||
{
|
||||
size_t pos;
|
||||
|
||||
// delete leadings del
|
||||
pos = str.find_first_not_of(del);
|
||||
if (pos == NPOS)
|
||||
pos = str.size();
|
||||
str = str.substr(pos);
|
||||
|
||||
// delete trailing del
|
||||
pos = str.find_last_not_of(del);
|
||||
if (pos != NPOS)
|
||||
str = str.substr(0, pos + 1);
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
std::vector<std::string>
|
||||
split(const std::string & input, std::string delim, char ctrim)
|
||||
{
|
||||
std::vector<std::string> split_str;
|
||||
std::string tmp;
|
||||
size_t start = 0;
|
||||
size_t end = 0;
|
||||
size_t len = 0;
|
||||
|
||||
while (end != NPOS)
|
||||
{
|
||||
end = input.find(delim, start);
|
||||
len = end - start;
|
||||
if (end == NPOS)
|
||||
len = end;
|
||||
tmp = input.substr(start, len);
|
||||
if (ctrim != '\0')
|
||||
tmp = trim(tmp, ctrim);
|
||||
if (tmp.size() != 0)
|
||||
split_str.push_back( tmp );
|
||||
start = end + delim.size();
|
||||
}
|
||||
return split_str;
|
||||
}
|
||||
|
||||
std::string itos(int n)
|
||||
{
|
||||
std::stringstream strs;
|
||||
|
||||
strs << n;
|
||||
return ( strs.str() );
|
||||
}
|
||||
|
||||
std::string parse_env(const std::string & env)
|
||||
{
|
||||
std::string ret = "";
|
||||
char * ret_env;
|
||||
|
||||
ret_env = getenv(env.c_str());
|
||||
if (ret_env != NULL)
|
||||
ret = ret_env;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string print_env(char **env, std::string tag)
|
||||
{
|
||||
std::string ret = "";
|
||||
|
||||
for (int i = 0; env[i] != NULL; ++i)
|
||||
{
|
||||
ret += "<" + tag + ">";
|
||||
ret += env[i];
|
||||
ret += "</" + tag + "><br>";
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string
|
||||
print_form(std::string form, std::string tag_key, std::string tag_val)
|
||||
{
|
||||
std::vector<std::string> split_str;
|
||||
std::vector<std::string> sub_split_str;
|
||||
std::vector<std::string>::const_iterator it;
|
||||
std::string ret = "";
|
||||
std::string key;
|
||||
|
||||
split_str = split(form, "&");
|
||||
for (it = split_str.begin(); it != split_str.end(); ++it)
|
||||
{
|
||||
sub_split_str = split(*it, "=");
|
||||
key = sub_split_str[0];
|
||||
if (key == "fname")
|
||||
key = "first name";
|
||||
else if (key == "lname")
|
||||
key = "last name";
|
||||
ret += "<br><" + tag_key + ">" + key + ": </" + tag_key + ">";
|
||||
ret += "<" + tag_val + ">" + sub_split_str[1] + "</" + tag_val + ">";
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string get_form_infos(const std::string & rq_body)
|
||||
{
|
||||
std::string form_infos;
|
||||
std::string method;
|
||||
|
||||
method = parse_env("REQUEST_METHOD");
|
||||
|
||||
if (method == "POST")
|
||||
form_infos = rq_body;
|
||||
else if (method == "GET")
|
||||
form_infos = parse_env("QUERY_STRING");
|
||||
|
||||
return form_infos;
|
||||
}
|
||||
|
||||
std::string get_value(const std::string & key, const std::string & rq_body)
|
||||
{
|
||||
std::string infos;
|
||||
std::string ret;
|
||||
size_t pos;
|
||||
size_t end;
|
||||
size_t len;
|
||||
|
||||
infos = get_form_infos(rq_body);
|
||||
pos = str_tolower(infos).find(str_tolower(key));
|
||||
if (pos == NPOS)
|
||||
return "";
|
||||
pos = infos.find_first_of("=", pos);
|
||||
if (pos == NPOS)
|
||||
return "";
|
||||
pos++;
|
||||
end = infos.find_first_of("&", pos);
|
||||
if (end == NPOS)
|
||||
end = infos.size();
|
||||
len = end - pos;
|
||||
ret = infos.substr(pos, len);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
fill_body_basic(char **env, std::string & http_body, const std::string & rq_body)
|
||||
{
|
||||
std::string rq_method = "not found";
|
||||
std::string rq_query;
|
||||
std::string form_infos;
|
||||
|
||||
rq_method = parse_env("REQUEST_METHOD");
|
||||
rq_query = parse_env("QUERY_STRING");
|
||||
|
||||
if (rq_method == "POST")
|
||||
form_infos = rq_body;
|
||||
else if (rq_method == "GET")
|
||||
form_infos = rq_query;
|
||||
|
||||
http_body = HTML_BODY_TOP;
|
||||
|
||||
http_body += "<br><h3>method used: </h3>";
|
||||
http_body += "<p>" + rq_method + "</p>";
|
||||
|
||||
http_body += "<br><h3>form body: </h3>";
|
||||
http_body += "<p>" + rq_body + "</p>";
|
||||
|
||||
http_body += "<br><h3>form query: </h3>";
|
||||
http_body += "<p>" + rq_query + "</p>";
|
||||
|
||||
http_body += "<br><br><h3>output:</h3><br>";
|
||||
http_body += print_form(form_infos, "p", "p");
|
||||
|
||||
http_body += "<br><br><h3>cgi_env_variables:</h3><br>";
|
||||
http_body += print_env(env, "p");
|
||||
|
||||
http_body += HTML_BODY_BOTTOM;
|
||||
}
|
||||
|
||||
size_t eval_file_access(const std::string &path, int mode)
|
||||
{
|
||||
if (::access(path.c_str(), F_OK) == -1)
|
||||
{
|
||||
std::perror("err access()");
|
||||
return 404; // NOT_FOUND, file doesn't exist
|
||||
}
|
||||
|
||||
if (::access(path.c_str(), mode) == -1)
|
||||
{
|
||||
std::perror("err access()");
|
||||
return 403; // FORBIDDEN, file doesn't have access permission
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
68
srcs/cgi-bin/cgi_utils.hpp
Normal file
@@ -0,0 +1,68 @@
|
||||
|
||||
#ifndef CGI_UTILS_HPP
|
||||
# define CGI_UTILS_HPP
|
||||
|
||||
# include <iostream>
|
||||
# include <string>
|
||||
# include <sstream>
|
||||
# include <fstream>
|
||||
# include <vector>
|
||||
# include <stdlib.h> // getenv
|
||||
# include <algorithm> // transform
|
||||
# include <unistd.h> // sleep, close, access
|
||||
|
||||
# define CR "\r"
|
||||
# define LF "\n"
|
||||
# define CRLF CR LF
|
||||
# define CRLF_SIZE 2
|
||||
# define NPOS std::string::npos
|
||||
|
||||
# define HTML_BODY_TOP "<!DOCTYPE html>"\
|
||||
"<html>"\
|
||||
" <head>"\
|
||||
" <meta charset=\"UTF-8\">"\
|
||||
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"\
|
||||
" <title>CGI</title>"\
|
||||
" <link href=\"./cgi_style.css\" type=\"text/css\" rel=\"stylesheet\">"\
|
||||
" </head>"\
|
||||
" <body>"\
|
||||
" <h1>CGI</h1><br>"
|
||||
# define HTML_BODY_BOTTOM " <br><h1>END CGI</h1>"\
|
||||
" </body>"\
|
||||
"</html>"
|
||||
|
||||
std::string
|
||||
str_tolower(std::string str);
|
||||
|
||||
std::string
|
||||
trim(std::string str, char del);
|
||||
|
||||
std::vector<std::string>
|
||||
split(const std::string & input, std::string delim, char ctrim = '\0');
|
||||
|
||||
std::string
|
||||
itos(int n);
|
||||
|
||||
std::string
|
||||
parse_env(const std::string & env);
|
||||
|
||||
std::string
|
||||
print_env(char **env, std::string tag = "p");
|
||||
|
||||
std::string
|
||||
get_form_infos(const std::string & rq_body);
|
||||
|
||||
std::string
|
||||
get_value(const std::string & key, const std::string & rq_body);
|
||||
|
||||
std::string
|
||||
print_form(std::string form, std::string key = "p", std::string val = "p");
|
||||
|
||||
void
|
||||
fill_body_basic(char **env, std::string & http_body, const std::string & rq_body);
|
||||
|
||||
size_t
|
||||
eval_file_access(const std::string &path, int mode);
|
||||
|
||||
#endif
|
||||
|
||||
10
srcs/cgi-bin/tmp.php
Executable file
@@ -0,0 +1,10 @@
|
||||
#! /usr/bin/php
|
||||
|
||||
<?php
|
||||
|
||||
if(isset($_FILE["fileToUpload"]))
|
||||
echo "there is a file";
|
||||
else
|
||||
echo "\n\nHeader: something\r\n\r\nno file\r\n";
|
||||
|
||||
?>
|
||||
56
srcs/cgi-bin/upload_file.php
Executable file
@@ -0,0 +1,56 @@
|
||||
#! /usr/bin/php
|
||||
|
||||
|
||||
<?php
|
||||
|
||||
|
||||
|
||||
$target_dir = "user_files/";
|
||||
$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
|
||||
$uploadOk = 1;
|
||||
$imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));
|
||||
|
||||
// Check if image file is a actual image or fake image
|
||||
if(isset($_POST["submit"])) {
|
||||
$check = getimagesize($_FILES["fileToUpload"]["tmp_name"]);
|
||||
if($check !== false) {
|
||||
echo "File is an image - " . $check["mime"] . ".";
|
||||
$uploadOk = 1;
|
||||
} else {
|
||||
echo "File is not an image.";
|
||||
$uploadOk = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Check if file already exists
|
||||
if (file_exists($target_file)) {
|
||||
echo "Sorry, file already exists.";
|
||||
$uploadOk = 0;
|
||||
}
|
||||
|
||||
// Check file size
|
||||
if ($_FILES["fileToUpload"]["size"] > 500000) {
|
||||
echo "Sorry, your file is too large.";
|
||||
$uploadOk = 0;
|
||||
}
|
||||
|
||||
// Allow certain file formats
|
||||
if($imageFileType != "jpg" && $imageFileType != "png" && $imageFileType != "jpeg"
|
||||
&& $imageFileType != "gif" ) {
|
||||
echo "Sorry, only JPG, JPEG, PNG & GIF files are allowed.";
|
||||
$uploadOk = 0;
|
||||
}
|
||||
|
||||
// Check if $uploadOk is set to 0 by an error
|
||||
if ($uploadOk == 0) {
|
||||
echo "Sorry, your file was not uploaded.";
|
||||
// if everything is ok, try to upload file
|
||||
} else {
|
||||
if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
|
||||
echo "The file ". htmlspecialchars( basename( $_FILES["fileToUpload"]["name"])). " has been uploaded.";
|
||||
} else {
|
||||
echo "Sorry, there was an error uploading your file.";
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
67
srcs/cgi-bin/upload_file1.php
Executable file
@@ -0,0 +1,67 @@
|
||||
#! /usr/bin/php
|
||||
|
||||
|
||||
|
||||
|
||||
<?php
|
||||
// $FileName=$_FILES['myFile']['filename'];
|
||||
# $TmpName=$_FILES['myFile']['tmp_name'];
|
||||
# move_uploaded_file($TmpName, $FileName);
|
||||
# echo("File was uploaded successfully!");
|
||||
|
||||
// this part needs to be grabed from POST uri
|
||||
$target_dir = "./www/user_files/";
|
||||
//$target_dir = $_POST["upload_dir"];
|
||||
//$target_dir = $_GET["upload_dir"];
|
||||
//$target_file = $target_dir . basename($_FILES["fileToUpload"]["name"]);
|
||||
$target_file = $target_dir . basename($_FILES["myFile"]["name"]);
|
||||
|
||||
$uploadOk = 1;
|
||||
$fileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));
|
||||
//$imageFileType = strtolower(pathinfo($target_file,PATHINFO_EXTENSION));
|
||||
|
||||
// Check if image file is a actual image or fake image
|
||||
//if(isset($_POST["submit"])) {
|
||||
// $check = getimagesize($_FILES["fileToUpload"]["tmp_name"]);
|
||||
// if($check !== false) {
|
||||
// echo "File is an image - " . $check["mime"] . ".";
|
||||
// $uploadOk = 1;
|
||||
// } else {
|
||||
// echo "File is not an image.";
|
||||
// $uploadOk = 0;
|
||||
// }
|
||||
//}
|
||||
|
||||
// Check if file already exists
|
||||
if (file_exists($target_file)) {
|
||||
echo "Sorry, file already exists.";
|
||||
$uploadOk = 0;
|
||||
}
|
||||
|
||||
// Check file size
|
||||
if ($_FILES["fileToUpload"]["size"] > 500000) {
|
||||
echo "Sorry, your file is too large.";
|
||||
$uploadOk = 0;
|
||||
}
|
||||
|
||||
// Allow certain file formats
|
||||
//if($imageFileType != "jpg" && $imageFileType != "png" && $imageFileType != "jpeg"
|
||||
//&& $imageFileType != "gif" ) {
|
||||
// echo "Sorry, only JPG, JPEG, PNG & GIF files are allowed.";
|
||||
// $uploadOk = 0;
|
||||
//}
|
||||
|
||||
// Check if $uploadOk is set to 0 by an error
|
||||
if ($uploadOk == 0) {
|
||||
echo "Sorry, your file was not uploaded.";
|
||||
// if everything is ok, try to upload file
|
||||
} else {
|
||||
if (move_uploaded_file($_FILES["fileToUpload"]["tmp_name"], $target_file)) {
|
||||
echo "The file ". htmlspecialchars( basename( $_FILES["fileToUpload"]["name"])). " has been uploaded.";
|
||||
} else {
|
||||
echo "Sorry, there was an error uploading your file.";
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
|
||||
25
srcs/colors.h
Normal file
@@ -0,0 +1,25 @@
|
||||
#ifndef COLORS_H
|
||||
# define COLORS_H
|
||||
|
||||
# define GRAY "\e[0;30m"
|
||||
# define RED "\e[0;31m"
|
||||
# define GREEN "\e[0;32m"
|
||||
# define YELLOW "\e[0;33m"
|
||||
# define BLUE "\e[0;34m"
|
||||
# define PURPLE "\e[0;35m"
|
||||
# define CYAN "\e[0;36m"
|
||||
# define WHITE "\e[0;37m"
|
||||
|
||||
# define B_GRAY "\e[1;30m"
|
||||
# define B_RED "\e[1;31m"
|
||||
# define B_GREEN "\e[1;32m"
|
||||
# define B_YELLOW "\e[1;33m"
|
||||
# define B_BLUE "\e[1;34m"
|
||||
# define B_PURPLE "\e[1;35m"
|
||||
# define B_CYAN "\e[1;36m"
|
||||
# define B_WHITE "\e[1;37m"
|
||||
|
||||
# define RESET "\e[0m"
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,400 +0,0 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* ConfigParser.cpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: lperrey <lperrey@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/07/13 22:11:17 by me #+# #+# */
|
||||
/* Updated: 2022/08/03 17:51:35 by lperrey ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#include "ConfigParser.hpp"
|
||||
|
||||
// Default
|
||||
ConfigParser::ConfigParser()
|
||||
{
|
||||
std::cout << "Default Constructor\n";
|
||||
// don't use yet, you have no idea what the defaults are
|
||||
}
|
||||
|
||||
ConfigParser::ConfigParser(const char* path)
|
||||
{
|
||||
std::cout << "Param Constructor\n";
|
||||
|
||||
std::ifstream file;
|
||||
std::string buf;
|
||||
size_t comment;
|
||||
|
||||
_content.clear();
|
||||
file.open(path);
|
||||
if (file.is_open())
|
||||
{
|
||||
// are there more throws i need to add in case of errors, what would
|
||||
// those errors be?
|
||||
while (!file.eof())
|
||||
{
|
||||
getline(file, buf);
|
||||
// remove # comments here.
|
||||
if ((comment = buf.find_first_of("#")) == std::string::npos)
|
||||
{
|
||||
// remove empty lines, i think...
|
||||
if ((buf.find_first_not_of(" \t")) != std::string::npos)
|
||||
_content.append(buf + '\n');
|
||||
}
|
||||
else if (comment > 0 && (buf.find_first_not_of(" \t")) < comment)
|
||||
{
|
||||
// is there a comment at the end of the line
|
||||
std::string tmp = buf.substr(0, comment - 1);
|
||||
_content.append(tmp + '\n');
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
else
|
||||
throw std::invalid_argument("open config");
|
||||
}
|
||||
|
||||
ConfigParser::~ConfigParser()
|
||||
{
|
||||
// do i need to destroy anything, won't it handle itself?
|
||||
}
|
||||
|
||||
/*
|
||||
ConfigParser & ConfigParser::operator=(const ConfigParser& rhs)
|
||||
{
|
||||
if (this == rhs) // * & ?
|
||||
return (*this); // * ?
|
||||
|
||||
// make some stuff equal
|
||||
return (*this);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
std::vector<ServerConfig> * ConfigParser::parse()
|
||||
{
|
||||
std::vector<ServerConfig> * ret = new std::vector<ServerConfig>();
|
||||
// std::vector<ServerConfig> ret;
|
||||
|
||||
size_t start = 0;
|
||||
size_t curr = _content.find_first_not_of(" \t\n", 0);
|
||||
|
||||
if (curr == std::string::npos)
|
||||
throw std::invalid_argument("empty config file");
|
||||
while (curr != std::string::npos)
|
||||
{
|
||||
// why no checks here
|
||||
// if not here do i need them elsewhere?
|
||||
start = _content.find_first_not_of(" \t\n", curr);
|
||||
curr = _content.find_first_of(" \t\n", start);
|
||||
std::string key = _content.substr(start, curr - start);
|
||||
if (key != "server")
|
||||
throw std::invalid_argument("bad config file arguments 1");
|
||||
ret->push_back(_parse_server(&curr));
|
||||
}
|
||||
_post_processing(ret);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
ServerConfig ConfigParser::_parse_server(size_t *start)
|
||||
{
|
||||
ServerConfig ret;
|
||||
size_t curr = _content.find_first_not_of(" \t\n", *start);
|
||||
|
||||
ret.client_body_limit = 0;
|
||||
ret.autoindex = false;
|
||||
if (curr == std::string::npos || _content[curr] != '{')
|
||||
throw std::invalid_argument("bad config file syntax 1");
|
||||
|
||||
curr = _content.find_first_of(" \t\n", curr + 1);
|
||||
// if (curr == std::string::npos) // are there other things to check for?
|
||||
// throw std::invalid_argument("bad config file syntax");
|
||||
while (curr != std::string::npos) // here curr == { + 1
|
||||
{
|
||||
// so this moves curr to past the word...
|
||||
std::string key = _get_first_word(&curr);
|
||||
// now curr is on space after 1st word.
|
||||
if (key == "}")
|
||||
{
|
||||
// why +1 curr is already after it no?
|
||||
*start = _content.find_first_not_of(" \t\n", curr + 1);
|
||||
break ;
|
||||
}
|
||||
else if (key == "location")
|
||||
ret.locations.push_back(_parse_location(&curr));
|
||||
else
|
||||
{
|
||||
std::string values = _get_rest_of_line(&curr);
|
||||
// curr now should be \n
|
||||
_set_server_values(&ret, key, values);
|
||||
}
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
|
||||
LocationConfig ConfigParser::_parse_location(size_t *start)
|
||||
{
|
||||
LocationConfig ret;
|
||||
size_t curr = *start;
|
||||
// start is after the 1st word aka "location"
|
||||
|
||||
ret.client_body_limit = 0;
|
||||
ret.redirect_status = 0;
|
||||
ret.path = _get_first_word(&curr);
|
||||
// in theory now curr should be right after the "path"
|
||||
|
||||
curr = _content.find_first_not_of(" \t\n", curr);
|
||||
|
||||
if (curr == std::string::npos || _content[curr] != '{')
|
||||
throw std::invalid_argument("bad config file syntax 2");
|
||||
|
||||
curr = _content.find_first_of(" \t\n", curr + 1);
|
||||
// if (curr == std::string::npos) // are there other things to check for?
|
||||
// throw std::invalid_argument("bad config file syntax");
|
||||
while (curr != std::string::npos)
|
||||
{
|
||||
// so this moves curr to past the word...
|
||||
std::string key = _get_first_word(&curr);
|
||||
// now curr is on space after 1st word.
|
||||
if (key == "}")
|
||||
{
|
||||
*start = curr;
|
||||
break ;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string values = _get_rest_of_line(&curr);
|
||||
// curr now should be \n
|
||||
_set_location_values(&ret, key, values);
|
||||
}
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void ConfigParser::_set_server_values(ServerConfig *server, \
|
||||
const std::string key, std::string value)
|
||||
{
|
||||
value = _pre_set_val_check(key, value);
|
||||
|
||||
std::vector<std::string> tmp_val = ::split(value, ' ');
|
||||
size_t size = tmp_val.size();
|
||||
|
||||
if (size < 1)
|
||||
throw std::invalid_argument("missing value");
|
||||
else if (key == "server_name" && size == 1)
|
||||
{
|
||||
for (size_t i = 0; i < server->server_name.size(); i++)
|
||||
{
|
||||
if (server->server_name[i].compare(tmp_val[0]) == 0)
|
||||
throw std::invalid_argument("server_name already exists");
|
||||
}
|
||||
server->server_name.push_back(tmp_val[0]);
|
||||
}
|
||||
else if (key == "listen" && size == 1 && server->host == "" \
|
||||
&& server->port == "")
|
||||
{
|
||||
if (tmp_val[0].find_first_of(":") == std::string::npos)
|
||||
{
|
||||
// should i limit which ports can be used?
|
||||
if (!::isNumeric(tmp_val[0]))
|
||||
throw std::invalid_argument("bad port number");
|
||||
server->host = "0.0.0.0";
|
||||
server->port = tmp_val[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<std::string> tmp2 = ::split(tmp_val[0], ':');
|
||||
|
||||
std::vector<std::string> ip = ::split(tmp2[0], '.');
|
||||
if (ip.size() != 4)
|
||||
throw std::invalid_argument("bad host ip");
|
||||
for (size_t i = 0; i < ip.size(); i++)
|
||||
{
|
||||
if (!::isNumeric_btw(0, 255, ip[i]))
|
||||
throw std::invalid_argument("bad host ip");
|
||||
}
|
||||
if (!::isNumeric(tmp2[1]))
|
||||
throw std::invalid_argument("bad port number");
|
||||
server->host = tmp2[0];
|
||||
server->port = tmp2[1];
|
||||
}
|
||||
}
|
||||
else if (key == "root" && size == 1 && server->root == "")
|
||||
{
|
||||
DIR* dir = opendir(tmp_val[0].c_str());
|
||||
if (dir)
|
||||
closedir(dir);
|
||||
else
|
||||
throw std::invalid_argument("root dir could not be opened");
|
||||
server->root = tmp_val[0];
|
||||
}
|
||||
else if (key == "autoindex" && size == 1)
|
||||
{
|
||||
// autoindex is a bool, there's no good way for me to see if it has
|
||||
// bet set already
|
||||
server->autoindex = (tmp_val[0] == "on" ? true : false);
|
||||
}
|
||||
else if (key == "client_body_limit" && size == 1 \
|
||||
&& server->client_body_limit == 0)
|
||||
{
|
||||
if (!::isNumeric(tmp_val[0]))
|
||||
throw std::invalid_argument("client_body_limit not a number");
|
||||
server->client_body_limit = atoi(tmp_val[0].c_str());
|
||||
}
|
||||
else if (key == "index")
|
||||
{
|
||||
// i think you can call index several times...
|
||||
// should i be doing an access?
|
||||
// since index is at the root, but root might not yet be defined
|
||||
// will check index later in post
|
||||
for (unsigned long i = 0; i != tmp_val.size(); i++)
|
||||
server->index.push_back(tmp_val[i]);
|
||||
}
|
||||
else if (key == "allow_methods" && server->allow_methods.empty())
|
||||
{
|
||||
for (unsigned long i = 0; i != tmp_val.size(); i++)
|
||||
{
|
||||
http_method m = ::str_to_http_method(tmp_val[i]);
|
||||
if (m == UNKNOWN)
|
||||
throw std::invalid_argument("not a valid method");
|
||||
server->allow_methods.push_back(m);
|
||||
}
|
||||
}
|
||||
else if (key == "error_page")
|
||||
{
|
||||
|
||||
// so it can either be just a /here/is/the/repo
|
||||
// or it can be http://some_domain.com/here
|
||||
// wtf... how should we handle...
|
||||
|
||||
|
||||
|
||||
// you can definitely call Error_pages several times, i think
|
||||
std::string path = tmp_val[tmp_val.size() - 1];
|
||||
for (unsigned long i = 0; i != tmp_val.size() - 1; i++)
|
||||
{
|
||||
// what are the bounds for Error codes?
|
||||
if (!(isNumeric_btw(0, 600, tmp_val[i])))
|
||||
throw std::invalid_argument("value not a valid number");
|
||||
int status_code = atoi(tmp_val[i].c_str());
|
||||
|
||||
// yea cuz here we continue.. why suddenly flexible not throw ?
|
||||
if (server->error_pages.find(status_code) != server->error_pages.end())
|
||||
continue ;
|
||||
server->error_pages[status_code] = path;
|
||||
}
|
||||
}
|
||||
/* else if (key == "recv_timeout" && size == 1 && server->server_name == "")
|
||||
{
|
||||
// what is tv_sec and do i need it?
|
||||
// ok so i don't fully understand this part but ok, keep for now...
|
||||
server->recv_timeout.tv_sec = atoi(tmp_val[0].c_str());
|
||||
}
|
||||
else if (key == "send_timeout" && size == 1 && server->server_name == "")
|
||||
{
|
||||
server->send_timeout.tv_sec = atoi(tmp_val[0].c_str());
|
||||
}
|
||||
*/ else
|
||||
{
|
||||
// means either you didn't write the right key, or the value is
|
||||
// missing, or the value has already been filled.
|
||||
throw std::invalid_argument("bad key value pair");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ConfigParser::_set_location_values(LocationConfig *location, \
|
||||
const std::string key, std::string value)
|
||||
{
|
||||
value = _pre_set_val_check(key, value);
|
||||
|
||||
std::vector<std::string> tmp_val = ::split(value, ' ');
|
||||
size_t size = tmp_val.size();
|
||||
|
||||
if (size < 1)
|
||||
throw std::invalid_argument("missing value");
|
||||
else if (key == "root" && size == 1 && location->root == "")
|
||||
{
|
||||
DIR* dir = opendir(tmp_val[0].c_str());
|
||||
if (dir)
|
||||
closedir(dir);
|
||||
else
|
||||
throw std::invalid_argument("root dir could not be opened");
|
||||
location->root = tmp_val[0];
|
||||
}
|
||||
else if (key == "client_body_limit" && size == 1 \
|
||||
&& location->client_body_limit == 0)
|
||||
{
|
||||
if (!::isNumeric(tmp_val[0]))
|
||||
throw std::invalid_argument("client_body_limit not a number");
|
||||
location->client_body_limit = atoi(tmp_val[0].c_str());
|
||||
}
|
||||
else if (key == "index")
|
||||
{
|
||||
// you can definitely call Index several times, i think
|
||||
for (unsigned long i = 0; i != tmp_val.size(); i++)
|
||||
location->index.push_back(tmp_val[i]);
|
||||
}
|
||||
else if (key == "allow_methods" && location->allow_methods.empty())
|
||||
{
|
||||
for (unsigned long i = 0; i != tmp_val.size(); i++)
|
||||
{
|
||||
http_method m = ::str_to_http_method(tmp_val[i]);
|
||||
if (m == UNKNOWN)
|
||||
throw std::invalid_argument("not a valid method");
|
||||
location->allow_methods.push_back(m);
|
||||
}
|
||||
}
|
||||
else if (key == "cgi_info")
|
||||
{
|
||||
// you can call cgi_info several times i think.
|
||||
// ok wtf is all this even doing, figure that out
|
||||
unsigned long i = value.find_first_of(" ");
|
||||
if (i == std::string::npos)
|
||||
throw std::invalid_argument("bad config file arguments 8");
|
||||
// ok why an int now, we gotta be more consistent!
|
||||
int j = value.find_first_not_of(" ", i);
|
||||
location->cgi_info[value.substr(0, i)] = value.substr(j, value.length());
|
||||
}
|
||||
else if (key == "return" && location->redirect_status == 0 \
|
||||
&& location->redirect_uri == "")
|
||||
{
|
||||
// actually i think there can only be one per location...
|
||||
// you can definitely call return several times, i think
|
||||
if (tmp_val.size() != 2)
|
||||
throw std::invalid_argument("wrong number of values");
|
||||
// and tmp_val[0] should be a number and tmp_val[1] a string?
|
||||
if (!(::isNumeric(tmp_val[0])))
|
||||
throw std::invalid_argument("value not a number");
|
||||
|
||||
// somehow check that tmp_val[1] is a string? or valid? how?
|
||||
// something about using access() to see if
|
||||
location->redirect_status = atoi(tmp_val[0].c_str());
|
||||
location->redirect_uri = tmp_val[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
// means either you didn't write the right key, or the value is
|
||||
// missing, or the value has already been filled.
|
||||
throw std::invalid_argument("bad key value pair");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,14 +1,3 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* ConfigParser.hpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: lperrey <lperrey@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/07/11 23:01:41 by me #+# #+# */
|
||||
/* Updated: 2022/08/03 17:32:33 by lperrey ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef CONFIGPARSER_HPP
|
||||
# define CONFIGPARSER_HPP
|
||||
@@ -22,82 +11,45 @@
|
||||
# include <exception> // exception, what
|
||||
# include <stdexcept> // runtime_error, invalid_argument
|
||||
# include <string> // string
|
||||
# include <cstdlib> // atoi (athough it's already cover by <string>)
|
||||
# include <cstdlib> // strtol, stroul
|
||||
# include <iostream> // cout, cin
|
||||
# include <fstream> // ifstream
|
||||
//# include <unistd.h> // access()
|
||||
# include <dirent.h> // opendir()
|
||||
|
||||
# include <algorithm> // sort() in Post
|
||||
|
||||
class ConfigParser {
|
||||
|
||||
public:
|
||||
public:
|
||||
|
||||
// canonical
|
||||
ConfigParser();
|
||||
~ConfigParser();
|
||||
ConfigParser(const std::string &config_file);
|
||||
|
||||
ConfigParser(const char* path); // a string?
|
||||
~ConfigParser();
|
||||
void read_config(const std::string &config_file);
|
||||
|
||||
// ideally i wouldn't have one cuz it makes no sense, when would i use it?
|
||||
// ConfigParser & operator=(const ConfigParser& rhs);
|
||||
std::vector<ServerConfig> *parse() const;
|
||||
|
||||
// void parse(); // return void cuz throw exceptions.
|
||||
std::vector<ServerConfig> * parse(); // const?
|
||||
// std::vector<ServerConfig> parse(); // const?
|
||||
void print_content() const;
|
||||
|
||||
// other parses?
|
||||
private:
|
||||
std::string _content;
|
||||
|
||||
// i thought if it were an instance of this class you could call
|
||||
// private member functions from anywhere...
|
||||
void _print_content() const;
|
||||
ServerConfig _parse_server(size_t *start) const;
|
||||
LocationConfig _parse_location(size_t *start) const;
|
||||
|
||||
private:
|
||||
std::string _content;
|
||||
void _set_server_values(ServerConfig *server, const std::string &key, std::string value) const;
|
||||
void _set_location_values(LocationConfig *location, const std::string &key, std::string value) const;
|
||||
|
||||
// explicit?
|
||||
// what exaclty does explicit do again?
|
||||
ConfigParser(); // might need a path as arg?
|
||||
// should this be in private since it always needs a path?
|
||||
|
||||
|
||||
ServerConfig _parse_server(size_t *start);
|
||||
LocationConfig _parse_location(size_t *start);
|
||||
|
||||
|
||||
void _set_server_values(ServerConfig *server, const std::string key, std::string value);
|
||||
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);
|
||||
|
||||
std::string _get_first_word(size_t *curr); // const?
|
||||
std::string _get_rest_of_line(size_t *curr); // const?
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// some sort of post processing...
|
||||
|
||||
void _post_processing(std::vector<ServerConfig> *servers);
|
||||
/* Extra */
|
||||
std::string _pre_set_val_check(const std::string &key,
|
||||
const std::string &value) const;
|
||||
|
||||
std::string _get_first_word(size_t *curr) const;
|
||||
std::string _get_rest_of_line(size_t *curr) const;
|
||||
|
||||
/* Post Processing */
|
||||
void _post_processing(std::vector<ServerConfig> *servers) const;
|
||||
bool _find_root_path_location(std::vector<LocationConfig> locations) const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
// def needs work line a better name an do i even need this?
|
||||
// should it be in Utils instead?
|
||||
class MyException : public std::invalid_argument
|
||||
{
|
||||
MyException(const std::string str)
|
||||
: std::invalid_argument(str) {}
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,85 +0,0 @@
|
||||
|
||||
|
||||
|
||||
#include "ConfigParser.hpp"
|
||||
|
||||
|
||||
|
||||
void ConfigParser::_post_processing(std::vector<ServerConfig> *servers)
|
||||
{
|
||||
|
||||
// make certain servers default
|
||||
// fill out empty settings
|
||||
// if special settings are empty throw
|
||||
|
||||
std::vector<ServerConfig>::iterator it = servers->begin();
|
||||
|
||||
while (it != servers->end())
|
||||
{
|
||||
// host and port should already be set
|
||||
if (it->host == "")
|
||||
throw std::invalid_argument("Config file needs a host and port");
|
||||
|
||||
// is that a good default?
|
||||
if (it->root == "")
|
||||
it->root = "/";
|
||||
if (it->client_body_limit == 0)
|
||||
it->client_body_limit = 5000; // what is the recomended size?
|
||||
|
||||
// autoindex should already be false by default right?
|
||||
|
||||
// what do we do if Allow methods is left empty?
|
||||
// all ?
|
||||
if (it->allow_methods.empty())
|
||||
throw std::invalid_argument("No methods specified");
|
||||
|
||||
|
||||
// what to do if index is left empty? index.html?
|
||||
// ok but i still need to check index, no idea how...
|
||||
|
||||
// if error_pages is left empty, we'll use the defaults which
|
||||
// i believe are set elsewhere...
|
||||
|
||||
std::vector<LocationConfig>::iterator it_l = it->locations.begin();
|
||||
while (it_l != it->locations.end())
|
||||
{
|
||||
// check that path is feasible...
|
||||
// opendir?
|
||||
DIR* dir = opendir(it_l->path.c_str());
|
||||
if (dir)
|
||||
closedir(dir);
|
||||
else
|
||||
throw std::invalid_argument("location dir could not be opened");
|
||||
|
||||
if (it_l->client_body_limit == 0)
|
||||
it_l->client_body_limit = 5000; // what is the recomended size?
|
||||
if (it_l->root == "")
|
||||
it_l->root = it->root;
|
||||
|
||||
// fill out allow methods from server?
|
||||
if (it_l->allow_methods.empty())
|
||||
it_l->allow_methods = it->allow_methods;
|
||||
|
||||
// fill out index from Server?
|
||||
// or do a bunch of checks on what is in there...
|
||||
|
||||
// same for redirect status i think
|
||||
|
||||
// maybe do something for Cgi_info?
|
||||
|
||||
++it_l;
|
||||
}
|
||||
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
// do the defaults at the end?
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
|
||||
|
||||
|
||||
#include "ConfigParser.hpp"
|
||||
|
||||
|
||||
|
||||
std::string ConfigParser::_pre_set_val_check(const std::string key, \
|
||||
const std::string value)
|
||||
{
|
||||
|
||||
// check key for ;
|
||||
// check values for ; at end and right number of words depending on key
|
||||
|
||||
// std::cout << "pre check\n";
|
||||
if (key.find_first_of(";") != std::string::npos)
|
||||
throw std::invalid_argument("bad config file arguments 2");
|
||||
|
||||
// there shouldn't be any tabs, right? not between values...
|
||||
if (value.find_first_of("\t") != std::string::npos)
|
||||
{
|
||||
std::cout << value << "\n";
|
||||
throw std::invalid_argument("bad config file arguments 3");
|
||||
}
|
||||
|
||||
size_t i = value.find_first_of(";");
|
||||
// so you can't have no ;
|
||||
// you can't have just ;
|
||||
// and you can't have a ; not at the end or several ;
|
||||
// in theory value_find_last_of should find the only ;
|
||||
if (i == std::string::npos || (value.find_last_not_of(" \n")) != i \
|
||||
|| value.compare(";") == 0)
|
||||
throw std::invalid_argument("bad config file arguments 4");
|
||||
|
||||
|
||||
// we Trim value.
|
||||
// is this valid?
|
||||
// would it be better to shove the result directly in tmp_val?
|
||||
// like call substr in split?
|
||||
//value = value.substr(0, i - 1);
|
||||
return (value.substr(0, i));
|
||||
}
|
||||
|
||||
|
||||
|
||||
// assumes curr is on a space or \t or \n
|
||||
// get first word? next word? word?
|
||||
std::string ConfigParser::_get_first_word(size_t *curr)
|
||||
{
|
||||
size_t start;
|
||||
|
||||
// are these checks excessive?
|
||||
if ((start = _content.find_first_not_of(" \t\n", *curr)) == std::string::npos)
|
||||
throw std::invalid_argument("bad config file arguments");
|
||||
if ((*curr = _content.find_first_of(" \t\n", start)) == std::string::npos)
|
||||
throw std::invalid_argument("bad config file arguments");
|
||||
|
||||
std::string key = _content.substr(start, *curr - start);
|
||||
|
||||
return (key);
|
||||
}
|
||||
|
||||
// also assumes curr is on a space \t or \n
|
||||
std::string ConfigParser::_get_rest_of_line(size_t *curr)
|
||||
{
|
||||
size_t start;
|
||||
|
||||
if ((start = _content.find_first_not_of(" \t\n", *curr)) == std::string::npos)
|
||||
throw std::invalid_argument("bad config file arguments");
|
||||
|
||||
// std::cout << "start + 4 = " << _content.substr(start, 4) << "\n";
|
||||
// std::cout << "curr + 4 = " << _content.substr(*curr, 4) << "\n";
|
||||
|
||||
|
||||
if ((*curr = _content.find_first_of("\n", start)) == std::string::npos)
|
||||
throw std::invalid_argument("bad config file arguments");
|
||||
|
||||
std::string values = _content.substr(start, *curr - start);
|
||||
|
||||
// std::cout << "rest of Line values: " << values << "\n";
|
||||
|
||||
return (values);
|
||||
}
|
||||
|
||||
void ConfigParser::_print_content() const
|
||||
{
|
||||
std::cout << _content;
|
||||
}
|
||||
|
||||
// I might need to make my own Exceptions to throw...
|
||||
@@ -1,56 +1,77 @@
|
||||
/* ************************************************************************** */
|
||||
/* */
|
||||
/* ::: :::::::: */
|
||||
/* LocationConfig.hpp :+: :+: :+: */
|
||||
/* +:+ +:+ +:+ */
|
||||
/* By: lperrey <lperrey@student.42.fr> +#+ +:+ +#+ */
|
||||
/* +#+#+#+#+#+ +#+ */
|
||||
/* Created: 2022/07/23 16:08:00 by me #+# #+# */
|
||||
/* Updated: 2022/08/02 14:06:07 by lperrey ### ########.fr */
|
||||
/* */
|
||||
/* ************************************************************************** */
|
||||
|
||||
#ifndef LOCATIONCONFIG_HPP
|
||||
# define LOCATIONCONFIG_HPP
|
||||
|
||||
# include <map>
|
||||
# include <vector>
|
||||
# include <string>
|
||||
|
||||
# include "utils.hpp"
|
||||
|
||||
// again, struct instead?
|
||||
class LocationConfig
|
||||
struct LocationConfig
|
||||
{
|
||||
public:
|
||||
// canonic stuff?
|
||||
|
||||
std::string path;
|
||||
|
||||
int client_body_limit;
|
||||
std::string root;
|
||||
std::string path; // /path and /path/ are fine
|
||||
// i remove trailing / systematically
|
||||
std::string root;
|
||||
std::vector<std::string> index;
|
||||
std::vector<http_method> allow_methods;
|
||||
std::map<std::string, std::string> cgi_info;
|
||||
unsigned int allow_methods;
|
||||
std::vector<std::string> cgi_ext; // php not .php
|
||||
bool autoindex;
|
||||
|
||||
// wait if i can call several times, shouldn't it be a map?
|
||||
// wait no there can only be 1 and i think it might have to be in
|
||||
// location only...
|
||||
int redirect_status;
|
||||
std::string redirect_uri;
|
||||
// au pire you do location / { return 301 http://location; }
|
||||
// and that's how you get the redirect from the root.
|
||||
std::string upload_dir;
|
||||
|
||||
int redirect_status; // only in location
|
||||
std::string redirect_uri; // only 1 per location
|
||||
|
||||
void print_all() const
|
||||
{
|
||||
std::cout << "\nPRINTING A LOCATION\n";
|
||||
|
||||
std::cout << "Path: " << path << '\n';
|
||||
std::cout << "root: " << root << '\n';
|
||||
std::cout << "autoindex: " << autoindex << '\n';
|
||||
|
||||
std::cout << "Skipping index...\n";
|
||||
|
||||
std::cout << "Location allow_methods: ";
|
||||
std::cout << ::http_methods_to_str(allow_methods) << "\n";
|
||||
|
||||
std::cout << "Skipping redirect status etc...\n";
|
||||
|
||||
std::cout << "------\n";
|
||||
}
|
||||
|
||||
bool operator<(const LocationConfig& rhs) const
|
||||
{
|
||||
int comp_lhs = 0;
|
||||
int comp_rhs = 0;
|
||||
size_t tmp = 0;
|
||||
|
||||
while ((tmp = this->path.find_first_of("/", tmp)) != NPOS)
|
||||
{
|
||||
++tmp;
|
||||
++comp_lhs;
|
||||
}
|
||||
if (path[path.find_last_of("/") + 1] != '\0')
|
||||
++comp_lhs;
|
||||
tmp = 0;
|
||||
while ((tmp = rhs.path.find_first_of("/", tmp)) != NPOS)
|
||||
{
|
||||
++tmp;
|
||||
++comp_rhs;
|
||||
}
|
||||
if (rhs.path[rhs.path.find_last_of("/") + 1] != '\0')
|
||||
++comp_rhs;
|
||||
|
||||
return (comp_lhs < comp_rhs);
|
||||
};
|
||||
|
||||
bool operator==(const LocationConfig& rhs) const
|
||||
{
|
||||
if (path.compare(rhs.path) == 0)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -10,54 +10,24 @@
|
||||
# include <string> // string
|
||||
# include <iostream> // cout, cin
|
||||
|
||||
// a class that's all public? just so we have options?
|
||||
class ServerConfig
|
||||
struct ServerConfig
|
||||
{
|
||||
public:
|
||||
|
||||
// do i need some canonic stuff?
|
||||
|
||||
|
||||
// there can be several
|
||||
std::vector<std::string> server_name;
|
||||
// we could shove default in here if we wanted to...
|
||||
|
||||
// there can only be 1 per server...
|
||||
std::string host;
|
||||
std::string port; // port needs to be something else... not quite an int
|
||||
// should a Server be able to handle several?
|
||||
std::string port;
|
||||
|
||||
// there can only be one.
|
||||
std::string root;
|
||||
|
||||
unsigned int client_body_limit; // set to default max if none set
|
||||
size_t client_body_limit;
|
||||
|
||||
// might be the only one we let slide if bad input...
|
||||
bool autoindex;
|
||||
|
||||
// we will check the index in the post processing with access() ?
|
||||
std::vector<std::string> index;
|
||||
std::map<int, std::string> error_pages;
|
||||
|
||||
// i'm tempted to do something diff for storing method types...
|
||||
// fuck it, you can only call allow_methods once in Server
|
||||
// once more in each location.
|
||||
std::vector<http_method> allow_methods;
|
||||
|
||||
std::vector<LocationConfig> locations;
|
||||
|
||||
// not convinced we need these...
|
||||
// struct timeval send_timeout;
|
||||
// struct timeval recv_timeout;
|
||||
|
||||
|
||||
// fuck maybe i do need return here...
|
||||
// wait if i can call several times, shouldn't it be a map?
|
||||
// i think actually there can only be 1 and it can only be in a location?
|
||||
// int redirect_status;
|
||||
// std::string redirect_uri;
|
||||
|
||||
void print_all()
|
||||
void print_all() const
|
||||
{
|
||||
std::cout << "PRINTING A FULL SERVER CONFIG\n\n";
|
||||
|
||||
@@ -68,20 +38,14 @@ public:
|
||||
for (size_t i = 0; i < index.size(); i++)
|
||||
std::cout << index[i] << " ";
|
||||
std::cout << "\nerror_pages: ";
|
||||
for(std::map<int, std::string>::iterator it = error_pages.begin(); \
|
||||
for(std::map<int, std::string>::const_iterator it = error_pages.begin(); \
|
||||
it != error_pages.end(); it++)
|
||||
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 << "\nallow_methods: ";
|
||||
for (size_t i = 0; i < allow_methods.size(); i++)
|
||||
std::cout << allow_methods[i] << " ";
|
||||
std::cout << "\nskiping Locations for now...\n";
|
||||
std::cout << "also skiping send_timeout and recv\n";
|
||||
std::cout << "autoindex: " << autoindex << '\n';
|
||||
|
||||
for (std::vector<LocationConfig>::const_iterator it = locations.begin(); it < locations.end(); it++)
|
||||
it->print_all();
|
||||
|
||||
std::cout << "client_body_limit: " << client_body_limit << '\n';
|
||||
// std::cout << "redirect_status: " << redirect_status << '\n';
|
||||
// std::cout << "redirect_uri: " << redirect_uri << '\n';
|
||||
std::cout << "host: " << host << '\n';
|
||||
std::cout << "port: " << port << '\n';
|
||||
|
||||
|
||||
63
srcs/config/extraConfig.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
|
||||
#include "ConfigParser.hpp"
|
||||
|
||||
std::string ConfigParser::_pre_set_val_check(const std::string &key,
|
||||
const std::string &value) const
|
||||
{
|
||||
|
||||
// check key for ;
|
||||
// check values for ; at end and right number of words depending on key
|
||||
|
||||
if (key.find_first_of(";") != NPOS)
|
||||
throw std::invalid_argument("bad config file arguments");
|
||||
|
||||
if (value.find_first_of("\t") != NPOS)
|
||||
throw std::invalid_argument("why would you put tabs between values");
|
||||
|
||||
size_t i = value.find_first_of(";");
|
||||
// so you can't have no ;
|
||||
// you can't have just ;
|
||||
// and you can't have a ; not at the end or several ;
|
||||
// in theory value_find_last_of should find the only ;
|
||||
if (i == NPOS || (value.find_last_not_of(" \n")) != i \
|
||||
|| value.compare(";") == 0)
|
||||
throw std::invalid_argument("bad config file arguments");
|
||||
|
||||
|
||||
return (value.substr(0, i));
|
||||
}
|
||||
|
||||
// assumes curr is on a space or \t or \n
|
||||
std::string ConfigParser::_get_first_word(size_t *curr) const
|
||||
{
|
||||
size_t start;
|
||||
|
||||
if ((start = _content.find_first_not_of(" \t\n", *curr)) == NPOS)
|
||||
throw std::invalid_argument("bad config file arguments");
|
||||
if ((*curr = _content.find_first_of(" \t\n", start)) == NPOS)
|
||||
throw std::invalid_argument("bad config file arguments");
|
||||
|
||||
std::string key = _content.substr(start, *curr - start);
|
||||
return (key);
|
||||
}
|
||||
|
||||
// also assumes curr is on a space \t or \n
|
||||
std::string ConfigParser::_get_rest_of_line(size_t *curr) const
|
||||
{
|
||||
size_t start;
|
||||
|
||||
if ((start = _content.find_first_not_of(" \t\n", *curr)) == NPOS)
|
||||
throw std::invalid_argument("bad config file arguments");
|
||||
if ((*curr = _content.find_first_of("\n", start)) == NPOS)
|
||||
throw std::invalid_argument("bad config file arguments");
|
||||
|
||||
std::string values = _content.substr(start, *curr - start);
|
||||
return (values);
|
||||
}
|
||||
|
||||
|
||||
void ConfigParser::print_content() const
|
||||
{
|
||||
std::cout << _content;
|
||||
}
|
||||
|
||||
319
srcs/config/parser.cpp
Normal file
@@ -0,0 +1,319 @@
|
||||
|
||||
#include "ConfigParser.hpp"
|
||||
|
||||
ConfigParser::ConfigParser() {};
|
||||
ConfigParser::~ConfigParser() {};
|
||||
|
||||
ConfigParser::ConfigParser(const std::string &config_file)
|
||||
{
|
||||
read_config(config_file);
|
||||
}
|
||||
|
||||
void ConfigParser::read_config(const std::string &config_file)
|
||||
{
|
||||
std::ifstream file;
|
||||
std::string buf;
|
||||
size_t comment;
|
||||
|
||||
file.open(config_file.c_str());
|
||||
if (!file)
|
||||
throw std::invalid_argument("failed to open config");
|
||||
else
|
||||
{
|
||||
_content.clear();
|
||||
while (!file.eof())
|
||||
{
|
||||
getline(file, buf);
|
||||
// remove # comments here.
|
||||
if ((comment = buf.find_first_of("#")) == NPOS)
|
||||
{
|
||||
// remove empty lines, i think...
|
||||
if ((buf.find_first_not_of(" \t")) != NPOS)
|
||||
_content.append(buf + '\n');
|
||||
}
|
||||
else if (comment > 0 && (buf.find_first_not_of(" \t")) < comment)
|
||||
{
|
||||
// check for comment at the end of the line
|
||||
std::string tmp = buf.substr(0, comment - 1);
|
||||
_content.append(tmp + '\n');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<ServerConfig> * ConfigParser::parse() const
|
||||
{
|
||||
std::vector<ServerConfig> * ret = new std::vector<ServerConfig>();
|
||||
|
||||
size_t start = 0;
|
||||
size_t curr = _content.find_first_not_of(" \t\n", 0);
|
||||
|
||||
if (curr == NPOS)
|
||||
throw std::invalid_argument("empty config file");
|
||||
while (curr != NPOS)
|
||||
{
|
||||
if ((start = _content.find_first_not_of(" \t\n", curr)) == NPOS)
|
||||
throw std::invalid_argument("empty config file");
|
||||
|
||||
if ((curr = _content.find_first_of(" \t\n", start)) == NPOS)
|
||||
throw std::invalid_argument("empty config file");
|
||||
std::string key = _content.substr(start, curr - start);
|
||||
if (key != "server")
|
||||
throw std::invalid_argument("bad config file arguments");
|
||||
ret->push_back(_parse_server(&curr));
|
||||
}
|
||||
_post_processing(ret);
|
||||
return (ret);
|
||||
}
|
||||
|
||||
ServerConfig ConfigParser::_parse_server(size_t *start) const
|
||||
{
|
||||
ServerConfig ret;
|
||||
size_t curr = _content.find_first_not_of(" \t\n", *start);
|
||||
|
||||
ret.client_body_limit = 0;
|
||||
if (curr == NPOS || _content[curr] != '{')
|
||||
throw std::invalid_argument("bad config file syntax");
|
||||
|
||||
if ((curr = _content.find_first_of(" \t\n", curr + 1)) == NPOS)
|
||||
throw std::invalid_argument("bad config file syntax");
|
||||
while (curr != NPOS) // here curr == { + 1
|
||||
{
|
||||
// so this moves curr to past the word...
|
||||
std::string key = _get_first_word(&curr);
|
||||
// now curr is on space after 1st word.
|
||||
if (key == "}")
|
||||
{
|
||||
// why +1 curr is already after it no?
|
||||
*start = _content.find_first_not_of(" \t\n", curr + 1);
|
||||
break ;
|
||||
}
|
||||
else if (key == "location")
|
||||
ret.locations.push_back(_parse_location(&curr));
|
||||
else
|
||||
{
|
||||
std::string values = _get_rest_of_line(&curr);
|
||||
// curr now should be \n
|
||||
_set_server_values(&ret, key, values);
|
||||
}
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
|
||||
LocationConfig ConfigParser::_parse_location(size_t *start) const
|
||||
{
|
||||
LocationConfig ret;
|
||||
size_t curr = *start;
|
||||
// start is after the 1st word aka "location"
|
||||
|
||||
ret.autoindex = false;
|
||||
ret.redirect_status = 0;
|
||||
ret.allow_methods = 0;
|
||||
|
||||
ret.path = _get_first_word(&curr);
|
||||
if (ret.path[0] != '/')
|
||||
throw std::invalid_argument("Location path require a leading /");
|
||||
// in theory now curr should be right after the "path"
|
||||
|
||||
curr = _content.find_first_not_of(" \t\n", curr);
|
||||
|
||||
if (curr == NPOS || _content[curr] != '{')
|
||||
throw std::invalid_argument("bad config file syntax");
|
||||
|
||||
if ((curr = _content.find_first_of(" \t\n", curr + 1)) == NPOS)
|
||||
throw std::invalid_argument("bad config file syntax");
|
||||
while (curr != NPOS)
|
||||
{
|
||||
// so this moves curr to past the word...
|
||||
std::string key = _get_first_word(&curr);
|
||||
// now curr is on space after 1st word.
|
||||
if (key == "}")
|
||||
{
|
||||
*start = curr;
|
||||
break ;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string values = _get_rest_of_line(&curr);
|
||||
// curr now should be \n
|
||||
_set_location_values(&ret, key, values);
|
||||
}
|
||||
}
|
||||
return (ret);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ConfigParser::_set_server_values(ServerConfig *server,
|
||||
const std::string &key, std::string value) const
|
||||
{
|
||||
value = _pre_set_val_check(key, value);
|
||||
|
||||
std::vector<std::string> tmp_val = ::split(value, ' ');
|
||||
size_t size = tmp_val.size();
|
||||
|
||||
if (size < 1)
|
||||
throw std::invalid_argument("missing value");
|
||||
else if (key == "server_name" && server->server_name.empty())
|
||||
{
|
||||
for (size_t i = 0; i < size; i++)
|
||||
{
|
||||
for (std::vector<std::string>::const_iterator it = server->server_name.begin();
|
||||
it < server->server_name.end(); it++)
|
||||
{
|
||||
if (it->compare(tmp_val[i]) == 0)
|
||||
throw std::invalid_argument("server_name already exists");
|
||||
}
|
||||
server->server_name.push_back(tmp_val[i]);
|
||||
}
|
||||
}
|
||||
else if (key == "listen" && size == 1 && server->host == ""
|
||||
&& server->port == "")
|
||||
{
|
||||
if (tmp_val[0].find_first_of(":") == NPOS)
|
||||
{
|
||||
if (!::is_numeric_btw(0, 65535, tmp_val[0]))
|
||||
throw std::invalid_argument("bad port number");
|
||||
server->host = "0.0.0.0";
|
||||
server->port = tmp_val[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
std::vector<std::string> tmp2 = ::split(tmp_val[0], ':');
|
||||
|
||||
std::vector<std::string> ip = ::split(tmp2[0], '.');
|
||||
if (ip.size() != 4)
|
||||
throw std::invalid_argument("bad host ip");
|
||||
for (size_t i = 0; i < ip.size(); i++)
|
||||
{
|
||||
if (!::is_numeric_btw(0, 255, ip[i]))
|
||||
throw std::invalid_argument("bad host ip");
|
||||
}
|
||||
if (!::is_numeric_btw(0, 65535, tmp2[1]))
|
||||
throw std::invalid_argument("bad port number");
|
||||
server->host = tmp2[0];
|
||||
server->port = tmp2[1];
|
||||
}
|
||||
}
|
||||
else if (key == "root" && size == 1 && server->root == "")
|
||||
{
|
||||
// remove trailing /
|
||||
if (tmp_val[0][tmp_val[0].size() - 1] == '/')
|
||||
tmp_val[0].erase(tmp_val[0].size() - 1, 1);
|
||||
server->root = tmp_val[0];
|
||||
}
|
||||
else if (key == "client_body_limit" && size == 1
|
||||
&& server->client_body_limit == 0)
|
||||
{
|
||||
if (!::is_numeric(tmp_val[0]))
|
||||
throw std::invalid_argument("client_body_limit not a number");
|
||||
server->client_body_limit = std::strtoul(tmp_val[0].c_str(), NULL, 10);
|
||||
if (errno == ERANGE || server->client_body_limit > (ULONG_MAX / KB) )
|
||||
throw std::invalid_argument("client_body_limit too big");
|
||||
server->client_body_limit = server->client_body_limit * KB;
|
||||
}
|
||||
else if (key == "index")
|
||||
{
|
||||
for (size_t i = 0; i != tmp_val.size(); i++)
|
||||
server->index.push_back(tmp_val[i]);
|
||||
}
|
||||
else if (key == "error_page")
|
||||
{
|
||||
std::string path = tmp_val[size - 1];
|
||||
for (size_t i = 0; i < size - 1; i++)
|
||||
{
|
||||
if (!(is_numeric_btw(400, 599, tmp_val[i])))
|
||||
throw std::invalid_argument("invalid error code");
|
||||
int status_code = std::strtoul(tmp_val[i].c_str(), NULL, 10);
|
||||
if (server->error_pages.find(status_code) != server->error_pages.end())
|
||||
throw std::invalid_argument("redeclaring error page");
|
||||
server->error_pages[status_code] = path;
|
||||
}
|
||||
}
|
||||
else
|
||||
throw std::invalid_argument("bad key value pair");
|
||||
}
|
||||
|
||||
|
||||
void ConfigParser::_set_location_values(LocationConfig *location,
|
||||
const std::string &key, std::string value) const
|
||||
{
|
||||
value = _pre_set_val_check(key, value);
|
||||
|
||||
std::vector<std::string> tmp_val = ::split(value, ' ');
|
||||
size_t size = tmp_val.size();
|
||||
|
||||
if (size < 1)
|
||||
throw std::invalid_argument("missing value");
|
||||
else if (key == "root" && size == 1 && location->root == "")
|
||||
{
|
||||
// remove trailing /
|
||||
if (tmp_val[0][tmp_val[0].size() - 1] == '/')
|
||||
tmp_val[0].erase(tmp_val[0].size() - 1, 1);
|
||||
location->root = tmp_val[0];
|
||||
}
|
||||
else if (key == "autoindex" && size == 1)
|
||||
location->autoindex = (tmp_val[0] == "on" ? true : false);
|
||||
else if (key == "index")
|
||||
{
|
||||
for (size_t i = 0; i < size; i++)
|
||||
location->index.push_back(tmp_val[i]);
|
||||
}
|
||||
else if (key == "allow_methods" && location->allow_methods == 0)
|
||||
{
|
||||
for (size_t i = 0; i < size; i++)
|
||||
{
|
||||
http_method m = ::str_to_http_method(tmp_val[i]);
|
||||
if (m == UNKNOWN)
|
||||
throw std::invalid_argument("not a valid method");
|
||||
location->allow_methods |= m;
|
||||
}
|
||||
}
|
||||
else if (key == "cgi_ext")
|
||||
{
|
||||
for (size_t i = 0; i < size; i++)
|
||||
{
|
||||
if (tmp_val[i][0] == '.')
|
||||
throw std::invalid_argument("cgi_ext should not have a leading '.'");
|
||||
location->cgi_ext.push_back(tmp_val[i]);
|
||||
}
|
||||
}
|
||||
else if (key == "redirect" && location->redirect_status == 0
|
||||
&& location->redirect_uri == "")
|
||||
{
|
||||
if (size != 2)
|
||||
throw std::invalid_argument("wrong number of values");
|
||||
if (tmp_val[0] != "301" && tmp_val[0] != "302"
|
||||
&& tmp_val[0] != "303" && tmp_val[0] != "307"
|
||||
&& tmp_val[0] != "308")
|
||||
throw std::invalid_argument("bad redirect status");
|
||||
if (tmp_val[1].compare(0, 7, "http://")
|
||||
&& tmp_val[1].compare(0, 8, "https://"))
|
||||
throw std::invalid_argument("bad redirect uri");
|
||||
|
||||
location->redirect_status = std::strtoul(tmp_val[0].c_str(), NULL, 10);
|
||||
location->redirect_uri = tmp_val[1];
|
||||
}
|
||||
else if (key == "upload_dir" && size == 1 && location->upload_dir == "")
|
||||
{
|
||||
// add trailing /
|
||||
if (tmp_val[0][tmp_val[0].size() - 1] != '/')
|
||||
tmp_val[0].push_back('/');
|
||||
location->upload_dir = tmp_val[0];
|
||||
}
|
||||
else
|
||||
throw std::invalid_argument("bad key value pair");
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
90
srcs/config/postProcessing.cpp
Normal file
@@ -0,0 +1,90 @@
|
||||
|
||||
|
||||
|
||||
#include "ConfigParser.hpp"
|
||||
|
||||
void ConfigParser::_post_processing(std::vector<ServerConfig> *servers) const
|
||||
{
|
||||
std::vector<ServerConfig>::iterator it = servers->begin();
|
||||
|
||||
while (it != servers->end())
|
||||
{
|
||||
if (it->host == "")
|
||||
throw std::invalid_argument("Config file needs a host and port");
|
||||
|
||||
if (it->root == "")
|
||||
throw std::invalid_argument("Config file needs a root");
|
||||
|
||||
if (it->index.empty())
|
||||
throw std::invalid_argument("Config file needs an Index");
|
||||
|
||||
if (it->client_body_limit == 0)
|
||||
it->client_body_limit = 1 * MB;
|
||||
|
||||
if (!_find_root_path_location(it->locations))
|
||||
{
|
||||
LocationConfig tmp;
|
||||
|
||||
tmp.path = "/";
|
||||
tmp.root = it->root;
|
||||
tmp.index = it->index;
|
||||
tmp.allow_methods = ANY_METHODS;
|
||||
tmp.autoindex = false;
|
||||
tmp.redirect_status = 0;
|
||||
it->locations.push_back(tmp);
|
||||
}
|
||||
|
||||
std::vector<LocationConfig>::iterator it_l = it->locations.begin();
|
||||
|
||||
while (it_l != it->locations.end())
|
||||
{
|
||||
if (it_l->path[it_l->path.size() - 1] == '/'
|
||||
&& it_l->path.size() > 1)
|
||||
it_l->path.erase(it_l->path.size() - 1);
|
||||
|
||||
if (it_l->root == "")
|
||||
it_l->root = it->root;
|
||||
|
||||
if (it_l->allow_methods == UNKNOWN)
|
||||
it_l->allow_methods = ANY_METHODS;
|
||||
|
||||
if (it_l->index.empty() && it_l->autoindex == false)
|
||||
it_l->index = it->index;
|
||||
|
||||
// nothing to be done for cgi_ext, error_pages, redirect
|
||||
|
||||
++it_l;
|
||||
}
|
||||
|
||||
it_l = it->locations.begin();
|
||||
while (it_l != it->locations.end())
|
||||
{
|
||||
std::vector<LocationConfig>::const_iterator tmp = it_l + 1;
|
||||
while (tmp != it->locations.end())
|
||||
{
|
||||
if (it_l->path == tmp->path)
|
||||
throw std::invalid_argument("Duplicate locations in config file");
|
||||
++tmp;
|
||||
}
|
||||
++it_l;
|
||||
}
|
||||
|
||||
std::sort(it->locations.begin(), it->locations.end());
|
||||
std::reverse(it->locations.begin(), it->locations.end());
|
||||
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
bool ConfigParser::_find_root_path_location(std::vector<LocationConfig> locations) const
|
||||
{
|
||||
std::vector<LocationConfig>::const_iterator it = locations.begin();
|
||||
|
||||
while (it != locations.end())
|
||||
{
|
||||
if (it->path.compare("/") == 0)
|
||||
return true;
|
||||
++it;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -5,47 +5,37 @@
|
||||
#include "Webserv.hpp"
|
||||
#include "ConfigParser.hpp"
|
||||
|
||||
// debug
|
||||
family_state g_family;
|
||||
sem_t* g_shmem;
|
||||
// debug end
|
||||
|
||||
int main(int ac, char **av)
|
||||
{
|
||||
// debug
|
||||
init_semaphore();
|
||||
|
||||
std::vector<ServerConfig>* servers_config = NULL;
|
||||
try
|
||||
{
|
||||
std::string config = (ac == 2 ? av[1] : "./default.config");
|
||||
|
||||
// like this just looks kinda gross, why bother creating an instance
|
||||
// and not immediately parsing? like it servers no other purpose...
|
||||
// what if i call parse directly in the constructor?
|
||||
// oh because the constructor has no return, but still
|
||||
// is there a better way?
|
||||
ConfigParser configParser(config);
|
||||
// configParser.print_content();
|
||||
|
||||
ConfigParser configParser(config.c_str());
|
||||
|
||||
configParser._print_content();
|
||||
|
||||
// i don't love that servers has to be a pointer...
|
||||
std::vector<ServerConfig>* servers = configParser.parse();
|
||||
|
||||
// use an iterator you moron
|
||||
for (std::vector<ServerConfig>::iterator it = servers->begin(); it < servers->end(); it++)
|
||||
{
|
||||
// std::cout << it->server_name << " ";
|
||||
it->print_all();
|
||||
}
|
||||
|
||||
|
||||
// Webserv serv(configParser.parse());
|
||||
// is this better or worse than using
|
||||
servers_config = configParser.parse();
|
||||
|
||||
Webserv serv;
|
||||
|
||||
// serv.init_virtual_servers();
|
||||
serv.init_virtual_servers(servers);
|
||||
delete servers;
|
||||
serv.init_virtual_servers(servers_config);
|
||||
delete servers_config;
|
||||
servers_config = NULL;
|
||||
serv.run();
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
std::cout << e.what() << '\n';
|
||||
std::cerr << e.what() << '\n';
|
||||
delete servers_config;
|
||||
}
|
||||
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||