diff --git a/cmd/server.c b/cmd/server.c index f537361..7b78ff8 100644 --- a/cmd/server.c +++ b/cmd/server.c @@ -32,7 +32,7 @@ int printDebug(char message[]) { return 0; } -void php_cgi(char *sPath) { +char *php_cgi(char *sPath, struct HTTPRequest *r) { int phpPipe[2]; char *buf = NULL; size_t bufLen = 1024; @@ -41,10 +41,12 @@ void php_cgi(char *sPath) { pipe(phpPipe); pid_t pid; + int status = 0; pid = fork(); - if (pid == 0) { + if (pid == 0) { // Child fork char script[500]; + char *queryString = NULL; close(phpPipe[0]); dup2(phpPipe[1], STDOUT_FILENO); strcpy(script, "SCRIPT_FILENAME="); @@ -52,15 +54,48 @@ void php_cgi(char *sPath) { strcat(script, sPath); putenv("GATEWAY_INTERFACE=CGI/1.1"); putenv(script); - putenv("QUERY_STRING="); - putenv("REQUEST_METHOD=GET"); putenv("REDIRECT_STATUS=true"); putenv("SERVER_PROTOCOL=HTTP/1.1"); putenv("REMOTE_HOST=127.0.0.1"); - execl("/usr/bin/php-cgi", "php-cgi", NULL); - } else if (pid < 0) { + if (!strcmp(r->requestType, "POST")) { + putenv("REQUEST_METHOD=POST"); + char conLenString[256]; + sprintf(conLenString, "CONTENT_LENGTH=%zu", r->requestBodyLen); + putenv(conLenString); + putenv("CONTENT_TYPE=application/x-www-form-urlencoded"); + queryString = malloc(r->requestBodyLen + 24); + sprintf(queryString, "QUERY_STRING=%s", r->requestBody); + putenv(queryString); + + // Starting fork to pipe stdin into php-cgi + int phpPipe2[2]; + pipe(phpPipe2); + pid_t pid2; + pid2 = fork(); + + if (pid2 == 0) { // Child fork + close(phpPipe2[0]); + dup2(phpPipe2[1], STDOUT_FILENO); + printf("%s", r->requestBody); + close(phpPipe2[1]); + exit(EXIT_SUCCESS); + } else if (pid < 0) { // Error forking + printDebug("Error in stdin php frok"); + } else { // Parent fork + close(phpPipe[1]); + dup2(phpPipe2[0], STDIN_FILENO); + execlp("/usr/bin/php-cgi", "php-cgi", NULL); + } + } else { + queryString = malloc(strlen(r->requestVars) + 24); + sprintf(queryString, "QUERY_STRING=%s", r->requestVars); + putenv(queryString); + putenv("REQUEST_METHOD=GET"); + execl("/usr/bin/php-cgi", "php-cgi", NULL); + } + } else if (pid < 0) { // Error forking printDebug("Error forking php exec"); - } else { + } else { // Parent fork size_t buffCount; close(phpPipe[1]); do { @@ -70,11 +105,16 @@ void php_cgi(char *sPath) { buf = realloc(buf, bufLen); } } while (buffCount == 0); + do { + waitpid(pid, &status, WUNTRACED); + } while (!WIFEXITED(status) && !WIFSIGNALED(status)); } close(phpPipe[0]); - printf("PHP: %s\n", buf); - return; + if (status != 0) { + return NULL; + } + return buf; } int parseHTTPRequest(unsigned char *buffer, struct HTTPRequest *r) { @@ -88,6 +128,7 @@ int parseHTTPRequest(unsigned char *buffer, struct HTTPRequest *r) { // Creating empty requestBody r->requestBody = calloc(8, sizeof(char)); + r->requestBodyLen = 0; for (int i = 0; i <= strlen((char *)buffer); i++) { temp[0] = buffer[i]; @@ -101,7 +142,7 @@ int parseHTTPRequest(unsigned char *buffer, struct HTTPRequest *r) { // HTTP Request Type if ((!strcmp(token, "GET")) || (!strcmp(token, "POST")) || (!strcmp(token, "PUT")) || (!strcmp(token, "DELETE")) || - (!strcmp(token, "CONNECT"))) { + (!strcmp(token, "CONNECT")) || (!strcmp(token, "HEAD"))) { // Grabbing HTTP Request Type r->requestType = malloc(strlen(token)); strcpy(r->requestType, token); @@ -130,7 +171,8 @@ int parseHTTPRequest(unsigned char *buffer, struct HTTPRequest *r) { (strlen((char *)checkLine) + strlen((char *)r->requestBody) + 1)); strcat((char *)r->requestBody, (char *)checkLine); // Adding newline to requestBody - sprintf((char *)r->requestBody, "%s\n", r->requestBody); + strcat((char *)r->requestBody, "\n"); + r->requestBodyLen += strlen((char *)checkLine); } else { // Information parsing !content if (strlen((char *)checkLine) == 1) { // Looking for blank empty line to end header info contentCheck = 1; @@ -185,6 +227,29 @@ int handleGetRequest(int socket, struct HTTPRequest *r, SSL *ssl) { unsigned char *fileContent = calloc(size, sizeof(unsigned char)); FILE *fp; char *workingReqDir; + + char *phpReturn = NULL; + char phpEnd[5] = ".php"; + bool endsWithPhp = false; + if (strlen(phpEnd) <= strlen(r->requestDir)) { + for (int i = 0; i < strlen(phpEnd); i++) { + if (r->requestDir[i + strlen(r->requestDir) - strlen(phpEnd)] != phpEnd[i]) { + endsWithPhp = false; + break; + } + endsWithPhp = true; + } + } + + if (endsWithPhp) { + phpReturn = php_cgi(r->requestDir, r); + if (phpReturn != NULL) { + return returnPHPRequest(socket, phpReturn, ssl); + } else { + return return500Request(socket, ssl); + } + } + // If requesting root directory change to index.html if (!strcmp(r->requestDir, "/")) { workingReqDir = "index.html"; @@ -281,26 +346,42 @@ int handleDELETERequest(int socket, struct HTTPRequest *r, SSL *ssl) { } int handlePOSTRequest(int socket, struct HTTPRequest *r, SSL *ssl) { + char *phpReturn = NULL; // Supported data types application/x-www-form-urlencoded application/json if (r->requestConLen == NULL) { // Return 411 if length var not specified printDebug("Content Length was not sent in POST request"); return return411Request(socket, ssl); } - //r->requestBody[strlen((char *)r->requestBody) - 1] = '\0'; // Resetting request content length to remove trailing newline if (r->requestConType != NULL) { - if (!strcmp(r->requestConType, "application/json")) { - printf("JSON Request\n"); - } else if (!strcmp(r->requestConType, "application/x-www-form-utlencoded")) { - printf("Application form\n"); + if (!strcmp(r->requestConType, "application/x-www-form-utlencoded") == 0) { + printDebug("Application From Selected"); + } else { + printDebug("Content will likely get parsed wrong"); } - } else { - printf("HERE\n"); } - php_cgi(r->requestDir); + char phpEnd[5] = ".php"; + bool endsWithPhp = false; + if (strlen(phpEnd) <= strlen(r->requestDir)) { + for (int i = 0; i < strlen(phpEnd); i++) { + if (r->requestDir[i + strlen(r->requestDir) - strlen(phpEnd)] != phpEnd[i]) { + endsWithPhp = false; + break; + } + endsWithPhp = true; + } + } - return return501Request(socket, ssl); + if (endsWithPhp) { + phpReturn = php_cgi(r->requestDir, r); + if (phpReturn != NULL) { + return returnPHPRequest(socket, phpReturn, ssl); + } + } else { + return return200Request(socket, NULL, ssl); + } + return return500Request(socket, ssl); } int handleRequest(unsigned char buffer[], int socket, SSL *ssl) { @@ -312,7 +393,7 @@ int handleRequest(unsigned char buffer[], int socket, SSL *ssl) { // Grabbing relevant information out of request checkerr = parseHTTPRequest(buffer, &r); if (checkerr != 0) { // Checking for HTTP parsing error - printDebug("Error ;("); + printDebug("Error parsing..."); if (checkerr == -1) { printDebug("Error reading request, returning empty 500"); return500Request(socket, ssl); @@ -335,6 +416,8 @@ int handleRequest(unsigned char buffer[], int socket, SSL *ssl) { handleDELETERequest(socket, &r, ssl); } else if (!strcmp(r.requestType, "CONNECT")) { return200Request(socket, NULL, ssl); + } else if (!strcmp(r.requestType, "HEAD")) { + return200Request(socket, NULL, ssl); } else { return500Request(socket, ssl); } diff --git a/content/vardumpGET.php b/content/vardumpGET.php new file mode 100644 index 0000000..180fc86 --- /dev/null +++ b/content/vardumpGET.php @@ -0,0 +1,4 @@ + diff --git a/content/vardumpPOST.php b/content/vardumpPOST.php new file mode 100644 index 0000000..517dc58 --- /dev/null +++ b/content/vardumpPOST.php @@ -0,0 +1,8 @@ + diff --git a/include/httpStruct.h b/include/httpStruct.h index e379ed1..e31097e 100644 --- a/include/httpStruct.h +++ b/include/httpStruct.h @@ -11,4 +11,5 @@ struct HTTPRequest { char *requestConType; char *requestConLen; unsigned char *requestBody; + size_t requestBodyLen; }; diff --git a/include/returnRequest.h b/include/returnRequest.h index a4ca3ef..a34faeb 100644 --- a/include/returnRequest.h +++ b/include/returnRequest.h @@ -15,3 +15,5 @@ int return500Request(int socket, SSL *ssl); int return501Request(int socket, SSL *ssl); int return505Request(int socket, SSL *ssl); +int returnPHPRequest(int socket, char *content, SSL *ssl); + diff --git a/src/returnRequest.c b/src/returnRequest.c index d313ad3..8d7392a 100644 --- a/src/returnRequest.c +++ b/src/returnRequest.c @@ -22,7 +22,7 @@ int return200Request(int socket, unsigned char *content, SSL *ssl) { char *message = ""; if (content != NULL) { message = calloc(strlen((char *)content) + 128, sizeof(char)); - sprintf(message, "HTTP/1.1 200 OK\nContent-Length: %zu\nConnection: close\n\n%s\n", + sprintf(message, "HTTP/1.1 200 OK\nContent-Length: %zu\nConnection: close\n\n%s", strlen((char *)content), content); } else { // Sending empty response message = calloc(128, sizeof(char)); @@ -65,7 +65,7 @@ int return411Request(int socket, SSL *ssl) { int return418Request(int socket, SSL *ssl) { char *message=calloc(128, sizeof(char)); - sprintf(message, "HTTP/1.1 418 I'm a teapotnContent-Length: 0\nConnection: close\n\n"); + sprintf(message, "HTTP/1.1 418 I'm a teapot\nContent-Length: 0\nConnection: close\n\n"); return returnRequest(socket, message, 418, ssl); } @@ -86,3 +86,34 @@ int return505Request(int socket, SSL *ssl) { sprintf(message, "HTTP/1.1 505 HTTP Version Not Supported\nContent-Length: 0\nConnection: close\n\n"); return returnRequest(socket, message, 505, ssl); } + +int returnPHPRequest(int socket, char *content, SSL *ssl) { + char *message = malloc(1024); + memset(message, 0, 1024); + char *line = malloc(1024); + memset(line, 0, 1024); + char temp[1]; + size_t lineNum = 0; + for (int i = 0; i <= strlen(content); i++) { + temp[0] = content[i]; + if (((!strcmp(temp, "\n")) && (i != 0)) || (i == strlen(content))) { + if (lineNum != 0) { + strcat(message, line); + strcat(message, "\n"); + } + if (strlen(line) > 0) { + memset(line, 0, strlen(line)); + } + lineNum++; + } else { + strcat(line, temp); + } + } + + free(line); + if (strlen(message) == 0) { // Return 500 on error parsing + free(message); + return return500Request(socket, ssl); + } + return return200Request(socket, (unsigned char *)message, ssl); +}