From b30a3a1407fb06df0438fef81cfe609bafe78e18 Mon Sep 17 00:00:00 2001 From: hugogogo Date: Tue, 2 Aug 2022 16:33:29 +0200 Subject: [PATCH 01/21] starting to find usefull informations in cgi rfc --- README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/README.md b/README.md index 20c8b93..074ff2c 100644 --- a/README.md +++ b/README.md @@ -89,6 +89,20 @@ - [ ] Your server should never die. +--- +## cgi rfc +[rfc 3875](https://www.rfc-editor.org/rfc/rfc3875) + +[server responsabilities](https://www.rfc-editor.org/rfc/rfc3875#section-3.1) +- The server [...] receives the request from the client +- selects a CGI script to handle the request +- converts the client request to a CGI request +- executes the script and converts the CGI response into a response for the client + +[script uri](https://www.rfc-editor.org/rfc/rfc3875#section-3.3) +- the 'Script-URI' [...] MUST have the property that if the client had accessed this URI instead, then the script would have been executed + + --- ## cgi env variables [cgi env variables](http://www.faqs.org/rfcs/rfc3875.html) From d79281751a53acbb989e3f61f42dc3cdbefe396a Mon Sep 17 00:00:00 2001 From: hugogogo Date: Tue, 2 Aug 2022 21:16:09 +0200 Subject: [PATCH 02/21] cgi rfc parsing into readme --- README.md | 80 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 59 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 074ff2c..db65285 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,4 @@ ---- -## questions -- mettre les fonctions specifiques a la requete, dans la class client ? -- où est-ce que j'inclus le cgi ? -- est-ce que le cgi est appellé par `/cgi-bin` ? - - non -- g rajouté `char ** env` dans client.cpp - - non -- ajouter un champ "message body" dans client ? - - non -- comment organiser la creation du message reponse (cgi ou pas) et des headers ? -- comment je gere le path `/cgi-bin/` avec la suite ? -- qu'est-ce que le cgi renvoit comme headers ? comment c'est géré ? - - https://www.rfc-editor.org/rfc/rfc3875 - --- ## man @@ -88,30 +73,83 @@ - [ ] Your server must be able to listen to multiple ports (see Configuration file) - [ ] Your server should never die. - --- ## cgi rfc [rfc 3875](https://www.rfc-editor.org/rfc/rfc3875) -[server responsabilities](https://www.rfc-editor.org/rfc/rfc3875#section-3.1) +[3.1: server responsabilities](https://www.rfc-editor.org/rfc/rfc3875#section-3.1) - The server [...] receives the request from the client - selects a CGI script to handle the request - converts the client request to a CGI request - executes the script and converts the CGI response into a response for the client -[script uri](https://www.rfc-editor.org/rfc/rfc3875#section-3.3) +[3.3: script uri](https://www.rfc-editor.org/rfc/rfc3875#section-3.3) - the 'Script-URI' [...] MUST have the property that if the client had accessed this URI instead, then the script would have been executed +[4: how the server prepare the cgi requests](https://www.rfc-editor.org/rfc/rfc3875#section-4) +- the cgi receives 2 differents set of informations : + - the request meta-variables, + - and the message-body + +[4.1: request meta-variables](https://www.rfc-editor.org/rfc/rfc3875#section-4.1) +- a header field that spans multiple lines MUST be merged onto a single line + +[4.2: request message-body](https://www.rfc-editor.org/rfc/rfc3875#section-4.2) +- unless defined otherwise, the script access request data by reading stdin + +[6: how the response from the script is returned to the server](https://www.rfc-editor.org/rfc/rfc3875#section-6) +- The response comprises 2 parts, separated by a blank line : + - a message-header + - and a message-body +- The message-header contains one or more header fields +- The body may be NULL + +[6.2: responses types](https://www.rfc-editor.org/rfc/rfc3875#section-6.2) +- four types of responses : + - document response + - local redirect response + - client redirect response + - client redirect response with document +- document response : + - it must return a Content-Type header field + - a Status-Header field is optional (200 is assumed if omited) + - the server must check the cgi-script output, and modifie it to comply with the protocol version +- local redirect response : + - it must return only a Location field + - it contains a local path URI and query string ('local-pathquery') + - the server must generate the response for this local-pathquery +- client redirect response : + - it must return only a Location field + - it contains an absolute URI path, to indicate the client that it should reprocess the request with this URI + - the http server must generate a 302 'Found' message +- client redirect response with document + - it must return a Location field with an absolute URI path + - it must return the Status header field, with a value of 302 'Found' + - the server must check the cgi-script output, and modifie it to comply with the protocol version + +[6.3: cgi header fields](https://www.rfc-editor.org/rfc/rfc3875#section-6.3) +- whitespace is permitted between the ":" and the field-value +- but not between the field-name and the ":" +- the CGI script can set three differents fields : + - Content-Type + - Location + - Status +- Content-Type : + - if there is a body in the response, a Content-Type field must be present + - if there is no Content-Type, the server must not attempt to determine one +- Location : + +- Status : --- ## cgi env variables -[cgi env variables](http://www.faqs.org/rfcs/rfc3875.html) +[cgi env variables](https://www.rfc-editor.org/rfc/rfc3875#section-4.1) [wikipedia variables environnements cgi](https://fr.wikipedia.org/wiki/Variables_d%27environnement_CGI) [cgi server variables on adobe](https://helpx.adobe.com/coldfusion/cfml-reference/reserved-words-and-variables/cgi-environment-cgi-scope-variables/cgi-server-variables.html) ``` AUTH_TYPE : if the srcipt is protected, the authentification method used to validate the user -CONTENT_LENGTH : length of the request content -CONTENT_TYPE : if there is attached information, as with method POST or PUT, this is the content type of the data (e.g. "text/plain", it is set by the attribute "enctype" in html
as three values : "application/x-www-form-urlencoded", "multipart/form-data", "text/plain") +CONTENT_LENGTH : length of the request body-message +CONTENT_TYPE : (Content-Type field) if there is attached information, as with method POST or PUT, this is the content type of the data (e.g. "text/plain", it is set by the attribute "enctype" in html as three values : "application/x-www-form-urlencoded", "multipart/form-data", "text/plain") GATEWAY_INTERFACE : CGI version (e.g. CGI/1.1) PATH_INFO : if any, path of the resquest in addition to the cgi script path (e.g. for cgi script path = "/usr/web/cgi-bin/script.cgi", and the url = "http://server.org/cgi-bin/script.cgi/house", the PATH-INFO would be "house") PATH_TRANSLATED : full path of the request, like path-to-cgi/PATH_INFO, null if PATH_INFO is null (e.g. for "http://server.org/cgi-bin/prog/the/path", PATH_INFO would be : "/the/path" and PATH_TRANSLATED would be : "/usr/web/cgi-bin/prog/the/path") From 41b5e578006ce7f6d424dd61814d93c2ed5fde6e Mon Sep 17 00:00:00 2001 From: hugogogo Date: Tue, 2 Aug 2022 23:39:53 +0200 Subject: [PATCH 03/21] finish to read cgi rfc --- README.md | 36 ++++++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index db65285..820b021 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ [4: how the server prepare the cgi requests](https://www.rfc-editor.org/rfc/rfc3875#section-4) - the cgi receives 2 differents set of informations : - - the request meta-variables, + - the request meta-variables (in UNIX, by env variables) - and the message-body [4.1: request meta-variables](https://www.rfc-editor.org/rfc/rfc3875#section-4.1) @@ -138,8 +138,40 @@ - if there is a body in the response, a Content-Type field must be present - if there is no Content-Type, the server must not attempt to determine one - Location : - + - the local URI path must be an absolut path, not a relative path, nor NULL + - the local URI path must, then, start with "/" + - the absolut URI start with ":" - Status : + - a 3-digit integer code + - 4 standards : + - 200 'OK' indicates success, it's the default value + - 302 'Found' with Location header and response message-body + - 400 'Bad Request' an unknown request format, like missing CONTENT-TYPE + - 501 'Not Implemented' the script received unsupported REQUEST-METHOD + - construction: `Status:400 "explication of the error"\n` +- the cgi-script can return other header fields, concerning the response message + - the server must translate cgi-headers syntax into http-header syntax + - for exemple, newline can be encoded in different ways +- the cgi-script must not return header fields concerning client-side communication + - the server can remove such fields + - (not sure : https://www.rfc-editor.org/rfc/rfc3875#section-6.3.4) + - the server must resolve conflicts between script-header fields and themselves + +[6.3: cgi message body](https://www.rfc-editor.org/rfc/rfc3875#section-6.4) +- the server must read it untill EOF +- the server must not modify it, except to convert charset if needed + +[7 and 8: usefull informations about implementation and security](https://www.rfc-editor.org/rfc/rfc3875#section-7) + +- le cgi-script doit renvoyer au moins un header suivit d'une ligne vide +- il peut dans certains cas envoyer d'autres headers +- le serveur doit verifier qu'il n'y a pas de doublons dans les headers +- le serveur doit verifier le formatage des headers (typiquement l'encodage, par exemple pour les newlines) +- ? comment on passe le body-message au script ? section 4.2 +- ? on doit gerer l'authentification ? +- ? pourquoi on doit construire un script-cgi ? section 3.3 +- ? si l'uri correspond au script-cgi, ca appel le script donc ? section 3.3 + --- ## cgi env variables From c331b69600da6cabc5d709d1446c98805e198f59 Mon Sep 17 00:00:00 2001 From: hugogogo Date: Tue, 2 Aug 2022 23:42:45 +0200 Subject: [PATCH 04/21] cgi explanation reademe layout --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 820b021..c7d2c5b 100644 --- a/README.md +++ b/README.md @@ -78,26 +78,32 @@ [rfc 3875](https://www.rfc-editor.org/rfc/rfc3875) [3.1: server responsabilities](https://www.rfc-editor.org/rfc/rfc3875#section-3.1) + - The server [...] receives the request from the client - selects a CGI script to handle the request - converts the client request to a CGI request - executes the script and converts the CGI response into a response for the client [3.3: script uri](https://www.rfc-editor.org/rfc/rfc3875#section-3.3) + - the 'Script-URI' [...] MUST have the property that if the client had accessed this URI instead, then the script would have been executed [4: how the server prepare the cgi requests](https://www.rfc-editor.org/rfc/rfc3875#section-4) + - the cgi receives 2 differents set of informations : - the request meta-variables (in UNIX, by env variables) - and the message-body [4.1: request meta-variables](https://www.rfc-editor.org/rfc/rfc3875#section-4.1) + - a header field that spans multiple lines MUST be merged onto a single line [4.2: request message-body](https://www.rfc-editor.org/rfc/rfc3875#section-4.2) + - unless defined otherwise, the script access request data by reading stdin [6: how the response from the script is returned to the server](https://www.rfc-editor.org/rfc/rfc3875#section-6) + - The response comprises 2 parts, separated by a blank line : - a message-header - and a message-body @@ -105,6 +111,7 @@ - The body may be NULL [6.2: responses types](https://www.rfc-editor.org/rfc/rfc3875#section-6.2) + - four types of responses : - document response - local redirect response @@ -128,6 +135,7 @@ - the server must check the cgi-script output, and modifie it to comply with the protocol version [6.3: cgi header fields](https://www.rfc-editor.org/rfc/rfc3875#section-6.3) + - whitespace is permitted between the ":" and the field-value - but not between the field-name and the ":" - the CGI script can set three differents fields : @@ -158,11 +166,13 @@ - the server must resolve conflicts between script-header fields and themselves [6.3: cgi message body](https://www.rfc-editor.org/rfc/rfc3875#section-6.4) + - the server must read it untill EOF - the server must not modify it, except to convert charset if needed [7 and 8: usefull informations about implementation and security](https://www.rfc-editor.org/rfc/rfc3875#section-7) +#### questions : - le cgi-script doit renvoyer au moins un header suivit d'une ligne vide - il peut dans certains cas envoyer d'autres headers - le serveur doit verifier qu'il n'y a pas de doublons dans les headers From 6c0dd771c3ee920d2978490667c926abe95891ce Mon Sep 17 00:00:00 2001 From: hugogogo Date: Tue, 2 Aug 2022 23:49:25 +0200 Subject: [PATCH 05/21] syntax layout --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c7d2c5b..bbbe8e5 100644 --- a/README.md +++ b/README.md @@ -188,7 +188,7 @@ [cgi env variables](https://www.rfc-editor.org/rfc/rfc3875#section-4.1) [wikipedia variables environnements cgi](https://fr.wikipedia.org/wiki/Variables_d%27environnement_CGI) [cgi server variables on adobe](https://helpx.adobe.com/coldfusion/cfml-reference/reserved-words-and-variables/cgi-environment-cgi-scope-variables/cgi-server-variables.html) -``` +```Markdown AUTH_TYPE : if the srcipt is protected, the authentification method used to validate the user CONTENT_LENGTH : length of the request body-message CONTENT_TYPE : (Content-Type field) if there is attached information, as with method POST or PUT, this is the content type of the data (e.g. "text/plain", it is set by the attribute "enctype" in html as three values : "application/x-www-form-urlencoded", "multipart/form-data", "text/plain") From 21283e2493d8f06758c0a7ccdaf7fbf3f13d4a9f Mon Sep 17 00:00:00 2001 From: hugogogo Date: Tue, 2 Aug 2022 23:50:14 +0200 Subject: [PATCH 06/21] syntax layout --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bbbe8e5..c347a2c 100644 --- a/README.md +++ b/README.md @@ -188,7 +188,7 @@ [cgi env variables](https://www.rfc-editor.org/rfc/rfc3875#section-4.1) [wikipedia variables environnements cgi](https://fr.wikipedia.org/wiki/Variables_d%27environnement_CGI) [cgi server variables on adobe](https://helpx.adobe.com/coldfusion/cfml-reference/reserved-words-and-variables/cgi-environment-cgi-scope-variables/cgi-server-variables.html) -```Markdown +```None AUTH_TYPE : if the srcipt is protected, the authentification method used to validate the user CONTENT_LENGTH : length of the request body-message CONTENT_TYPE : (Content-Type field) if there is attached information, as with method POST or PUT, this is the content type of the data (e.g. "text/plain", it is set by the attribute "enctype" in html as three values : "application/x-www-form-urlencoded", "multipart/form-data", "text/plain") From 6791b13a52c93f69a2bd8b8a6c7970ea7c5a442b Mon Sep 17 00:00:00 2001 From: hugogogo Date: Tue, 2 Aug 2022 23:58:09 +0200 Subject: [PATCH 07/21] syntax layout --- README.md | 128 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) diff --git a/README.md b/README.md index c347a2c..24003df 100644 --- a/README.md +++ b/README.md @@ -188,7 +188,135 @@ [cgi env variables](https://www.rfc-editor.org/rfc/rfc3875#section-4.1) [wikipedia variables environnements cgi](https://fr.wikipedia.org/wiki/Variables_d%27environnement_CGI) [cgi server variables on adobe](https://helpx.adobe.com/coldfusion/cfml-reference/reserved-words-and-variables/cgi-environment-cgi-scope-variables/cgi-server-variables.html) + +```Shell +Shell +AUTH_TYPE : if the srcipt is protected, the authentification method used to validate the user +CONTENT_LENGTH : length of the request body-message +CONTENT_TYPE : (Content-Type field) if there is attached information, as with method POST or PUT, this is the content type of the data (e.g. "text/plain", it is set by the attribute "enctype" in html as three values : "application/x-www-form-urlencoded", "multipart/form-data", "text/plain") +GATEWAY_INTERFACE : CGI version (e.g. CGI/1.1) +PATH_INFO : if any, path of the resquest in addition to the cgi script path (e.g. for cgi script path = "/usr/web/cgi-bin/script.cgi", and the url = "http://server.org/cgi-bin/script.cgi/house", the PATH-INFO would be "house") +PATH_TRANSLATED : full path of the request, like path-to-cgi/PATH_INFO, null if PATH_INFO is null (e.g. for "http://server.org/cgi-bin/prog/the/path", PATH_INFO would be : "/the/path" and PATH_TRANSLATED would be : "/usr/web/cgi-bin/prog/the/path") +QUERY_STRING : everything following the ? in the url sent by client (e.g. for url "http://server.org/query?var1=val2&var2=val2", it would be : "var1=val2&var2=val2") +REMOTE_ADDR : ip address of the client +REMOTE_HOST : host name of the client, empty if not known, or equal to REMOTE_ADDR +REMOTE_IDENT : if known, username of the client, otherwise empty, use for logging only +REMOTE_USER : username of client, if script is protected and the server support user authentification +REQUEST_METHOD : method used for the request (for http, usually POST or GET) +SCRIPT_NAME : path to the cgi, relative to the root, used for self-referencing URLs (e.g. "/cgi-bin/script.cgi") +SERVER_NAME : name of the server, as hostname, IP address, or DNS (e.g. dns : "www.server.org") +SERVER_PORT : the port number your server is listening on (e.g. 80) +SERVER_PROTOCOL : protocol used for the request (e.g. HTTP/1.1) +SERVER_SOFTWARE : the server software you're using (e.g. Apache 1.3) +``` + ```None +None +AUTH_TYPE : if the srcipt is protected, the authentification method used to validate the user +CONTENT_LENGTH : length of the request body-message +CONTENT_TYPE : (Content-Type field) if there is attached information, as with method POST or PUT, this is the content type of the data (e.g. "text/plain", it is set by the attribute "enctype" in html as three values : "application/x-www-form-urlencoded", "multipart/form-data", "text/plain") +GATEWAY_INTERFACE : CGI version (e.g. CGI/1.1) +PATH_INFO : if any, path of the resquest in addition to the cgi script path (e.g. for cgi script path = "/usr/web/cgi-bin/script.cgi", and the url = "http://server.org/cgi-bin/script.cgi/house", the PATH-INFO would be "house") +PATH_TRANSLATED : full path of the request, like path-to-cgi/PATH_INFO, null if PATH_INFO is null (e.g. for "http://server.org/cgi-bin/prog/the/path", PATH_INFO would be : "/the/path" and PATH_TRANSLATED would be : "/usr/web/cgi-bin/prog/the/path") +QUERY_STRING : everything following the ? in the url sent by client (e.g. for url "http://server.org/query?var1=val2&var2=val2", it would be : "var1=val2&var2=val2") +REMOTE_ADDR : ip address of the client +REMOTE_HOST : host name of the client, empty if not known, or equal to REMOTE_ADDR +REMOTE_IDENT : if known, username of the client, otherwise empty, use for logging only +REMOTE_USER : username of client, if script is protected and the server support user authentification +REQUEST_METHOD : method used for the request (for http, usually POST or GET) +SCRIPT_NAME : path to the cgi, relative to the root, used for self-referencing URLs (e.g. "/cgi-bin/script.cgi") +SERVER_NAME : name of the server, as hostname, IP address, or DNS (e.g. dns : "www.server.org") +SERVER_PORT : the port number your server is listening on (e.g. 80) +SERVER_PROTOCOL : protocol used for the request (e.g. HTTP/1.1) +SERVER_SOFTWARE : the server software you're using (e.g. Apache 1.3) +``` + +```Texte +Texte +AUTH_TYPE : if the srcipt is protected, the authentification method used to validate the user +CONTENT_LENGTH : length of the request body-message +CONTENT_TYPE : (Content-Type field) if there is attached information, as with method POST or PUT, this is the content type of the data (e.g. "text/plain", it is set by the attribute "enctype" in html as three values : "application/x-www-form-urlencoded", "multipart/form-data", "text/plain") +GATEWAY_INTERFACE : CGI version (e.g. CGI/1.1) +PATH_INFO : if any, path of the resquest in addition to the cgi script path (e.g. for cgi script path = "/usr/web/cgi-bin/script.cgi", and the url = "http://server.org/cgi-bin/script.cgi/house", the PATH-INFO would be "house") +PATH_TRANSLATED : full path of the request, like path-to-cgi/PATH_INFO, null if PATH_INFO is null (e.g. for "http://server.org/cgi-bin/prog/the/path", PATH_INFO would be : "/the/path" and PATH_TRANSLATED would be : "/usr/web/cgi-bin/prog/the/path") +QUERY_STRING : everything following the ? in the url sent by client (e.g. for url "http://server.org/query?var1=val2&var2=val2", it would be : "var1=val2&var2=val2") +REMOTE_ADDR : ip address of the client +REMOTE_HOST : host name of the client, empty if not known, or equal to REMOTE_ADDR +REMOTE_IDENT : if known, username of the client, otherwise empty, use for logging only +REMOTE_USER : username of client, if script is protected and the server support user authentification +REQUEST_METHOD : method used for the request (for http, usually POST or GET) +SCRIPT_NAME : path to the cgi, relative to the root, used for self-referencing URLs (e.g. "/cgi-bin/script.cgi") +SERVER_NAME : name of the server, as hostname, IP address, or DNS (e.g. dns : "www.server.org") +SERVER_PORT : the port number your server is listening on (e.g. 80) +SERVER_PROTOCOL : protocol used for the request (e.g. HTTP/1.1) +SERVER_SOFTWARE : the server software you're using (e.g. Apache 1.3) +``` + +```Text +Text +AUTH_TYPE : if the srcipt is protected, the authentification method used to validate the user +CONTENT_LENGTH : length of the request body-message +CONTENT_TYPE : (Content-Type field) if there is attached information, as with method POST or PUT, this is the content type of the data (e.g. "text/plain", it is set by the attribute "enctype" in html as three values : "application/x-www-form-urlencoded", "multipart/form-data", "text/plain") +GATEWAY_INTERFACE : CGI version (e.g. CGI/1.1) +PATH_INFO : if any, path of the resquest in addition to the cgi script path (e.g. for cgi script path = "/usr/web/cgi-bin/script.cgi", and the url = "http://server.org/cgi-bin/script.cgi/house", the PATH-INFO would be "house") +PATH_TRANSLATED : full path of the request, like path-to-cgi/PATH_INFO, null if PATH_INFO is null (e.g. for "http://server.org/cgi-bin/prog/the/path", PATH_INFO would be : "/the/path" and PATH_TRANSLATED would be : "/usr/web/cgi-bin/prog/the/path") +QUERY_STRING : everything following the ? in the url sent by client (e.g. for url "http://server.org/query?var1=val2&var2=val2", it would be : "var1=val2&var2=val2") +REMOTE_ADDR : ip address of the client +REMOTE_HOST : host name of the client, empty if not known, or equal to REMOTE_ADDR +REMOTE_IDENT : if known, username of the client, otherwise empty, use for logging only +REMOTE_USER : username of client, if script is protected and the server support user authentification +REQUEST_METHOD : method used for the request (for http, usually POST or GET) +SCRIPT_NAME : path to the cgi, relative to the root, used for self-referencing URLs (e.g. "/cgi-bin/script.cgi") +SERVER_NAME : name of the server, as hostname, IP address, or DNS (e.g. dns : "www.server.org") +SERVER_PORT : the port number your server is listening on (e.g. 80) +SERVER_PROTOCOL : protocol used for the request (e.g. HTTP/1.1) +SERVER_SOFTWARE : the server software you're using (e.g. Apache 1.3) +``` + +```Asterisk dialplan +Asterisk dialplan +AUTH_TYPE : if the srcipt is protected, the authentification method used to validate the user +CONTENT_LENGTH : length of the request body-message +CONTENT_TYPE : (Content-Type field) if there is attached information, as with method POST or PUT, this is the content type of the data (e.g. "text/plain", it is set by the attribute "enctype" in html as three values : "application/x-www-form-urlencoded", "multipart/form-data", "text/plain") +GATEWAY_INTERFACE : CGI version (e.g. CGI/1.1) +PATH_INFO : if any, path of the resquest in addition to the cgi script path (e.g. for cgi script path = "/usr/web/cgi-bin/script.cgi", and the url = "http://server.org/cgi-bin/script.cgi/house", the PATH-INFO would be "house") +PATH_TRANSLATED : full path of the request, like path-to-cgi/PATH_INFO, null if PATH_INFO is null (e.g. for "http://server.org/cgi-bin/prog/the/path", PATH_INFO would be : "/the/path" and PATH_TRANSLATED would be : "/usr/web/cgi-bin/prog/the/path") +QUERY_STRING : everything following the ? in the url sent by client (e.g. for url "http://server.org/query?var1=val2&var2=val2", it would be : "var1=val2&var2=val2") +REMOTE_ADDR : ip address of the client +REMOTE_HOST : host name of the client, empty if not known, or equal to REMOTE_ADDR +REMOTE_IDENT : if known, username of the client, otherwise empty, use for logging only +REMOTE_USER : username of client, if script is protected and the server support user authentification +REQUEST_METHOD : method used for the request (for http, usually POST or GET) +SCRIPT_NAME : path to the cgi, relative to the root, used for self-referencing URLs (e.g. "/cgi-bin/script.cgi") +SERVER_NAME : name of the server, as hostname, IP address, or DNS (e.g. dns : "www.server.org") +SERVER_PORT : the port number your server is listening on (e.g. 80) +SERVER_PROTOCOL : protocol used for the request (e.g. HTTP/1.1) +SERVER_SOFTWARE : the server software you're using (e.g. Apache 1.3) +``` + +```Asterisk +Asterisk +AUTH_TYPE : if the srcipt is protected, the authentification method used to validate the user +CONTENT_LENGTH : length of the request body-message +CONTENT_TYPE : (Content-Type field) if there is attached information, as with method POST or PUT, this is the content type of the data (e.g. "text/plain", it is set by the attribute "enctype" in html as three values : "application/x-www-form-urlencoded", "multipart/form-data", "text/plain") +GATEWAY_INTERFACE : CGI version (e.g. CGI/1.1) +PATH_INFO : if any, path of the resquest in addition to the cgi script path (e.g. for cgi script path = "/usr/web/cgi-bin/script.cgi", and the url = "http://server.org/cgi-bin/script.cgi/house", the PATH-INFO would be "house") +PATH_TRANSLATED : full path of the request, like path-to-cgi/PATH_INFO, null if PATH_INFO is null (e.g. for "http://server.org/cgi-bin/prog/the/path", PATH_INFO would be : "/the/path" and PATH_TRANSLATED would be : "/usr/web/cgi-bin/prog/the/path") +QUERY_STRING : everything following the ? in the url sent by client (e.g. for url "http://server.org/query?var1=val2&var2=val2", it would be : "var1=val2&var2=val2") +REMOTE_ADDR : ip address of the client +REMOTE_HOST : host name of the client, empty if not known, or equal to REMOTE_ADDR +REMOTE_IDENT : if known, username of the client, otherwise empty, use for logging only +REMOTE_USER : username of client, if script is protected and the server support user authentification +REQUEST_METHOD : method used for the request (for http, usually POST or GET) +SCRIPT_NAME : path to the cgi, relative to the root, used for self-referencing URLs (e.g. "/cgi-bin/script.cgi") +SERVER_NAME : name of the server, as hostname, IP address, or DNS (e.g. dns : "www.server.org") +SERVER_PORT : the port number your server is listening on (e.g. 80) +SERVER_PROTOCOL : protocol used for the request (e.g. HTTP/1.1) +SERVER_SOFTWARE : the server software you're using (e.g. Apache 1.3) +``` + +```Brainfuck +Brainfuck AUTH_TYPE : if the srcipt is protected, the authentification method used to validate the user CONTENT_LENGTH : length of the request body-message CONTENT_TYPE : (Content-Type field) if there is attached information, as with method POST or PUT, this is the content type of the data (e.g. "text/plain", it is set by the attribute "enctype" in html as three values : "application/x-www-form-urlencoded", "multipart/form-data", "text/plain") From 83536ee8add92b2366035771816e4cc088bc084d Mon Sep 17 00:00:00 2001 From: hugogogo Date: Wed, 3 Aug 2022 00:00:54 +0200 Subject: [PATCH 08/21] syntax layout --- README.md | 129 +----------------------------------------------------- 1 file changed, 1 insertion(+), 128 deletions(-) diff --git a/README.md b/README.md index 24003df..24f0821 100644 --- a/README.md +++ b/README.md @@ -189,134 +189,7 @@ [wikipedia variables environnements cgi](https://fr.wikipedia.org/wiki/Variables_d%27environnement_CGI) [cgi server variables on adobe](https://helpx.adobe.com/coldfusion/cfml-reference/reserved-words-and-variables/cgi-environment-cgi-scope-variables/cgi-server-variables.html) -```Shell -Shell -AUTH_TYPE : if the srcipt is protected, the authentification method used to validate the user -CONTENT_LENGTH : length of the request body-message -CONTENT_TYPE : (Content-Type field) if there is attached information, as with method POST or PUT, this is the content type of the data (e.g. "text/plain", it is set by the attribute "enctype" in html as three values : "application/x-www-form-urlencoded", "multipart/form-data", "text/plain") -GATEWAY_INTERFACE : CGI version (e.g. CGI/1.1) -PATH_INFO : if any, path of the resquest in addition to the cgi script path (e.g. for cgi script path = "/usr/web/cgi-bin/script.cgi", and the url = "http://server.org/cgi-bin/script.cgi/house", the PATH-INFO would be "house") -PATH_TRANSLATED : full path of the request, like path-to-cgi/PATH_INFO, null if PATH_INFO is null (e.g. for "http://server.org/cgi-bin/prog/the/path", PATH_INFO would be : "/the/path" and PATH_TRANSLATED would be : "/usr/web/cgi-bin/prog/the/path") -QUERY_STRING : everything following the ? in the url sent by client (e.g. for url "http://server.org/query?var1=val2&var2=val2", it would be : "var1=val2&var2=val2") -REMOTE_ADDR : ip address of the client -REMOTE_HOST : host name of the client, empty if not known, or equal to REMOTE_ADDR -REMOTE_IDENT : if known, username of the client, otherwise empty, use for logging only -REMOTE_USER : username of client, if script is protected and the server support user authentification -REQUEST_METHOD : method used for the request (for http, usually POST or GET) -SCRIPT_NAME : path to the cgi, relative to the root, used for self-referencing URLs (e.g. "/cgi-bin/script.cgi") -SERVER_NAME : name of the server, as hostname, IP address, or DNS (e.g. dns : "www.server.org") -SERVER_PORT : the port number your server is listening on (e.g. 80) -SERVER_PROTOCOL : protocol used for the request (e.g. HTTP/1.1) -SERVER_SOFTWARE : the server software you're using (e.g. Apache 1.3) -``` - ```None -None -AUTH_TYPE : if the srcipt is protected, the authentification method used to validate the user -CONTENT_LENGTH : length of the request body-message -CONTENT_TYPE : (Content-Type field) if there is attached information, as with method POST or PUT, this is the content type of the data (e.g. "text/plain", it is set by the attribute "enctype" in html as three values : "application/x-www-form-urlencoded", "multipart/form-data", "text/plain") -GATEWAY_INTERFACE : CGI version (e.g. CGI/1.1) -PATH_INFO : if any, path of the resquest in addition to the cgi script path (e.g. for cgi script path = "/usr/web/cgi-bin/script.cgi", and the url = "http://server.org/cgi-bin/script.cgi/house", the PATH-INFO would be "house") -PATH_TRANSLATED : full path of the request, like path-to-cgi/PATH_INFO, null if PATH_INFO is null (e.g. for "http://server.org/cgi-bin/prog/the/path", PATH_INFO would be : "/the/path" and PATH_TRANSLATED would be : "/usr/web/cgi-bin/prog/the/path") -QUERY_STRING : everything following the ? in the url sent by client (e.g. for url "http://server.org/query?var1=val2&var2=val2", it would be : "var1=val2&var2=val2") -REMOTE_ADDR : ip address of the client -REMOTE_HOST : host name of the client, empty if not known, or equal to REMOTE_ADDR -REMOTE_IDENT : if known, username of the client, otherwise empty, use for logging only -REMOTE_USER : username of client, if script is protected and the server support user authentification -REQUEST_METHOD : method used for the request (for http, usually POST or GET) -SCRIPT_NAME : path to the cgi, relative to the root, used for self-referencing URLs (e.g. "/cgi-bin/script.cgi") -SERVER_NAME : name of the server, as hostname, IP address, or DNS (e.g. dns : "www.server.org") -SERVER_PORT : the port number your server is listening on (e.g. 80) -SERVER_PROTOCOL : protocol used for the request (e.g. HTTP/1.1) -SERVER_SOFTWARE : the server software you're using (e.g. Apache 1.3) -``` - -```Texte -Texte -AUTH_TYPE : if the srcipt is protected, the authentification method used to validate the user -CONTENT_LENGTH : length of the request body-message -CONTENT_TYPE : (Content-Type field) if there is attached information, as with method POST or PUT, this is the content type of the data (e.g. "text/plain", it is set by the attribute "enctype" in html as three values : "application/x-www-form-urlencoded", "multipart/form-data", "text/plain") -GATEWAY_INTERFACE : CGI version (e.g. CGI/1.1) -PATH_INFO : if any, path of the resquest in addition to the cgi script path (e.g. for cgi script path = "/usr/web/cgi-bin/script.cgi", and the url = "http://server.org/cgi-bin/script.cgi/house", the PATH-INFO would be "house") -PATH_TRANSLATED : full path of the request, like path-to-cgi/PATH_INFO, null if PATH_INFO is null (e.g. for "http://server.org/cgi-bin/prog/the/path", PATH_INFO would be : "/the/path" and PATH_TRANSLATED would be : "/usr/web/cgi-bin/prog/the/path") -QUERY_STRING : everything following the ? in the url sent by client (e.g. for url "http://server.org/query?var1=val2&var2=val2", it would be : "var1=val2&var2=val2") -REMOTE_ADDR : ip address of the client -REMOTE_HOST : host name of the client, empty if not known, or equal to REMOTE_ADDR -REMOTE_IDENT : if known, username of the client, otherwise empty, use for logging only -REMOTE_USER : username of client, if script is protected and the server support user authentification -REQUEST_METHOD : method used for the request (for http, usually POST or GET) -SCRIPT_NAME : path to the cgi, relative to the root, used for self-referencing URLs (e.g. "/cgi-bin/script.cgi") -SERVER_NAME : name of the server, as hostname, IP address, or DNS (e.g. dns : "www.server.org") -SERVER_PORT : the port number your server is listening on (e.g. 80) -SERVER_PROTOCOL : protocol used for the request (e.g. HTTP/1.1) -SERVER_SOFTWARE : the server software you're using (e.g. Apache 1.3) -``` - -```Text -Text -AUTH_TYPE : if the srcipt is protected, the authentification method used to validate the user -CONTENT_LENGTH : length of the request body-message -CONTENT_TYPE : (Content-Type field) if there is attached information, as with method POST or PUT, this is the content type of the data (e.g. "text/plain", it is set by the attribute "enctype" in html as three values : "application/x-www-form-urlencoded", "multipart/form-data", "text/plain") -GATEWAY_INTERFACE : CGI version (e.g. CGI/1.1) -PATH_INFO : if any, path of the resquest in addition to the cgi script path (e.g. for cgi script path = "/usr/web/cgi-bin/script.cgi", and the url = "http://server.org/cgi-bin/script.cgi/house", the PATH-INFO would be "house") -PATH_TRANSLATED : full path of the request, like path-to-cgi/PATH_INFO, null if PATH_INFO is null (e.g. for "http://server.org/cgi-bin/prog/the/path", PATH_INFO would be : "/the/path" and PATH_TRANSLATED would be : "/usr/web/cgi-bin/prog/the/path") -QUERY_STRING : everything following the ? in the url sent by client (e.g. for url "http://server.org/query?var1=val2&var2=val2", it would be : "var1=val2&var2=val2") -REMOTE_ADDR : ip address of the client -REMOTE_HOST : host name of the client, empty if not known, or equal to REMOTE_ADDR -REMOTE_IDENT : if known, username of the client, otherwise empty, use for logging only -REMOTE_USER : username of client, if script is protected and the server support user authentification -REQUEST_METHOD : method used for the request (for http, usually POST or GET) -SCRIPT_NAME : path to the cgi, relative to the root, used for self-referencing URLs (e.g. "/cgi-bin/script.cgi") -SERVER_NAME : name of the server, as hostname, IP address, or DNS (e.g. dns : "www.server.org") -SERVER_PORT : the port number your server is listening on (e.g. 80) -SERVER_PROTOCOL : protocol used for the request (e.g. HTTP/1.1) -SERVER_SOFTWARE : the server software you're using (e.g. Apache 1.3) -``` - -```Asterisk dialplan -Asterisk dialplan -AUTH_TYPE : if the srcipt is protected, the authentification method used to validate the user -CONTENT_LENGTH : length of the request body-message -CONTENT_TYPE : (Content-Type field) if there is attached information, as with method POST or PUT, this is the content type of the data (e.g. "text/plain", it is set by the attribute "enctype" in html as three values : "application/x-www-form-urlencoded", "multipart/form-data", "text/plain") -GATEWAY_INTERFACE : CGI version (e.g. CGI/1.1) -PATH_INFO : if any, path of the resquest in addition to the cgi script path (e.g. for cgi script path = "/usr/web/cgi-bin/script.cgi", and the url = "http://server.org/cgi-bin/script.cgi/house", the PATH-INFO would be "house") -PATH_TRANSLATED : full path of the request, like path-to-cgi/PATH_INFO, null if PATH_INFO is null (e.g. for "http://server.org/cgi-bin/prog/the/path", PATH_INFO would be : "/the/path" and PATH_TRANSLATED would be : "/usr/web/cgi-bin/prog/the/path") -QUERY_STRING : everything following the ? in the url sent by client (e.g. for url "http://server.org/query?var1=val2&var2=val2", it would be : "var1=val2&var2=val2") -REMOTE_ADDR : ip address of the client -REMOTE_HOST : host name of the client, empty if not known, or equal to REMOTE_ADDR -REMOTE_IDENT : if known, username of the client, otherwise empty, use for logging only -REMOTE_USER : username of client, if script is protected and the server support user authentification -REQUEST_METHOD : method used for the request (for http, usually POST or GET) -SCRIPT_NAME : path to the cgi, relative to the root, used for self-referencing URLs (e.g. "/cgi-bin/script.cgi") -SERVER_NAME : name of the server, as hostname, IP address, or DNS (e.g. dns : "www.server.org") -SERVER_PORT : the port number your server is listening on (e.g. 80) -SERVER_PROTOCOL : protocol used for the request (e.g. HTTP/1.1) -SERVER_SOFTWARE : the server software you're using (e.g. Apache 1.3) -``` - -```Asterisk -Asterisk -AUTH_TYPE : if the srcipt is protected, the authentification method used to validate the user -CONTENT_LENGTH : length of the request body-message -CONTENT_TYPE : (Content-Type field) if there is attached information, as with method POST or PUT, this is the content type of the data (e.g. "text/plain", it is set by the attribute "enctype" in html as three values : "application/x-www-form-urlencoded", "multipart/form-data", "text/plain") -GATEWAY_INTERFACE : CGI version (e.g. CGI/1.1) -PATH_INFO : if any, path of the resquest in addition to the cgi script path (e.g. for cgi script path = "/usr/web/cgi-bin/script.cgi", and the url = "http://server.org/cgi-bin/script.cgi/house", the PATH-INFO would be "house") -PATH_TRANSLATED : full path of the request, like path-to-cgi/PATH_INFO, null if PATH_INFO is null (e.g. for "http://server.org/cgi-bin/prog/the/path", PATH_INFO would be : "/the/path" and PATH_TRANSLATED would be : "/usr/web/cgi-bin/prog/the/path") -QUERY_STRING : everything following the ? in the url sent by client (e.g. for url "http://server.org/query?var1=val2&var2=val2", it would be : "var1=val2&var2=val2") -REMOTE_ADDR : ip address of the client -REMOTE_HOST : host name of the client, empty if not known, or equal to REMOTE_ADDR -REMOTE_IDENT : if known, username of the client, otherwise empty, use for logging only -REMOTE_USER : username of client, if script is protected and the server support user authentification -REQUEST_METHOD : method used for the request (for http, usually POST or GET) -SCRIPT_NAME : path to the cgi, relative to the root, used for self-referencing URLs (e.g. "/cgi-bin/script.cgi") -SERVER_NAME : name of the server, as hostname, IP address, or DNS (e.g. dns : "www.server.org") -SERVER_PORT : the port number your server is listening on (e.g. 80) -SERVER_PROTOCOL : protocol used for the request (e.g. HTTP/1.1) -SERVER_SOFTWARE : the server software you're using (e.g. Apache 1.3) -``` - -```Brainfuck -Brainfuck AUTH_TYPE : if the srcipt is protected, the authentification method used to validate the user CONTENT_LENGTH : length of the request body-message CONTENT_TYPE : (Content-Type field) if there is attached information, as with method POST or PUT, this is the content type of the data (e.g. "text/plain", it is set by the attribute "enctype" in html as three values : "application/x-www-form-urlencoded", "multipart/form-data", "text/plain") @@ -336,7 +209,7 @@ SERVER_PROTOCOL : protocol used for the request (e.g. HTTP/1.1) SERVER_SOFTWARE : the server software you're using (e.g. Apache 1.3) ``` [redirect status for php-cgi](https://woozle.org/papers/php-cgi.html) -``` +```None REDIRECT_STATUS : for exemple, 200 ``` From 6f171ec07b211a46f79cad8a6a00abe5c56709f2 Mon Sep 17 00:00:00 2001 From: hugogogo Date: Sat, 6 Aug 2022 11:34:48 +0200 Subject: [PATCH 09/21] wip cgi env variables --- README.md | 5 ++++- srcs/Client.cpp | 35 ++++++++++++++++++++++++++++++----- srcs/Client.hpp | 7 +++++++ srcs/webserv/accept.cpp | 14 ++++++++++++++ srcs/webserv/cgi_script.cpp | 17 +++++++++-------- srcs/webserv/init.cpp | 2 ++ 6 files changed, 66 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 24f0821..238113c 100644 --- a/README.md +++ b/README.md @@ -174,12 +174,15 @@ #### questions : - le cgi-script doit renvoyer au moins un header suivit d'une ligne vide +- ce header est soit "Content-Type", soit "Location", soit "Status" - il peut dans certains cas envoyer d'autres headers - le serveur doit verifier qu'il n'y a pas de doublons dans les headers - le serveur doit verifier le formatage des headers (typiquement l'encodage, par exemple pour les newlines) - ? comment on passe le body-message au script ? section 4.2 + -> en ecrivant le body dans le fd temp sur lequel on a branché stdin et stdout avant d'execve le script - ? on doit gerer l'authentification ? -- ? pourquoi on doit construire un script-cgi ? section 3.3 + -> pas pour l'instant on va dire :p +- ? pourquoi on construit un script-cgi ? section 3.3 - ? si l'uri correspond au script-cgi, ca appel le script donc ? section 3.3 diff --git a/srcs/Client.cpp b/srcs/Client.cpp index e6c6f39..b8e2f47 100644 --- a/srcs/Client.cpp +++ b/srcs/Client.cpp @@ -43,16 +43,20 @@ void Client::parse_request() list.erase(list.begin()); // headers _parse_request_headers(list); - //body- message + // body-message _parse_request_body(pos + 4); + // port and hostname + _parse_port_hostname(_request.headers["Host"]); } -std::string Client::get_method() { return _request.method; } -std::string Client::get_path() { return _request.path; } -std::string Client::get_version() { return _request.version; } -std::string Client::get_body() { return _request.body; } +std::string Client::get_method() { return _request.method; } +std::string Client::get_path() { return _request.path; } +std::string Client::get_version() { return _request.version; } +std::string Client::get_body() { return _request.body; } +std::string Client::get_port() { return _request.port; } +std::string Client::get_hostname() { return _request.hostname; } std::string Client::get_headers(std::string key) { return _request.headers[key]; } /********************************************* @@ -113,4 +117,25 @@ void Client::_parse_request_body( size_t pos ) _request.body = body; } +void Client::_parse_port_hostname(std::string host) +{ + size_t pos; + + if (host == "") + { + std::cerr << "no host\n"; + throw std::runtime_error("no host in request"); + } + + pos = host.find(':'); + // port : + if (pos == std::string::npos) + _request.port = "4040"; // TODO: make equal to default port in config + else + _request.port = host.substr(pos); + if (_request.port == ":") + _request.port = ""; + // hostname : + _request.hostname = host.substr(0, pos); +} diff --git a/srcs/Client.hpp b/srcs/Client.hpp index 002f1c5..2b0d30b 100644 --- a/srcs/Client.hpp +++ b/srcs/Client.hpp @@ -15,6 +15,8 @@ struct Request std::string path; std::string version; std::string body; + std::string port; + std::string hostname; }; class Client @@ -26,6 +28,8 @@ class Client //Client &operator=(Client const &rhs); int fd; + std::string port; + std::string ip; std::string raw_request; std::string response; unsigned int status; @@ -34,6 +38,8 @@ class Client std::string get_path(); std::string get_version(); std::string get_body(); + std::string get_port(); + std::string get_hostname(); std::string get_headers(std::string key); void parse_request(); @@ -44,6 +50,7 @@ class Client void _parse_request_line( std::string rline ); void _parse_request_headers( std::vector list ); void _parse_request_body( size_t pos ); + void _parse_port_hostname(std::string host); }; diff --git a/srcs/webserv/accept.cpp b/srcs/webserv/accept.cpp index f6db17b..38afa83 100644 --- a/srcs/webserv/accept.cpp +++ b/srcs/webserv/accept.cpp @@ -22,5 +22,19 @@ void Webserv::_accept_connection(int fd) _clients.push_back(Client()); _clients.back().fd = accepted_fd; + // HUGO WIP + // + _clients.back().port = ::itos(addr.sin_port); + struct in_addr tmp = { addr.sin_addr.s_addr }; + _clients.back().ip = inet_ntoa( tmp ); + + std::cout + << "port:" << _clients.back().port + << " ip:" << _clients.back().ip + << "\n"; + // + // HUGO END + _epoll_update(accepted_fd, EPOLLIN, EPOLL_CTL_ADD); } + diff --git a/srcs/webserv/cgi_script.cpp b/srcs/webserv/cgi_script.cpp index ee1319e..f925839 100644 --- a/srcs/webserv/cgi_script.cpp +++ b/srcs/webserv/cgi_script.cpp @@ -36,17 +36,18 @@ char** Webserv::_set_env(Client *client) env[4] = _dup_env("PATH_INFO"); env[5] = _dup_env("PATH_TRANSLATED"); env[6] = _dup_env("QUERY_STRING"); - env[7] = _dup_env("REMOTE_ADDR"); + env[7] = _dup_env("REMOTE_ADDR", client->ip); env[8] = _dup_env("REMOTE_HOST", client->get_headers("Host")); // just test - env[9] = _dup_env("REMOTE_IDENT"); - env[10] = _dup_env("REMOTE_USER"); + env[9] = _dup_env("REMOTE_IDENT"); // TODO: implement if authentification + env[10] = _dup_env("REMOTE_USER"); // TODO: implement if authentification env[11] = _dup_env("REQUEST_METHOD", client->get_method()); - env[12] = _dup_env("SCRIPT_NAME"); - env[13] = _dup_env("SERVER_NAME"); - env[14] = _dup_env("SERVER_PORT"); + env[12] = _dup_env("SCRIPT_NAME"); // TODO: define (https://www.rfc-editor.org/rfc/rfc3875#section-4.1.13 + // ,https://www.rfc-editor.org/rfc/rfc3875#section-8.2) + env[13] = _dup_env("SERVER_NAME", client->get_hostname()); + env[14] = _dup_env("SERVER_PORT", client->get_port()); env[15] = _dup_env("SERVER_PROTOCOL", client->get_version()); - env[16] = _dup_env("SERVER_SOFTWARE"); - env[17] = _dup_env("REDIRECT_STATUS"); + env[16] = _dup_env("SERVER_SOFTWARE", "webser/1.0"); + env[17] = _dup_env("REDIRECT_STATUS", "200"); env[18] = NULL; return env; diff --git a/srcs/webserv/init.cpp b/srcs/webserv/init.cpp index 4c5956e..e666da8 100644 --- a/srcs/webserv/init.cpp +++ b/srcs/webserv/init.cpp @@ -24,6 +24,7 @@ void Webserv::init_virtual_servers(std::vector* servers) std::perror("err socket()"); throw std::runtime_error("Socket init"); } + // HUGO ADD // // allow socket descriptor to be reuseable @@ -36,6 +37,7 @@ void Webserv::init_virtual_servers(std::vector* servers) } // // HUGO ADD END + _listen_sockets.push_back(ret); _bind(_listen_sockets.back(), std::atoi(it->port.data()), it->host); From e0fd743b5b587676385ef66cf0a36f5a5dad262c Mon Sep 17 00:00:00 2001 From: hugogogo Date: Sun, 7 Aug 2022 13:06:16 +0200 Subject: [PATCH 10/21] key fields headers in map are in lowercase + getters for this map are case insensitive + change request fiel 'path' for 'uri', 'query', and 'abs_path' --- README.md | 46 ++++++++++++++++++++++++++----------- srcs/Client.cpp | 44 ++++++++++++++++++++++++----------- srcs/Client.hpp | 16 +++++++------ srcs/utils.cpp | 7 ++++++ srcs/utils.hpp | 3 +++ srcs/webserv/cgi_script.cpp | 5 ++-- srcs/webserv/response.cpp | 8 +++---- 7 files changed, 89 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index e5748b5..ac9034c 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,36 @@ -## questions : +## work together +#### questions - in client.cpp i fill the port, is there a default one in case it's not in the request ? -- le cgi-script doit renvoyer au moins un header suivit d'une ligne vide -- ce header est soit "Content-Type", soit "Location", soit "Status" -- il peut dans certains cas envoyer d'autres headers -- le serveur doit verifier qu'il n'y a pas de doublons dans les headers -- le serveur doit verifier le formatage des headers (typiquement l'encodage, par exemple pour les newlines) -- ? comment on passe le body-message au script ? section 4.2 - -> en ecrivant le body dans le fd temp sur lequel on a branché stdin et stdout avant d'execve le script -- ? on doit gerer l'authentification ? - -> pas pour l'instant on va dire :p -- ? pourquoi on construit un script-cgi ? section 3.3 -- ? on doit gerer l'authentification ? -- ? pourquoi on doit construire un script-cgi ? section 3.3 -- ? si l'uri correspond au script-cgi, ca appel le script donc ? section 3.3 +#### notifications +- i changed the Client getters in two categories : + - getters for requests infos : `get_rq_` + - getters for client sides infos : `get_cl_` (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 + +#### share knowledge +##### cgi +- the cgi-script will send back at least one header field followed by an empty line +- this header field will be one of three : + - "Content-Type" + - "Location" + - "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 ":", the server must send back a status 302 with this uri to the client +- 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 + --- ## man @@ -141,10 +157,12 @@ - local redirect response : - it must return only a Location field - it contains a local path URI and query string ('local-pathquery') + - the local path URI must start with a "/" - the server must generate the response for this local-pathquery - client redirect response : - it must return only a Location field - it contains an absolute URI path, to indicate the client that it should reprocess the request with this URI + - the absolute URI always start with the name of scheme followed by ":" - the http server must generate a 302 'Found' message - client redirect response with document - it must return a Location field with an absolute URI path diff --git a/srcs/Client.cpp b/srcs/Client.cpp index b96b924..94dc5ae 100644 --- a/srcs/Client.cpp +++ b/srcs/Client.cpp @@ -74,6 +74,7 @@ void Client::parse_request() std::vector list; size_t pos; +// DEBUG std::cout << "\n" << "request:\n" << raw_request << "START _______________________\n\n" @@ -87,7 +88,7 @@ std::cout << "\n" list.erase(list.begin()); _parse_request_headers(list); _parse_request_body(pos + 4); - _parse_port_hostname(_request.headers["Host"]); + _parse_port_hostname(this->get_rq_headers("Host")); // add "raw_request.clear()" after parsing ? for little less memory usage ? } @@ -103,10 +104,14 @@ void Client::clear() void Client::clear_request() { _request.method = UNKNOWN; - _request.path.clear(); + _request.uri.clear(); _request.version.clear(); _request.headers.clear(); _request.body.clear(); + _request.abs_path.clear(); + _request.query.clear(); + _request.port.clear(); + _request.hostname.clear(); } @@ -115,25 +120,24 @@ void Client::clear_request() *********************************************/ // client side -int Client::get_cl_fd() const { return _fd; } +int Client::get_cl_fd() const { return _fd; } std::string Client::get_cl_ip() const { return _ip; } listen_socket * Client::get_cl_lsocket() const { return _lsocket; } std::string Client::get_cl_port() const { return _port; } + // requette -http_method Client::get_rq_method()const { return _request.method; } +http_method Client::get_rq_method() const { return _request.method; } std::string Client::get_rq_method_str() const -{ - std::string method; - method = ::http_methods_to_str(_request.method); - return method; -} -std::string Client::get_rq_path() const { return _request.path; } + { return ::http_methods_to_str(_request.method); } +std::string Client::get_rq_uri() const { return _request.uri; } +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_headers(const std::string & key) - { return _request.headers[key]; } +std::string Client::get_rq_headers(const std::string & key) const + { return _request.headers.find(::str_tolower(key))->second; } /********************************************* @@ -160,13 +164,26 @@ void Client::_parse_request_line( std::string rline ) // https://stackoverflow.com/questions/40311306/when-is-absoluteuri-used-from-the-http-request-specs tmp = ::trim(sline[1], ' '); tmp = ::trim(tmp, '\r'); - _request.path = tmp; + _request.uri = tmp; + _parse_request_uri( tmp ); // http version tmp = ::trim(sline[2], ' '); tmp = ::trim(tmp, '\r'); _request.version = tmp; } +void Client::_parse_request_uri( std::string uri ) +{ + size_t pos; + + pos = uri.find("?"); + if (pos != std::string::npos) + _request.query = uri.substr(pos + 1); + else + _request.query = ""; + _request.abs_path = uri.substr(0, pos); +} + void Client::_parse_request_headers( std::vector list ) { std::string key; @@ -180,6 +197,7 @@ void Client::_parse_request_headers( std::vector list ) key = (*it).substr( 0, pos ); key = ::trim(key, ' '); key = ::trim(key, '\r'); + key = ::str_tolower(key); val = (*it).substr( pos + 1 ); val = ::trim(val, ' '); val = ::trim(val, '\r'); diff --git a/srcs/Client.hpp b/srcs/Client.hpp index b2c11ae..65340a1 100644 --- a/srcs/Client.hpp +++ b/srcs/Client.hpp @@ -14,7 +14,9 @@ struct Request { http_method method; - std::string path; + std::string uri; + std::string abs_path; + std::string query; std::string version; std::map headers; std::string body; @@ -38,10 +40,6 @@ class Client size_t body_size; unsigned int status; -// std::string port; -// std::string ip; -// listen_socket * lsocket; - // getters int get_cl_fd() const; std::string get_cl_port() const; @@ -51,12 +49,14 @@ class Client // requests getters http_method get_rq_method() const; std::string get_rq_method_str() const; - std::string get_rq_path() const; + std::string get_rq_uri() 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_headers(const std::string & key); + std::string get_rq_headers(const std::string & key) const; void parse_request(); void clear(); @@ -70,6 +70,7 @@ class Client struct Request _request; void _parse_request_line( std::string rline ); + void _parse_request_uri( std::string uri ); void _parse_request_headers( std::vector list ); void _parse_request_body( size_t pos ); void _parse_port_hostname(std::string host); @@ -81,3 +82,4 @@ bool operator==(const Client& lhs, int fd); bool operator==(int fd, const Client& rhs); #endif + diff --git a/srcs/utils.cpp b/srcs/utils.cpp index 2144a51..dbd2833 100644 --- a/srcs/utils.cpp +++ b/srcs/utils.cpp @@ -105,3 +105,10 @@ bool operator==(const listen_socket& lhs, int fd) bool operator==(int fd, const listen_socket& rhs) { return fd == rhs.fd; } + +std::string str_tolower(std::string str) +{ + std::transform(str.begin(), str.end(), str.begin(), ::tolower); + return str; +} + diff --git a/srcs/utils.hpp b/srcs/utils.hpp index 6ea657c..5b271b4 100644 --- a/srcs/utils.hpp +++ b/srcs/utils.hpp @@ -6,6 +6,8 @@ # include # include # include // atoi +# include // tolower +# include // transform # define CR "\r" # define LF "\n" @@ -46,5 +48,6 @@ std::string trim(std::string str, char c); http_method str_to_http_method(std::string &str); std::string http_methods_to_str(unsigned int methods); void replace_all_substr(std::string &str, const std::string &ori_substr, const std::string &new_substr); +std::string str_tolower(std::string str); #endif diff --git a/srcs/webserv/cgi_script.cpp b/srcs/webserv/cgi_script.cpp index b025a28..742a6f4 100644 --- a/srcs/webserv/cgi_script.cpp +++ b/srcs/webserv/cgi_script.cpp @@ -3,7 +3,8 @@ bool Webserv::_is_cgi(Client *client) { - if (client->get_rq_path().find("/cgi-bin/") != std::string::npos) + // TMP + if (client->get_rq_abs_path().find("/cgi-bin") != std::string::npos) return true; return false; } @@ -35,7 +36,7 @@ char** Webserv::_set_env(Client *client) env[3] = _dup_env("GATEWAY_INTERFACE"); env[4] = _dup_env("PATH_INFO"); env[5] = _dup_env("PATH_TRANSLATED"); - env[6] = _dup_env("QUERY_STRING"); + env[6] = _dup_env("QUERY_STRING" , client->get_rq_query()); env[7] = _dup_env("REMOTE_ADDR" , client->get_cl_ip()); env[8] = _dup_env("REMOTE_HOST" , client->get_rq_headers("Host")); // just test env[9] = _dup_env("REMOTE_IDENT"); // authentification not supported diff --git a/srcs/webserv/response.cpp b/srcs/webserv/response.cpp index e5c80a3..151eb59 100644 --- a/srcs/webserv/response.cpp +++ b/srcs/webserv/response.cpp @@ -72,7 +72,7 @@ void Webserv::_construct_response(Client *client, ServerConfig &server) client->status = 413; return; } - LocationConfig &location = _determine_location(server, client->get_rq_path()); + LocationConfig &location = _determine_location(server, client->get_rq_uri()); _process_method(client, server, location); } @@ -135,7 +135,7 @@ void Webserv::_error_html_response(Client *client, ServerConfig &server) void Webserv::_get(Client *client, ServerConfig &server, LocationConfig &location) { (void)server; // To remove from arg if we determine its useless - std::string path = client->get_rq_path(); + std::string path = client->get_rq_uri(); if (path == "/") // TODO : index and autoindex path.append(INDEX); @@ -255,7 +255,7 @@ void Webserv::_post(Client *client, ServerConfig &server, LocationConfig &locati WIP https://www.rfc-editor.org/rfc/rfc9110.html#name-post */ - std::string path = client->get_rq_path(); + std::string path = client->get_rq_uri(); path.insert(0, location.root); /* CGI Here ? */ @@ -321,7 +321,7 @@ void Webserv::_delete(Client *client, ServerConfig &server, LocationConfig &loca WIP https://www.rfc-editor.org/rfc/rfc9110.html#name-delete */ - std::string path = client->get_rq_path(); + std::string path = client->get_rq_uri(); path.insert(0, location.root); /* CGI Here ? */ From 7ecfc22c7b123b6b5f3627ba38d7fe0048c2af7b Mon Sep 17 00:00:00 2001 From: hugogogo Date: Sun, 7 Aug 2022 15:51:36 +0200 Subject: [PATCH 11/21] script path is found and fill --- README.md | 38 +++++++++++++------------ srcs/Client.cpp | 45 +++++++++++++++++++++++++---- srcs/Client.hpp | 11 +++++++ srcs/webserv/Webserv.hpp | 1 + srcs/webserv/cgi_script.cpp | 57 ++++++++++++++++++++++--------------- 5 files changed, 106 insertions(+), 46 deletions(-) diff --git a/README.md b/README.md index ac9034c..6572914 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,9 @@ ## work together #### 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 +- how do we deal with cgi config default folder path or anything ? #### notifications - i changed the Client getters in two categories : @@ -13,24 +16,6 @@ - add `query` (ex. var=val) - the header fields names, as key in map, are stored in lowercase, and getters are case-insensitives -#### share knowledge -##### cgi -- the cgi-script will send back at least one header field followed by an empty line -- this header field will be one of three : - - "Content-Type" - - "Location" - - "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 ":", the server must send back a status 302 with this uri to the client -- 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 - --- ## man @@ -110,6 +95,23 @@ ## cgi rfc [rfc 3875](https://www.rfc-editor.org/rfc/rfc3875) +#### 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 : + - "Content-Type" + - "Location" + - "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 ":", the server must send back a status 302 with this uri to the client +- 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) - The server [...] receives the request from the client diff --git a/srcs/Client.cpp b/srcs/Client.cpp index 94dc5ae..321df1e 100644 --- a/srcs/Client.cpp +++ b/srcs/Client.cpp @@ -77,8 +77,11 @@ void Client::parse_request() // DEBUG std::cout << "\n" << "request:\n" << raw_request - << "START _______________________\n\n" + << "START _______________________\n\n" << raw_request + << "\nSCRIPT PATH _________________\n" + << "\npath:" << _request.script.path + << "\npath_info:" << _request.script.info << "\n END _______________________\n"; pos = (raw_request).find(CRLF CRLF); @@ -92,6 +95,24 @@ std::cout << "\n" // add "raw_request.clear()" after parsing ? for little less memory usage ? } +bool Client::fill_script_path(std::string script) +{ + size_t pos; + int len = script.size(); + std::string path = this->get_rq_abs_path(); + std::string tmp; + + pos = path.find(script); + if (pos != std::string::npos) + { + tmp = path.substr(0, pos + len); + _request.script.path = "./srcs/cgi-bin" + tmp; // TODO: deal with cgi path + _request.script.info = path.substr(pos + len); + return true; + } + return false; +} + void Client::clear() { clear_request(); @@ -103,6 +124,7 @@ void Client::clear() void Client::clear_request() { + clear_script(); _request.method = UNKNOWN; _request.uri.clear(); _request.version.clear(); @@ -114,6 +136,12 @@ void Client::clear_request() _request.hostname.clear(); } +void Client::clear_script() +{ + _request.script.path.clear(); + _request.script.info.clear(); +} + /********************************************* * GETTERS @@ -136,8 +164,17 @@ 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 - { return _request.headers.find(::str_tolower(key))->second; } +{ + std::map::const_iterator it; + + it = _request.headers.find(::str_tolower(key)); + if (it == _request.headers.end()) + return ""; + return it->second; +} /********************************************* @@ -159,9 +196,7 @@ void Client::_parse_request_line( std::string rline ) tmp = ::trim(sline[0], ' '); tmp = ::trim(tmp, '\r'); _request.method = str_to_http_method(tmp); - // TODO uri in request_line - // https://www.rfc-editor.org/rfc/rfc7230#section-5.3 - // https://stackoverflow.com/questions/40311306/when-is-absoluteuri-used-from-the-http-request-specs + // uri tmp = ::trim(sline[1], ' '); tmp = ::trim(tmp, '\r'); _request.uri = tmp; diff --git a/srcs/Client.hpp b/srcs/Client.hpp index 65340a1..9d57934 100644 --- a/srcs/Client.hpp +++ b/srcs/Client.hpp @@ -11,6 +11,12 @@ # include // sockaddr_in, struct in_addr # include // htonl, htons, ntohl, ntohs, inet_addr, inet_ntoa +struct Script +{ + std::string path; + std::string info; +}; + struct Request { http_method method; @@ -22,6 +28,7 @@ struct Request std::string body; std::string port; std::string hostname; + struct Script script; }; # define MAX_FILESIZE 1000000 // (1Mo) @@ -56,11 +63,15 @@ class Client 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(); void clear(); void clear_request(); + void clear_script(); + bool fill_script_path(std::string script); private: int _fd; diff --git a/srcs/webserv/Webserv.hpp b/srcs/webserv/Webserv.hpp index 189bc81..85cd738 100644 --- a/srcs/webserv/Webserv.hpp +++ b/srcs/webserv/Webserv.hpp @@ -99,6 +99,7 @@ class Webserv void _construct_client(Client *client); char** _set_env(Client *client); char* _dup_env(std::string var, std::string val); + char* _dup_env(std::string var, int i); void _exec_script(Client *client, char **env); // epoll_update.cpp int _epoll_update(int fd, uint32_t events, int op); diff --git a/srcs/webserv/cgi_script.cpp b/srcs/webserv/cgi_script.cpp index 742a6f4..55df2d9 100644 --- a/srcs/webserv/cgi_script.cpp +++ b/srcs/webserv/cgi_script.cpp @@ -3,8 +3,10 @@ bool Webserv::_is_cgi(Client *client) { - // TMP - if (client->get_rq_abs_path().find("/cgi-bin") != std::string::npos) + // TODO see how it works with config + if (client->fill_script_path("php-cgi")) + return true; + if (client->fill_script_path("cgi_cpp.cgi")) return true; return false; } @@ -26,29 +28,39 @@ char* Webserv::_dup_env(std::string var, std::string val = "") return ( strdup(str.c_str()) ); } +char* Webserv::_dup_env(std::string var, int i) +{ + std::string str; + std::string val; + + val = ::itos(i); + str = var + "=" + val; + return ( strdup(str.c_str()) ); +} + char** Webserv::_set_env(Client *client) { char** env = new char*[19]; - env[0] = _dup_env("AUTH_TYPE"); - env[1] = _dup_env("CONTENT_LENGTH" , "665"); - env[2] = _dup_env("CONTENT_TYPE"); - env[3] = _dup_env("GATEWAY_INTERFACE"); - env[4] = _dup_env("PATH_INFO"); - env[5] = _dup_env("PATH_TRANSLATED"); - env[6] = _dup_env("QUERY_STRING" , client->get_rq_query()); - env[7] = _dup_env("REMOTE_ADDR" , client->get_cl_ip()); - env[8] = _dup_env("REMOTE_HOST" , client->get_rq_headers("Host")); // just test - env[9] = _dup_env("REMOTE_IDENT"); // authentification not supported - env[10] = _dup_env("REMOTE_USER"); // authentification not supported - env[11] = _dup_env("REQUEST_METHOD" , client->get_rq_method_str()); - env[12] = _dup_env("SCRIPT_NAME"); // TODO: define (https://www.rfc-editor.org/rfc/rfc3875#section-4.1.13 - // ,https://www.rfc-editor.org/rfc/rfc3875#section-8.2) - env[13] = _dup_env("SERVER_NAME" , client->get_rq_hostname()); - env[14] = _dup_env("SERVER_PORT" , client->get_rq_port()); - env[15] = _dup_env("SERVER_PROTOCOL", client->get_rq_version()); - env[16] = _dup_env("SERVER_SOFTWARE", "webser/1.0"); - env[17] = _dup_env("REDIRECT_STATUS", "200"); + env[0] = _dup_env("AUTH_TYPE"); // authentification not supported + env[1] = _dup_env("CONTENT_LENGTH" , client->get_rq_body().size()); + env[2] = _dup_env("CONTENT_TYPE" , client->get_rq_headers("Content-Type")); + env[3] = _dup_env("GATEWAY_INTERFACE" , "CGI/1.0"); + env[4] = _dup_env("PATH_INFO" , client->get_rq_script_info()); + env[5] = _dup_env("PATH_TRANSLATED"); // not supported + env[6] = _dup_env("QUERY_STRING" , client->get_rq_query()); + env[7] = _dup_env("REMOTE_ADDR" , client->get_cl_ip()); + env[8] = _dup_env("REMOTE_HOST" , client->get_rq_headers("Host")); // just test + env[9] = _dup_env("REMOTE_IDENT"); // authentification not supported + env[10] = _dup_env("REMOTE_USER"); // authentification not supported + env[11] = _dup_env("REQUEST_METHOD" , client->get_rq_method_str()); + env[12] = _dup_env("SCRIPT_NAME"); // TODO: define (https://www.rfc-editor.org/rfc/rfc3875#section-4.1.13 + // ,https://www.rfc-editor.org/rfc/rfc3875#section-8.2) + env[13] = _dup_env("SERVER_NAME" , client->get_rq_hostname()); + env[14] = _dup_env("SERVER_PORT" , client->get_rq_port()); + env[15] = _dup_env("SERVER_PROTOCOL" , client->get_rq_version()); + env[16] = _dup_env("SERVER_SOFTWARE" , "webser/1.0"); + env[17] = _dup_env("REDIRECT_STATUS" , "200"); env[18] = NULL; return env; @@ -65,8 +77,7 @@ void Webserv::_exec_script(Client *client, char **env) if (fork() == 0) { dup2(client->get_cl_fd(), STDOUT_FILENO); -// execve("./srcs/cgi-bin/cgi_cpp.cgi", nll, client->env); - execve("./srcs/cgi-bin/php-cgi", nll, env); + execve(client->get_rq_script_path().c_str(), nll, env); } // inside parent process else From 63365a9067e3704c6b136c585a8593c5117ce0a8 Mon Sep 17 00:00:00 2001 From: hugogogo Date: Sun, 7 Aug 2022 22:33:39 +0200 Subject: [PATCH 12/21] cgi_script read and write on a string --- srcs/webserv/cgi_script.cpp | 47 +++++++++++++++++++++++++++++-------- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/srcs/webserv/cgi_script.cpp b/srcs/webserv/cgi_script.cpp index 55df2d9..662094d 100644 --- a/srcs/webserv/cgi_script.cpp +++ b/srcs/webserv/cgi_script.cpp @@ -68,22 +68,49 @@ char** Webserv::_set_env(Client *client) void Webserv::_exec_script(Client *client, char **env) { - int save_stdout; - char * const * nll = NULL; + #define RD 0 + #define WR 1 + #define BUF_SIZE 10 - // save STDOUT - save_stdout = dup(STDOUT_FILENO); - // inside child process + char buf[BUF_SIZE]; + int fd_in[2]; + int fd_out[2]; + char * const * nll = NULL; + std::string response; + std::string body = client->get_rq_body(); + + pipe(fd_in); + pipe(fd_out); if (fork() == 0) - { - dup2(client->get_cl_fd(), STDOUT_FILENO); + { + close(fd_in[WR]); + close(fd_out[RD]); + dup2(fd_in[RD], STDIN_FILENO); + dup2(fd_out[WR], STDOUT_FILENO); execve(client->get_rq_script_path().c_str(), nll, env); + std::cerr << "execve crashed\n"; } - // inside parent process else + { + close(fd_in[RD]); + close(fd_out[WR]); + // write to stdin of child programm + write(fd_in[WR], body.c_str(), body.size()); + close(fd_in[WR]); waitpid(-1, NULL, 0); - // restore stdout - dup2(save_stdout, STDOUT_FILENO); + + // read stdout of child programm + memset(buf, '\0', BUF_SIZE); + while (read(fd_out[RD], buf, BUF_SIZE) > 0) + { + response += buf; + memset(buf, '\0', BUF_SIZE); + } + } + if (response.empty()) + response += "Status: 500\r\n\r\n"; + // TODO: see how this must be handled + client->response += response; } void Webserv::_construct_client(Client *client) From 988e15c7389ac7ed8b657365fa676920f384c82b Mon Sep 17 00:00:00 2001 From: hugogogo Date: Mon, 8 Aug 2022 10:30:20 +0200 Subject: [PATCH 13/21] readme layout --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6572914..740109c 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,9 @@ - getters for requests infos : `get_rq_` - getters for client sides infos : `get_cl_` (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) + - `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 From 78c3ffa4560a0bd496b43dbb7ba3a4667e4645d7 Mon Sep 17 00:00:00 2001 From: hugogogo Date: Mon, 8 Aug 2022 10:31:36 +0200 Subject: [PATCH 14/21] readme layout --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 740109c..6bf5390 100644 --- a/README.md +++ b/README.md @@ -11,9 +11,9 @@ - getters for requests infos : `get_rq_` - getters for client sides infos : `get_cl_` (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) + - `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 From da1f4b6e371aa0f47ccc7b6d604cc721a77a0625 Mon Sep 17 00:00:00 2001 From: hugogogo Date: Mon, 8 Aug 2022 13:20:06 +0200 Subject: [PATCH 15/21] cgi exec compare with file method --- README.md | 16 ++++-- srcs/Client.cpp | 17 +++--- srcs/Client.hpp | 6 +-- srcs/webserv/cgi_script.cpp | 100 +++++++++++++++++++++++++----------- srcs/webserv/response.cpp | 6 +++ 5 files changed, 97 insertions(+), 48 deletions(-) diff --git a/README.md b/README.md index 6bf5390..be6550c 100644 --- a/README.md +++ b/README.md @@ -4,16 +4,24 @@ - 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 -- how do we deal with cgi config default folder path or anything ? +- 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 ? ) #### notifications - i changed the Client getters in two categories : - getters for requests infos : `get_rq_` - getters for client sides infos : `get_cl_` (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`) + - `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 diff --git a/srcs/Client.cpp b/srcs/Client.cpp index 321df1e..010cf2c 100644 --- a/srcs/Client.cpp +++ b/srcs/Client.cpp @@ -43,7 +43,7 @@ Client::Client( Client const & src ) { raw_request = src.raw_request; response = src.response; -// buf = strdup(src.buf); +// buf = strdup(src.buf); // TODO: this doesn't work body_size = src.body_size; status = src.status; return; @@ -75,14 +75,9 @@ void Client::parse_request() size_t pos; // DEBUG -std::cout << "\n" - << "request:\n" << raw_request - << "START _______________________\n\n" +std::cout << "\nREQUEST _____________________\n" << raw_request - << "\nSCRIPT PATH _________________\n" - << "\npath:" << _request.script.path - << "\npath_info:" << _request.script.info - << "\n END _______________________\n"; + << "\n\n"; pos = (raw_request).find(CRLF CRLF); sub = (raw_request).substr(0, pos); @@ -92,7 +87,7 @@ std::cout << "\n" _parse_request_headers(list); _parse_request_body(pos + 4); _parse_port_hostname(this->get_rq_headers("Host")); - // add "raw_request.clear()" after parsing ? for little less memory usage ? + raw_request.clear(); } bool Client::fill_script_path(std::string script) @@ -103,10 +98,10 @@ bool Client::fill_script_path(std::string script) std::string tmp; pos = path.find(script); - if (pos != std::string::npos) + if (pos == 0) { tmp = path.substr(0, pos + len); - _request.script.path = "./srcs/cgi-bin" + tmp; // TODO: deal with cgi path + _request.script.path = "./srcs" + tmp; // TODO: root path ? _request.script.info = path.substr(pos + len); return true; } diff --git a/srcs/Client.hpp b/srcs/Client.hpp index 9d57934..539a29b 100644 --- a/srcs/Client.hpp +++ b/srcs/Client.hpp @@ -74,9 +74,9 @@ class Client bool fill_script_path(std::string script); private: - int _fd; - std::string _port; - std::string _ip; + const int _fd; + const std::string _port; + const std::string _ip; listen_socket * _lsocket; struct Request _request; diff --git a/srcs/webserv/cgi_script.cpp b/srcs/webserv/cgi_script.cpp index 662094d..cc4d836 100644 --- a/srcs/webserv/cgi_script.cpp +++ b/srcs/webserv/cgi_script.cpp @@ -4,9 +4,9 @@ bool Webserv::_is_cgi(Client *client) { // TODO see how it works with config - if (client->fill_script_path("php-cgi")) + if (client->fill_script_path("/cgi-bin/php-cgi")) return true; - if (client->fill_script_path("cgi_cpp.cgi")) + if (client->fill_script_path("/cgi-bin/cgi_cpp.cgi")) return true; return false; } @@ -18,6 +18,10 @@ void Webserv::_exec_cgi(Client *client) env = _set_env(client); _exec_script(client, env); // _construct_response(client); + + for (size_t i = 0; env[i]; i++) + delete[] env[i]; + delete[] env; } char* Webserv::_dup_env(std::string var, std::string val = "") @@ -54,8 +58,7 @@ char** Webserv::_set_env(Client *client) env[9] = _dup_env("REMOTE_IDENT"); // authentification not supported env[10] = _dup_env("REMOTE_USER"); // authentification not supported env[11] = _dup_env("REQUEST_METHOD" , client->get_rq_method_str()); - env[12] = _dup_env("SCRIPT_NAME"); // TODO: define (https://www.rfc-editor.org/rfc/rfc3875#section-4.1.13 - // ,https://www.rfc-editor.org/rfc/rfc3875#section-8.2) + env[12] = _dup_env("SCRIPT_NAME" , client->get_rq_script_path()); env[13] = _dup_env("SERVER_NAME" , client->get_rq_hostname()); env[14] = _dup_env("SERVER_PORT" , client->get_rq_port()); env[15] = _dup_env("SERVER_PROTOCOL" , client->get_rq_version()); @@ -70,45 +73,82 @@ void Webserv::_exec_script(Client *client, char **env) { #define RD 0 #define WR 1 - #define BUF_SIZE 10 + #define CGI_BUF_SIZE 10 - char buf[BUF_SIZE]; - int fd_in[2]; - int fd_out[2]; - char * const * nll = NULL; - std::string response; - std::string body = client->get_rq_body(); +/*1*/ #define FD_WR_TO_CHLD fd_in[WR] +/* */ #define FD_WR_TO_PRNT fd_out[WR] +/* */ #define FD_RD_FR_CHLD fd_out[RD] +/* */ #define FD_RD_FR_PRNT fd_in[RD] +/*2*/// #define FD_WR_TO_CHLD fdIn +/* */// #define FD_WR_TO_PRNT fdOut +/* */// #define FD_RD_FR_CHLD fdOut +/* */// #define FD_RD_FR_PRNT fdIn - pipe(fd_in); - pipe(fd_out); - if (fork() == 0) + pid_t pid; + char buf[CGI_BUF_SIZE]; // WIP define buffer + char * const * nll = NULL; + std::string response; + std::string body = client->get_rq_body(); + +/*1*/ int fd_in[2]; +/* */ int fd_out[2]; +/*2*/// FILE *fIn; +/* */// FILE *fOut; +/* */// long fdIn; +/* */// long fdOut; + +/*1*/ pipe(fd_in); +/* */ pipe(fd_out); +/*2*/// fIn = tmpfile(); +/* */// fOut = tmpfile(); +/* */// fdIn = fileno(fIn); +/* */// fdOut = fileno(fOut); + + pid = fork(); + if (pid == -1) + std::cerr << "fork crashed" << std::endl; + else if (pid == 0) { - close(fd_in[WR]); - close(fd_out[RD]); - dup2(fd_in[RD], STDIN_FILENO); - dup2(fd_out[WR], STDOUT_FILENO); + +/*1*/ close(FD_WR_TO_CHLD); +/* */ close(FD_RD_FR_CHLD); +/*2*/ + + dup2(FD_RD_FR_PRNT, STDIN_FILENO); + dup2(FD_WR_TO_PRNT, STDOUT_FILENO); execve(client->get_rq_script_path().c_str(), nll, env); - std::cerr << "execve crashed\n"; + std::cerr << "execve crashed.\n"; } else { - close(fd_in[RD]); - close(fd_out[WR]); - // write to stdin of child programm - write(fd_in[WR], body.c_str(), body.size()); - close(fd_in[WR]); - waitpid(-1, NULL, 0); +/*1*/ close(FD_RD_FR_PRNT); +/* */ close(FD_WR_TO_PRNT); +/*2*/ - // read stdout of child programm - memset(buf, '\0', BUF_SIZE); - while (read(fd_out[RD], buf, BUF_SIZE) > 0) + write(FD_WR_TO_CHLD, body.c_str(), body.size()); + close(FD_WR_TO_CHLD); + waitpid(-1, NULL, 0); +/*1*/ +/*2*/// lseek(fdOut, 0, SEEK_SET); + + memset(buf, '\0', CGI_BUF_SIZE); + while (read(FD_RD_FR_CHLD, buf, CGI_BUF_SIZE - 1) > 0) { response += buf; - memset(buf, '\0', BUF_SIZE); + memset(buf, '\0', CGI_BUF_SIZE); } } if (response.empty()) - response += "Status: 500\r\n\r\n"; + response = "Status: 500\r\n\r\n"; + +/*1*/ +/*2*/// fclose(fIn); +/* */// fclose(fOut); +/* */// close(fdIn); +/* */// close(fdOut); + +// DEBUG +std::cout << "\n______response________\n" << response << "\n________________________\n"; // TODO: see how this must be handled client->response += response; } diff --git a/srcs/webserv/response.cpp b/srcs/webserv/response.cpp index 151eb59..261b959 100644 --- a/srcs/webserv/response.cpp +++ b/srcs/webserv/response.cpp @@ -147,6 +147,12 @@ void Webserv::_get(Client *client, ServerConfig &server, LocationConfig &locatio // if (_is_cgi(client)) { +// DEBUG +std::cout << "\nSCRIPT PATH _________________" + << "\npath:" << client->get_rq_script_path() + << "\npath_info:" << client->get_rq_script_info() + << "\n\n"; + _exec_cgi(client); return; } From 972f52ebc890003fcb11640e7a03207afe1493f2 Mon Sep 17 00:00:00 2001 From: hugogogo Date: Mon, 8 Aug 2022 15:36:16 +0200 Subject: [PATCH 16/21] client variables are const ref --- Makefile | 2 +- README.md | 28 ++++++++++++++++ srcs/Client.cpp | 8 ++--- srcs/Client.hpp | 18 +++++----- srcs/webserv/Webserv.hpp | 2 +- srcs/webserv/cgi_script.cpp | 65 ++++++++++--------------------------- srcs/webserv/response.cpp | 25 ++++++++++---- 7 files changed, 80 insertions(+), 68 deletions(-) diff --git a/Makefile b/Makefile index 1333a0c..ad045bd 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ NAME = webserv -CXX = clang++ +CXX = c++ CXXFLAGS = -Wall -Wextra #-Werror CXXFLAGS += $(HEADERS_D:%=-I%) diff --git a/README.md b/README.md index be6550c..889abb5 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ ## work together + #### 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 ? @@ -13,6 +14,8 @@ - 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 : @@ -25,6 +28,31 @@ - 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 diff --git a/srcs/Client.cpp b/srcs/Client.cpp index 010cf2c..5224fdf 100644 --- a/srcs/Client.cpp +++ b/srcs/Client.cpp @@ -143,10 +143,10 @@ void Client::clear_script() *********************************************/ // client side -int Client::get_cl_fd() const { return _fd; } -std::string Client::get_cl_ip() const { return _ip; } -listen_socket * Client::get_cl_lsocket() const { return _lsocket; } -std::string Client::get_cl_port() const { return _port; } +int Client::get_cl_fd() const { return _fd; } +const std::string &Client::get_cl_ip() const { return _ip; } +const std::string &Client::get_cl_port() const { return _port; } +const listen_socket *Client::get_cl_lsocket() const { return _lsocket; } // requette http_method Client::get_rq_method() const { return _request.method; } diff --git a/srcs/Client.hpp b/srcs/Client.hpp index 539a29b..b364054 100644 --- a/srcs/Client.hpp +++ b/srcs/Client.hpp @@ -48,10 +48,10 @@ class Client unsigned int status; // getters - int get_cl_fd() const; - std::string get_cl_port() const; - std::string get_cl_ip() const; - listen_socket * get_cl_lsocket() const; + int get_cl_fd() const; + const std::string & get_cl_port() const; + const std::string & get_cl_ip() const; + const listen_socket * get_cl_lsocket() const; // requests getters http_method get_rq_method() const; @@ -74,11 +74,11 @@ class Client bool fill_script_path(std::string script); private: - const int _fd; - const std::string _port; - const std::string _ip; - listen_socket * _lsocket; - struct Request _request; + const int _fd; + const std::string _port; + const std::string _ip; + const listen_socket * _lsocket; + struct Request _request; void _parse_request_line( std::string rline ); void _parse_request_uri( std::string uri ); diff --git a/srcs/webserv/Webserv.hpp b/srcs/webserv/Webserv.hpp index 85cd738..30a644f 100644 --- a/srcs/webserv/Webserv.hpp +++ b/srcs/webserv/Webserv.hpp @@ -93,10 +93,10 @@ class Webserv ServerConfig &_determine_process_server(Client *client); LocationConfig &_determine_location(ServerConfig &server, std::string const &path); + void _response_correction(Client *client); // cgi_script.cpp bool _is_cgi(Client *client); void _exec_cgi(Client *client); - void _construct_client(Client *client); char** _set_env(Client *client); char* _dup_env(std::string var, std::string val); char* _dup_env(std::string var, int i); diff --git a/srcs/webserv/cgi_script.cpp b/srcs/webserv/cgi_script.cpp index cc4d836..b896170 100644 --- a/srcs/webserv/cgi_script.cpp +++ b/srcs/webserv/cgi_script.cpp @@ -17,9 +17,8 @@ void Webserv::_exec_cgi(Client *client) env = _set_env(client); _exec_script(client, env); -// _construct_response(client); - for (size_t i = 0; env[i]; i++) + for (int i = 0; env[i]; i++) delete[] env[i]; delete[] env; } @@ -39,6 +38,7 @@ char* Webserv::_dup_env(std::string var, int i) val = ::itos(i); str = var + "=" + val; + // TODO change strdup for something with new return ( strdup(str.c_str()) ); } @@ -74,46 +74,29 @@ void Webserv::_exec_script(Client *client, char **env) #define RD 0 #define WR 1 #define CGI_BUF_SIZE 10 - -/*1*/ #define FD_WR_TO_CHLD fd_in[WR] -/* */ #define FD_WR_TO_PRNT fd_out[WR] -/* */ #define FD_RD_FR_CHLD fd_out[RD] -/* */ #define FD_RD_FR_PRNT fd_in[RD] -/*2*/// #define FD_WR_TO_CHLD fdIn -/* */// #define FD_WR_TO_PRNT fdOut -/* */// #define FD_RD_FR_CHLD fdOut -/* */// #define FD_RD_FR_PRNT fdIn + #define FD_WR_TO_CHLD fd_in[WR] + #define FD_WR_TO_PRNT fd_out[WR] + #define FD_RD_FR_CHLD fd_out[RD] + #define FD_RD_FR_PRNT fd_in[RD] pid_t pid; char buf[CGI_BUF_SIZE]; // WIP define buffer char * const * nll = NULL; std::string response; std::string body = client->get_rq_body(); + int fd_in[2]; + int fd_out[2]; -/*1*/ int fd_in[2]; -/* */ int fd_out[2]; -/*2*/// FILE *fIn; -/* */// FILE *fOut; -/* */// long fdIn; -/* */// long fdOut; - -/*1*/ pipe(fd_in); -/* */ pipe(fd_out); -/*2*/// fIn = tmpfile(); -/* */// fOut = tmpfile(); -/* */// fdIn = fileno(fIn); -/* */// fdOut = fileno(fOut); + pipe(fd_in); + pipe(fd_out); pid = fork(); if (pid == -1) std::cerr << "fork crashed" << std::endl; else if (pid == 0) { - -/*1*/ close(FD_WR_TO_CHLD); -/* */ close(FD_RD_FR_CHLD); -/*2*/ - + close(FD_WR_TO_CHLD); + close(FD_RD_FR_CHLD); dup2(FD_RD_FR_PRNT, STDIN_FILENO); dup2(FD_WR_TO_PRNT, STDOUT_FILENO); execve(client->get_rq_script_path().c_str(), nll, env); @@ -121,15 +104,11 @@ void Webserv::_exec_script(Client *client, char **env) } else { -/*1*/ close(FD_RD_FR_PRNT); -/* */ close(FD_WR_TO_PRNT); -/*2*/ - + close(FD_RD_FR_PRNT); + close(FD_WR_TO_PRNT); write(FD_WR_TO_CHLD, body.c_str(), body.size()); close(FD_WR_TO_CHLD); waitpid(-1, NULL, 0); -/*1*/ -/*2*/// lseek(fdOut, 0, SEEK_SET); memset(buf, '\0', CGI_BUF_SIZE); while (read(FD_RD_FR_CHLD, buf, CGI_BUF_SIZE - 1) > 0) @@ -141,20 +120,12 @@ void Webserv::_exec_script(Client *client, char **env) if (response.empty()) response = "Status: 500\r\n\r\n"; -/*1*/ -/*2*/// fclose(fIn); -/* */// fclose(fOut); -/* */// close(fdIn); -/* */// close(fdOut); - // DEBUG -std::cout << "\n______response________\n" << response << "\n________________________\n"; +std::cout << "\n_______response_______\n" + << response + << "\n_____end response_____\n"; + // TODO: see how this must be handled client->response += response; } -void Webserv::_construct_client(Client *client) -{ - (void)client; -} - diff --git a/srcs/webserv/response.cpp b/srcs/webserv/response.cpp index 261b959..ed08d6f 100644 --- a/srcs/webserv/response.cpp +++ b/srcs/webserv/response.cpp @@ -147,13 +147,8 @@ void Webserv::_get(Client *client, ServerConfig &server, LocationConfig &locatio // if (_is_cgi(client)) { -// DEBUG -std::cout << "\nSCRIPT PATH _________________" - << "\npath:" << client->get_rq_script_path() - << "\npath_info:" << client->get_rq_script_info() - << "\n\n"; - _exec_cgi(client); + _response_correction(client); return; } // @@ -229,6 +224,24 @@ void Webserv::_get_file(Client *client, const std::string &path) } } +// WIP HUGO +void Webserv::_response_correction(Client *client) +{ + // 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 field duplicate (resolve conflicts) + // TODO : there is no space between filed name and ":" + // TODO : if no Location field && no Status field -> status code = 200 + // TODO?: handle Location field, either : + // - local : start with '/' --> rerun the request with new uri + // - client : start with ':' --> send back status code 302 + + (void)client; +} + void Webserv::_append_body(Client *client, const char *body, size_t body_size, const std::string &file_extension) { /* From f10931042fd694ee886f55a518182a34d7cd4f6d Mon Sep 17 00:00:00 2001 From: hugogogo Date: Mon, 8 Aug 2022 16:16:11 +0200 Subject: [PATCH 17/21] rewrite readme cgi todo list --- README.md | 18 ++++++++++++++++++ srcs/webserv/response.cpp | 12 ------------ 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 889abb5..453b0df 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,24 @@ ## work together +#### 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 field duplicate (resolve conflicts) +-> TODO : if status field, change server status for this one +! TODO : there is no space between filed name and ":" +! TODO : if no Location field && no Status field -> status code = 200 +! TODO?: handle Location field, either : + - local : start with '/' --> rerun the request with new uri + - client : start with ':' --> send back status code 302 + +#### what cgi ? +- a basic form with "name" and "something", that return a html page with that +- a script called by a file extension in URI + #### 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 ? diff --git a/srcs/webserv/response.cpp b/srcs/webserv/response.cpp index ed08d6f..e86761b 100644 --- a/srcs/webserv/response.cpp +++ b/srcs/webserv/response.cpp @@ -227,18 +227,6 @@ void Webserv::_get_file(Client *client, const std::string &path) // WIP HUGO void Webserv::_response_correction(Client *client) { - // 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 field duplicate (resolve conflicts) - // TODO : there is no space between filed name and ":" - // TODO : if no Location field && no Status field -> status code = 200 - // TODO?: handle Location field, either : - // - local : start with '/' --> rerun the request with new uri - // - client : start with ':' --> send back status code 302 - (void)client; } From e1a68bc3e43fdeeecf08030f83fc1d7621d67df4 Mon Sep 17 00:00:00 2001 From: hugogogo Date: Mon, 8 Aug 2022 18:06:41 +0200 Subject: [PATCH 18/21] changes var in client --- README.md | 18 +++++++++++------- big.config | 1 + srcs/Client.cpp | 16 ++++++++-------- srcs/Client.hpp | 8 ++++---- srcs/webserv/Webserv.hpp | 12 ++++++------ srcs/webserv/cgi_script.cpp | 28 ++++++++++++++-------------- 6 files changed, 44 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index 453b0df..7afc363 100644 --- a/README.md +++ b/README.md @@ -1,23 +1,27 @@ ## work together +#### 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 field duplicate (resolve conflicts) --> TODO : if status field, change server status for this one ! TODO : there is no space between filed name and ":" -! TODO : if no Location field && no Status field -> status code = 200 ! TODO?: handle Location field, either : - local : start with '/' --> rerun the request with new uri - client : start with ':' --> send back status code 302 - -#### what cgi ? -- a basic form with "name" and "something", that return a html page with that -- a script called by a file extension in URI +-> 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 ? diff --git a/big.config b/big.config index 5139c18..05d8e85 100644 --- a/big.config +++ b/big.config @@ -16,6 +16,7 @@ server { location /board { allow_methods GET; root ./www/html; + cgi_ext php cgi } location /board/content { diff --git a/srcs/Client.cpp b/srcs/Client.cpp index 5224fdf..354d1c3 100644 --- a/srcs/Client.cpp +++ b/srcs/Client.cpp @@ -36,10 +36,10 @@ Client::~Client() { Client::Client( Client const & src ) : body_size(0) , status(0) - , _fd ( src.get_cl_fd() ) - , _port ( src.get_cl_port() ) - , _ip ( src.get_cl_ip() ) - , _lsocket ( src.get_cl_lsocket() ) + , _fd ( src._fd ) + , _port ( src._port ) + , _ip ( src._ip ) + , _lsocket ( src._lsocket ) { raw_request = src.raw_request; response = src.response; @@ -143,10 +143,10 @@ void Client::clear_script() *********************************************/ // client side -int Client::get_cl_fd() const { return _fd; } -const std::string &Client::get_cl_ip() const { return _ip; } -const std::string &Client::get_cl_port() const { return _port; } -const listen_socket *Client::get_cl_lsocket() const { return _lsocket; } +int Client::get_cl_fd() const { return _fd; } +const std::string & Client::get_cl_ip() const { return _ip; } +const std::string & Client::get_cl_port() const { return _port; } +const listen_socket * Client::get_cl_lsocket() const { return _lsocket; } // requette http_method Client::get_rq_method() const { return _request.method; } diff --git a/srcs/Client.hpp b/srcs/Client.hpp index b364054..64759f0 100644 --- a/srcs/Client.hpp +++ b/srcs/Client.hpp @@ -74,10 +74,10 @@ class Client bool fill_script_path(std::string script); private: - const int _fd; - const std::string _port; - const std::string _ip; - const listen_socket * _lsocket; + int _fd; + std::string _port; + std::string _ip; + listen_socket * _lsocket; struct Request _request; void _parse_request_line( std::string rline ); diff --git a/srcs/webserv/Webserv.hpp b/srcs/webserv/Webserv.hpp index 30a644f..6d128f2 100644 --- a/srcs/webserv/Webserv.hpp +++ b/srcs/webserv/Webserv.hpp @@ -95,12 +95,12 @@ class Webserv LocationConfig &_determine_location(ServerConfig &server, std::string const &path); void _response_correction(Client *client); // cgi_script.cpp - bool _is_cgi(Client *client); - void _exec_cgi(Client *client); - char** _set_env(Client *client); - char* _dup_env(std::string var, std::string val); - char* _dup_env(std::string var, int i); - void _exec_script(Client *client, char **env); + bool _is_cgi(Client *client); + std::string _exec_cgi(Client *client); + char** _set_env(Client *client); + char* _dup_env(std::string var, std::string val); + char* _dup_env(std::string var, int i); + std::string _exec_script(Client *client, char **env); // epoll_update.cpp int _epoll_update(int fd, uint32_t events, int op); int _epoll_update(int fd, uint32_t events, int op, void *ptr); diff --git a/srcs/webserv/cgi_script.cpp b/srcs/webserv/cgi_script.cpp index b896170..5d1f08b 100644 --- a/srcs/webserv/cgi_script.cpp +++ b/srcs/webserv/cgi_script.cpp @@ -11,16 +11,19 @@ bool Webserv::_is_cgi(Client *client) return false; } -void Webserv::_exec_cgi(Client *client) +std::string Webserv::_exec_cgi(Client *client) { - char** env; + char** env; + std::string script_output; env = _set_env(client); - _exec_script(client, env); + script_output = _exec_script(client, env); for (int i = 0; env[i]; i++) delete[] env[i]; delete[] env; + + return script_output; } char* Webserv::_dup_env(std::string var, std::string val = "") @@ -49,7 +52,7 @@ char** Webserv::_set_env(Client *client) env[0] = _dup_env("AUTH_TYPE"); // authentification not supported env[1] = _dup_env("CONTENT_LENGTH" , client->get_rq_body().size()); env[2] = _dup_env("CONTENT_TYPE" , client->get_rq_headers("Content-Type")); - env[3] = _dup_env("GATEWAY_INTERFACE" , "CGI/1.0"); + env[3] = _dup_env("GATEWAY_INTERFACE" , "CGI/1.1"); // https://www.rfc-editor.org/rfc/rfc3875 env[4] = _dup_env("PATH_INFO" , client->get_rq_script_info()); env[5] = _dup_env("PATH_TRANSLATED"); // not supported env[6] = _dup_env("QUERY_STRING" , client->get_rq_query()); @@ -69,7 +72,7 @@ char** Webserv::_set_env(Client *client) return env; } -void Webserv::_exec_script(Client *client, char **env) +std::string Webserv::_exec_script(Client *client, char **env) { #define RD 0 #define WR 1 @@ -82,7 +85,7 @@ void Webserv::_exec_script(Client *client, char **env) pid_t pid; char buf[CGI_BUF_SIZE]; // WIP define buffer char * const * nll = NULL; - std::string response; + std::string script_output; std::string body = client->get_rq_body(); int fd_in[2]; int fd_out[2]; @@ -113,19 +116,16 @@ void Webserv::_exec_script(Client *client, char **env) memset(buf, '\0', CGI_BUF_SIZE); while (read(FD_RD_FR_CHLD, buf, CGI_BUF_SIZE - 1) > 0) { - response += buf; + script_output += buf; memset(buf, '\0', CGI_BUF_SIZE); } } - if (response.empty()) - response = "Status: 500\r\n\r\n"; + if (script_output.empty()) + script_output = "Status: 500\r\n\r\n"; // DEBUG -std::cout << "\n_______response_______\n" - << response - << "\n_____end response_____\n"; +std::cout << "\n______response______\n" << script_output << "\n____end response____\n"; - // TODO: see how this must be handled - client->response += response; + return script_output; } From ae9a9b37f1d638003d06aaf26a491fef685057c6 Mon Sep 17 00:00:00 2001 From: hugogogo Date: Mon, 8 Aug 2022 18:22:54 +0200 Subject: [PATCH 19/21] added test form html in www --- www/form_get.html | 13 +++++++++++++ www/form_post.html | 13 +++++++++++++ 2 files changed, 26 insertions(+) create mode 100644 www/form_get.html create mode 100644 www/form_post.html diff --git a/www/form_get.html b/www/form_get.html new file mode 100644 index 0000000..626478d --- /dev/null +++ b/www/form_get.html @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/www/form_post.html b/www/form_post.html new file mode 100644 index 0000000..ae36576 --- /dev/null +++ b/www/form_post.html @@ -0,0 +1,13 @@ + + + + + + + +
+ +
+ + + From 3dad938e3cba5a18953046a57e9f062a61525917 Mon Sep 17 00:00:00 2001 From: hugogogo Date: Tue, 9 Aug 2022 11:19:46 +0200 Subject: [PATCH 20/21] add extern function for http message parsing + wip compare fields server and script + g tout cassey --- Makefile | 1 + README.md | 6 ++ srcs/Client.cpp | 84 +++++++++------------------ srcs/Client.hpp | 11 ++-- srcs/cgi-bin/php-cgi | 4 +- srcs/utils.cpp | 35 +++++++++-- srcs/utils.hpp | 1 + srcs/webserv/Webserv.hpp | 7 ++- srcs/webserv/cgi_script.cpp | 40 +++++++++++-- srcs/webserv/parsing_message_http.cpp | 75 ++++++++++++++++++++++++ srcs/webserv/parsing_message_http.hpp | 33 +++++++++++ srcs/webserv/parsing_request.cpp | 2 + srcs/webserv/response.cpp | 12 ++-- 13 files changed, 225 insertions(+), 86 deletions(-) create mode 100644 srcs/webserv/parsing_message_http.cpp create mode 100644 srcs/webserv/parsing_message_http.hpp create mode 100644 srcs/webserv/parsing_request.cpp diff --git a/Makefile b/Makefile index ad045bd..e1117aa 100644 --- a/Makefile +++ b/Makefile @@ -29,6 +29,7 @@ SRCS = main.cpp \ utils.cpp \ cgi_script.cpp \ Client.cpp \ + parsing_message_http.cpp \ OBJS_D = builds OBJS = $(SRCS:%.cpp=$(OBJS_D)/%.o) diff --git a/README.md b/README.md index 7afc363..c118b54 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,12 @@ ## 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` diff --git a/srcs/Client.cpp b/srcs/Client.cpp index 354d1c3..8a54403 100644 --- a/srcs/Client.cpp +++ b/srcs/Client.cpp @@ -70,22 +70,15 @@ Client & Client::operator=( Client const & rhs ) // https://www.tutorialspoint.com/http/http_requests.htm void Client::parse_request() { - std::string sub; - std::vector list; - size_t pos; + std::map headers; + std::string body; // DEBUG -std::cout << "\nREQUEST _____________________\n" - << raw_request - << "\n\n"; +std::cout << "\nREQUEST ____________\n" << raw_request << "\n_____________\n"; - pos = (raw_request).find(CRLF CRLF); - sub = (raw_request).substr(0, pos); - list = split(sub, '\n'); - _parse_request_line(*list.begin()); - list.erase(list.begin()); - _parse_request_headers(list); - _parse_request_body(pos + 4); + _parse_request_line(); + _parse_request_headers(); + _parse_request_body(); _parse_port_hostname(this->get_rq_headers("Host")); raw_request.clear(); } @@ -176,30 +169,24 @@ std::string Client::get_rq_headers(const std::string & key) const * PRIVATE MEMBER FUNCTIONS *********************************************/ -void Client::_parse_request_line( std::string rline ) +void Client::_parse_request_line() { - std::vector sline; - std::string tmp; + std::vector line; + int ret; - sline = split(rline, ' '); - if (sline.size() != 3) + ret = ::parse_http_first_line(raw_request, line); + if (ret != 3) { - std::cerr << "err _parse_request_line(): "; - throw std::runtime_error("bad request-line header"); + std::cerr << "err _parse_first_line(): wrong number of elements (" << ret << " instead of 3)\n"; + status = 400; // "bad request" + } + else + { + _request.method = str_to_http_method(line[0]); + _request.uri = line[1]; + _parse_request_uri(line[1]); + _request.version = line[2]; } - // method - tmp = ::trim(sline[0], ' '); - tmp = ::trim(tmp, '\r'); - _request.method = str_to_http_method(tmp); - // uri - tmp = ::trim(sline[1], ' '); - tmp = ::trim(tmp, '\r'); - _request.uri = tmp; - _parse_request_uri( tmp ); - // http version - tmp = ::trim(sline[2], ' '); - tmp = ::trim(tmp, '\r'); - _request.version = tmp; } void Client::_parse_request_uri( std::string uri ) @@ -214,32 +201,16 @@ void Client::_parse_request_uri( std::string uri ) _request.abs_path = uri.substr(0, pos); } -void Client::_parse_request_headers( std::vector list ) +void Client::_parse_request_headers() { - std::string key; - std::string val; - std::vector::iterator it; - size_t pos; - - for (it = list.begin(); it != list.end(); it++) - { - pos = (*it).find(':'); - key = (*it).substr( 0, pos ); - key = ::trim(key, ' '); - key = ::trim(key, '\r'); - key = ::str_tolower(key); - val = (*it).substr( pos + 1 ); - val = ::trim(val, ' '); - val = ::trim(val, '\r'); - _request.headers.insert( std::pair(key, val) ); - } + // TODO: check error and adjust status + _request.headers = ::parse_http_headers(raw_request); } -void Client::_parse_request_body( size_t pos ) +void Client::_parse_request_body() { - std::string body = &raw_request[pos]; - - _request.body = body; + // TODO: check error and adjust status + _request.body = ::parse_http_body(raw_request); } void Client::_parse_port_hostname(std::string host) @@ -247,10 +218,7 @@ void Client::_parse_port_hostname(std::string host) size_t pos; if (host == "") - { std::cerr << "no host\n"; - throw std::runtime_error("no host in request"); - } pos = host.find(':'); // port : diff --git a/srcs/Client.hpp b/srcs/Client.hpp index 64759f0..287f10f 100644 --- a/srcs/Client.hpp +++ b/srcs/Client.hpp @@ -7,9 +7,10 @@ # include # include # include // strdup -# include "utils.hpp" # include // sockaddr_in, struct in_addr # include // htonl, htons, ntohl, ntohs, inet_addr, inet_ntoa +# include "utils.hpp" +# include "parsing_message_http.hpp" struct Script { @@ -78,12 +79,12 @@ class Client std::string _port; std::string _ip; listen_socket * _lsocket; - struct Request _request; + struct Request _request; - void _parse_request_line( std::string rline ); + void _parse_request_line(); + void _parse_request_headers(); + void _parse_request_body(); void _parse_request_uri( std::string uri ); - void _parse_request_headers( std::vector list ); - void _parse_request_body( size_t pos ); void _parse_port_hostname(std::string host); }; diff --git a/srcs/cgi-bin/php-cgi b/srcs/cgi-bin/php-cgi index b51a88e..d3d3625 100755 --- a/srcs/cgi-bin/php-cgi +++ b/srcs/cgi-bin/php-cgi @@ -1,9 +1,9 @@ #! /usr/bin/php split(std::string input, char delimiter) std::string trim(std::string str, char c) { + // TODO: protect substr str = str.substr(str.find_first_not_of(c)); str = str.substr(0, str.find_last_not_of(c) + 1); @@ -100,15 +101,37 @@ void replace_all_substr(std::string &str, const std::string &ori_substr, const s } } -bool operator==(const listen_socket& lhs, int fd) - { return lhs.fd == fd; } - -bool operator==(int fd, const listen_socket& rhs) - { return fd == rhs.fd; } - std::string str_tolower(std::string str) { std::transform(str.begin(), str.end(), str.begin(), ::tolower); return str; } +void delete_line_in_string(std::string * str, size_t pos, std::string delim) +{ + size_t begin; + size_t end; + + begin = (*str).rfind(delim, pos); + if (begin == std::string::npos) + begin = 0; + else + begin += delim.size(); + + end = (*str).find(delim, pos); + if (end == std::string::npos) + end = 0; + else + end += delim.size(); + + (*str).erase(begin, end - begin); +} + + + +bool operator==(const listen_socket& lhs, int fd) + { return lhs.fd == fd; } + +bool operator==(int fd, const listen_socket& rhs) + { return fd == rhs.fd; } + diff --git a/srcs/utils.hpp b/srcs/utils.hpp index 5b271b4..e75f64a 100644 --- a/srcs/utils.hpp +++ b/srcs/utils.hpp @@ -49,5 +49,6 @@ http_method str_to_http_method(std::string &str); std::string http_methods_to_str(unsigned int methods); void replace_all_substr(std::string &str, const std::string &ori_substr, const std::string &new_substr); std::string str_tolower(std::string str); +void delete_line_in_string(std::string * str, size_t pos, std::string delim); #endif diff --git a/srcs/webserv/Webserv.hpp b/srcs/webserv/Webserv.hpp index 6d128f2..f9168cb 100644 --- a/srcs/webserv/Webserv.hpp +++ b/srcs/webserv/Webserv.hpp @@ -32,7 +32,7 @@ extern bool g_run; extern int g_last_signal; -void signal_handler(int signum); +void signal_handler(int signum); // these might only be TMP # define FAILURE -1 @@ -93,7 +93,6 @@ class Webserv ServerConfig &_determine_process_server(Client *client); LocationConfig &_determine_location(ServerConfig &server, std::string const &path); - void _response_correction(Client *client); // cgi_script.cpp bool _is_cgi(Client *client); std::string _exec_cgi(Client *client); @@ -101,6 +100,9 @@ class Webserv char* _dup_env(std::string var, std::string val); char* _dup_env(std::string var, int i); std::string _exec_script(Client *client, char **env); + void _check_script_output(Client *client, std::string output); + void _check_script_status(Client *client, std::string output); + void _check_script_fields(Client *client, std::string output); // epoll_update.cpp int _epoll_update(int fd, uint32_t events, int op); int _epoll_update(int fd, uint32_t events, int op, void *ptr); @@ -115,6 +117,7 @@ class Webserv void _listen(int socket_fd, unsigned int max_connections); void _init_http_status_map(); void _init_mime_types_map(); + }; #endif diff --git a/srcs/webserv/cgi_script.cpp b/srcs/webserv/cgi_script.cpp index 5d1f08b..ec38d1b 100644 --- a/srcs/webserv/cgi_script.cpp +++ b/srcs/webserv/cgi_script.cpp @@ -102,7 +102,8 @@ std::string Webserv::_exec_script(Client *client, char **env) close(FD_RD_FR_CHLD); dup2(FD_RD_FR_PRNT, STDIN_FILENO); dup2(FD_WR_TO_PRNT, STDOUT_FILENO); - execve(client->get_rq_script_path().c_str(), nll, env); + //execve(client->get_rq_script_path().c_str(), nll, env); + execve("truc", nll, env); std::cerr << "execve crashed.\n"; } else @@ -119,13 +120,42 @@ std::string Webserv::_exec_script(Client *client, char **env) script_output += buf; memset(buf, '\0', CGI_BUF_SIZE); } + close(FD_RD_FR_CHLD); } if (script_output.empty()) script_output = "Status: 500\r\n\r\n"; - -// DEBUG -std::cout << "\n______response______\n" << script_output << "\n____end response____\n"; - return script_output; } +void Webserv::_check_script_output(Client *client, std::string output) +{ + // TODO: it doesn't work with execve error, i don't know why yet ? + _check_script_status(client, output); + _check_script_fields(client, output); +} + +void Webserv::_check_script_status(Client *client, std::string output) +{ + size_t pos; + int status_pos; + + pos = output.find("Status:"); + if (pos != std::string::npos) + { + status_pos = pos + std::string("Status:").size(); + client->status = atoi(output.c_str() + status_pos); + ::delete_line_in_string(&output, pos, CRLF); + } + client->status = 200; +} + +void Webserv::_check_script_fields(Client *client, std::string output) +{ + std::map server_fields; + std::map script_fields; + + server_fields = parse_http_headers(client->response); + script_fields = parse_http_headers(output); + // TODO: compare both map to supress duplicates +} + diff --git a/srcs/webserv/parsing_message_http.cpp b/srcs/webserv/parsing_message_http.cpp new file mode 100644 index 0000000..d66ee6c --- /dev/null +++ b/srcs/webserv/parsing_message_http.cpp @@ -0,0 +1,75 @@ + +#include "parsing_message_http.hpp" + +size_t + parse_http_first_line(std::string message, std::vector &line) +{ + std::vector sline; + std::string sub; + std::string tmp; + size_t pos; + size_t ret; + + // TODO: check for err in substr + pos = message.find(CRLF); + sub = message.substr(0, pos); + sline = ::split(sub, ' '); + ret = sline.size(); + if (ret != 3) + return ret; + for (int i = 0; i < 3; i++) + { + tmp = ::trim(sline[0], ' '); + tmp = ::trim(tmp, '\r'); + line.push_back(tmp); + } + return ret; +} + +std::map + parse_http_headers(std::string message) +{ + std::map headers; + std::vector list; + std::vector::iterator it; + std::string sub; + std::string key; + std::string val; + size_t pos; + + pos = (message).find(CRLF CRLF); + sub = (message).substr(0, pos); + list = ::split(sub, '\n'); + // TODO: if (list.begin() is "first line") + list.erase(list.begin()); + + for (it = list.begin(); it != list.end(); it++) + { + // TODO: if pattern is not "NAME: value" return error + pos = (*it).find(':'); + key = (*it).substr( 0, pos ); + key = ::trim(key, ' '); + key = ::trim(key, '\r'); + key = ::str_tolower(key); + val = (*it).substr( pos + 1 ); + val = ::trim(val, ' '); + val = ::trim(val, '\r'); + headers.insert( std::pair(key, val) ); + } + return headers; +} + +std::string + parse_http_body(std::string message) +{ + std::string body; + size_t pos; + + pos = message.find(CRLF CRLF); + pos += std::string(CRLF CRLF).size(); + // TODO: copying just like that might fail in case of binary or images + body = message.substr(pos); + + return body; +} + diff --git a/srcs/webserv/parsing_message_http.hpp b/srcs/webserv/parsing_message_http.hpp new file mode 100644 index 0000000..34b955c --- /dev/null +++ b/srcs/webserv/parsing_message_http.hpp @@ -0,0 +1,33 @@ + +#ifndef PARSING_MESSAGE_HTTP_HPP +# define PARSING_MESSAGE_HTTP_HPP + +# include +# include +# include +# include +# include "utils.hpp" + +size_t + parse_http_first_line(std::string message, std::vector &line); + +std::map + parse_http_headers(std::string message); + +std::string + parse_http_body(std::string message); + +// http message structure : +// +// start-line +// request-line +// method SP target SP version +// response-line +// version SP status SP reason +// header-fields +// name ":" SP value +// CRLF +// body + +#endif + diff --git a/srcs/webserv/parsing_request.cpp b/srcs/webserv/parsing_request.cpp new file mode 100644 index 0000000..d83d9e3 --- /dev/null +++ b/srcs/webserv/parsing_request.cpp @@ -0,0 +1,2 @@ +#include "parsing_request.hpp" + diff --git a/srcs/webserv/response.cpp b/srcs/webserv/response.cpp index e86761b..fd3cc19 100644 --- a/srcs/webserv/response.cpp +++ b/srcs/webserv/response.cpp @@ -145,10 +145,12 @@ void Webserv::_get(Client *client, ServerConfig &server, LocationConfig &locatio // TMP HUGO // + std::string script_output; if (_is_cgi(client)) { - _exec_cgi(client); - _response_correction(client); + script_output = _exec_cgi(client); + _check_script_output(client, script_output); + std::cout << "_____________status:" << client->status << "\n"; return; } // @@ -224,12 +226,6 @@ void Webserv::_get_file(Client *client, const std::string &path) } } -// WIP HUGO -void Webserv::_response_correction(Client *client) -{ - (void)client; -} - void Webserv::_append_body(Client *client, const char *body, size_t body_size, const std::string &file_extension) { /* From 53a548e31418b46572a4914cb4100a758a49a694 Mon Sep 17 00:00:00 2001 From: hugogogo Date: Tue, 9 Aug 2022 14:57:05 +0200 Subject: [PATCH 21/21] wip script output verification working + trim secure pos segfault + concat script message with server message --- Makefile | 2 +- srcs/utils.cpp | 18 +++++++++++---- srcs/utils.hpp | 2 +- srcs/webserv/cgi_script.cpp | 33 ++++++++++++++++++++------- srcs/webserv/parsing_message_http.cpp | 19 +++++++++++++-- srcs/webserv/parsing_message_http.hpp | 3 +++ srcs/webserv/response.cpp | 5 +++- 7 files changed, 65 insertions(+), 17 deletions(-) diff --git a/Makefile b/Makefile index e1117aa..f570826 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ CXX = c++ CXXFLAGS = -Wall -Wextra #-Werror CXXFLAGS += $(HEADERS_D:%=-I%) CXXFLAGS += -std=c++98 -CXXFLAGS += -g +CXXFLAGS += -g3 CXXFLAGS += -MMD -MP #header dependencie #CXXFLAGS += -O3 diff --git a/srcs/utils.cpp b/srcs/utils.cpp index 66d8f74..e72d576 100644 --- a/srcs/utils.cpp +++ b/srcs/utils.cpp @@ -15,9 +15,19 @@ std::vector split(std::string input, char delimiter) std::string trim(std::string str, char c) { - // TODO: protect substr - str = str.substr(str.find_first_not_of(c)); - str = str.substr(0, str.find_last_not_of(c) + 1); + size_t pos; + + // delete leadings c + pos = str.find_first_not_of(c); + if (pos == std::string::npos) + return str; + str = str.substr(pos); + + // delete endings c + pos = str.find_last_not_of(c); + if (pos == std::string::npos) + return str; + str = str.substr(0, pos + 1); return str; } @@ -107,7 +117,7 @@ std::string str_tolower(std::string str) return str; } -void delete_line_in_string(std::string * str, size_t pos, std::string delim) +void del_line_in_str(std::string * str, size_t pos, std::string delim) { size_t begin; size_t end; diff --git a/srcs/utils.hpp b/srcs/utils.hpp index e75f64a..fdb037e 100644 --- a/srcs/utils.hpp +++ b/srcs/utils.hpp @@ -49,6 +49,6 @@ http_method str_to_http_method(std::string &str); std::string http_methods_to_str(unsigned int methods); void replace_all_substr(std::string &str, const std::string &ori_substr, const std::string &new_substr); std::string str_tolower(std::string str); -void delete_line_in_string(std::string * str, size_t pos, std::string delim); +void del_line_in_str(std::string * str, size_t pos, std::string delim); #endif diff --git a/srcs/webserv/cgi_script.cpp b/srcs/webserv/cgi_script.cpp index ec38d1b..be03cbe 100644 --- a/srcs/webserv/cgi_script.cpp +++ b/srcs/webserv/cgi_script.cpp @@ -102,8 +102,11 @@ std::string Webserv::_exec_script(Client *client, char **env) close(FD_RD_FR_CHLD); dup2(FD_RD_FR_PRNT, STDIN_FILENO); dup2(FD_WR_TO_PRNT, STDOUT_FILENO); - //execve(client->get_rq_script_path().c_str(), nll, env); - execve("truc", nll, env); + // DEBUG + std::cerr << "execve:\n"; + execve(client->get_rq_script_path().c_str(), nll, env); + // for tests execve crash : + //execve("wrong", nll, env); std::cerr << "execve crashed.\n"; } else @@ -144,18 +147,32 @@ void Webserv::_check_script_status(Client *client, std::string output) { status_pos = pos + std::string("Status:").size(); client->status = atoi(output.c_str() + status_pos); - ::delete_line_in_string(&output, pos, CRLF); + ::del_line_in_str(&output, pos, CRLF); } client->status = 200; } void Webserv::_check_script_fields(Client *client, std::string output) { - std::map server_fields; - std::map script_fields; + std::map srv_fld; // server_field + std::map scr_fld; // script_field + std::map::iterator it_srv; + std::map::iterator it_scr; + size_t pos; - server_fields = parse_http_headers(client->response); - script_fields = parse_http_headers(output); - // TODO: compare both map to supress duplicates + srv_fld = parse_http_headers(client->response); + scr_fld = parse_http_headers(output); + // wip: compare both map to supress duplicates + for (it_srv = srv_fld.begin(); it_srv != srv_fld.end(); it_srv++) + { + for (it_scr = scr_fld.begin(); it_scr != scr_fld.end(); it_scr++) + { + if (it_srv->first == it_scr->first) + { + pos = client->response.find(it_srv->first); + ::del_line_in_str(&client->response, pos, CRLF); + } + } + } } diff --git a/srcs/webserv/parsing_message_http.cpp b/srcs/webserv/parsing_message_http.cpp index d66ee6c..63e67cd 100644 --- a/srcs/webserv/parsing_message_http.cpp +++ b/srcs/webserv/parsing_message_http.cpp @@ -19,7 +19,7 @@ size_t return ret; for (int i = 0; i < 3; i++) { - tmp = ::trim(sline[0], ' '); + tmp = ::trim(sline[i], ' '); tmp = ::trim(tmp, '\r'); line.push_back(tmp); } @@ -40,7 +40,7 @@ std::map pos = (message).find(CRLF CRLF); sub = (message).substr(0, pos); list = ::split(sub, '\n'); - // TODO: if (list.begin() is "first line") + if ( maybe_http_first_line( *list.begin() ) ) list.erase(list.begin()); for (it = list.begin(); it != list.end(); it++) @@ -73,3 +73,18 @@ std::string return body; } +bool maybe_http_first_line(std::string str) +{ +// method SP target SP version https://www.rfc-editor.org/rfc/rfc7230.html#section-3.1.1 +// version SP status SP reason https://www.rfc-editor.org/rfc/rfc7230.html#section-3.1.2 + + std::vector sline; + + sline = ::split(str, ' '); + if (sline.size() != 3) + return false; + if (sline[0].find(':') != std::string::npos) + return false; + return true; +} + diff --git a/srcs/webserv/parsing_message_http.hpp b/srcs/webserv/parsing_message_http.hpp index 34b955c..67cd473 100644 --- a/srcs/webserv/parsing_message_http.hpp +++ b/srcs/webserv/parsing_message_http.hpp @@ -17,6 +17,9 @@ std::map std::string parse_http_body(std::string message); +bool + maybe_http_first_line(std::string); + // http message structure : // // start-line diff --git a/srcs/webserv/response.cpp b/srcs/webserv/response.cpp index fd3cc19..0a04a77 100644 --- a/srcs/webserv/response.cpp +++ b/srcs/webserv/response.cpp @@ -149,8 +149,11 @@ void Webserv::_get(Client *client, ServerConfig &server, LocationConfig &locatio if (_is_cgi(client)) { script_output = _exec_cgi(client); + // DEBUG + std::cout << "\n____script_output____\n" << script_output << "\n_______________\n"; + // wip check output of script _check_script_output(client, script_output); - std::cout << "_____________status:" << client->status << "\n"; + client->response += script_output; return; } //