From c708633197b24da522d914cf378ff5c7b0258553 Mon Sep 17 00:00:00 2001
From: Lorenz Stechauner <lorenz.stechauner@necronda.net>
Date: Sun, 27 Dec 2020 23:57:14 +0100
Subject: [PATCH] FastCGI stdin implementation

---
 src/client.c  | 20 +++++++++++++++++---
 src/fastcgi.c | 41 +++++++++++++++++++++++++++++++++++++++++
 src/fastcgi.h |  2 ++
 src/http.c    |  4 ++--
 4 files changed, 62 insertions(+), 5 deletions(-)

diff --git a/src/client.c b/src/client.c
index 34e7edb..be94cec 100644
--- a/src/client.c
+++ b/src/client.c
@@ -238,10 +238,23 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
         }
 
         if (strncmp(req.method, "POST", 4) == 0 || strncmp(req.method, "PUT", 3) == 0) {
-            // TODO send content to fastcgi
-        } else {
-            fastcgi_close_stdin(&php_fpm);
+            char *client_content_length = http_get_header_field(&req.hdr, "Content-Length");
+            unsigned long client_content_len = 0;
+            if (client_content_length == NULL) {
+                goto fastcgi_end;
+            }
+            client_content_len = strtoul(client_content_length, NULL, 10);
+            ret = fastcgi_receive(&php_fpm, client, client_content_len);
+            if (ret != 0) {
+                if (ret < 0) {
+                    goto abort;
+                }
+                res.status = http_get_status(502);
+                goto respond;
+            }
         }
+        fastcgi_end:
+        fastcgi_close_stdin(&php_fpm);
 
         char *accept_encoding = http_get_header_field(&req.hdr, "Accept-Encoding");
         if (accept_encoding != NULL && strstr(accept_encoding, "deflate") != NULL) {
@@ -350,6 +363,7 @@ int client_request_handler(sock *client, unsigned long client_num, unsigned int
 
     uri_free(&uri);
     abort:
+    if (php_fpm.socket != 0) close(php_fpm.socket);
     http_free_req(&req);
     http_free_res(&res);
     return !client_keep_alive;
diff --git a/src/fastcgi.c b/src/fastcgi.c
index 0b24135..cbf5ed9 100644
--- a/src/fastcgi.c
+++ b/src/fastcgi.c
@@ -476,3 +476,44 @@ int fastcgi_send(fastcgi_conn *conn, sock *client, int flags) {
         free(content);
     }
 }
+
+int fastcgi_receive(fastcgi_conn *conn, sock *client, unsigned long len) {
+    unsigned long rcv_len = 0;
+    char *buf[16384];
+    int ret;
+    FCGI_Header header = {
+            .version = FCGI_VERSION_1,
+            .type = FCGI_STDIN,
+            .requestIdB1 = conn->req_id >> 8,
+            .requestIdB0 = conn->req_id & 0xFF,
+            .contentLengthB1 = 0,
+            .contentLengthB0 = 0,
+            .paddingLength = 0,
+            .reserved = 0
+    };
+    while (rcv_len < len) {
+        if (client->enc) {
+            ret = SSL_read(client->ssl, buf, sizeof(buf));
+            if (ret <= 0) {
+                print(ERR_STR "Unable to receive: %s" CLR_STR, ssl_get_error(client->ssl, rcv_len));
+                return -1;
+            }
+        } else {
+            ret = recv(client->socket, buf, sizeof(buf), 0);
+            if (ret <= 0) {
+                print(ERR_STR "Unable to receive: %s" CLR_STR, strerror(errno));
+                return -1;
+            }
+        }
+        rcv_len += ret;
+        header.contentLengthB1 = (ret >> 8) & 0xFF;
+        header.contentLengthB0 = ret & 0xFF;
+        if (send(conn->socket, &header, sizeof(header), 0) != sizeof(header)) goto err;
+        if (send(conn->socket, buf, ret, 0) != ret) {
+            err:
+            fprintf(stderr, ERR_STR "Unable to send to PHP-FPM: %s" CLR_STR "\n", strerror(errno));
+            return -2;
+        }
+    }
+    return 0;
+}
diff --git a/src/fastcgi.h b/src/fastcgi.h
index bfb4664..b39fab6 100644
--- a/src/fastcgi.h
+++ b/src/fastcgi.h
@@ -30,6 +30,8 @@ int fastcgi_header(fastcgi_conn *conn, http_res *res, char *err_msg);
 
 int fastcgi_send(fastcgi_conn *conn, sock *client, int flags);
 
+int fastcgi_receive(fastcgi_conn *conn, sock *client, unsigned long len);
+
 
 /*
  * Listening socket file number
diff --git a/src/http.c b/src/http.c
index e6becc2..a15979c 100644
--- a/src/http.c
+++ b/src/http.c
@@ -54,13 +54,13 @@ int http_receive_request(sock *client, http_req *req) {
     while (1) {
         if (client->enc) {
             rcv_len = SSL_read(client->ssl, buf, CLIENT_MAX_HEADER_SIZE);
-            if (rcv_len < 0) {
+            if (rcv_len <= 0) {
                 print(ERR_STR "Unable to receive: %s" CLR_STR, ssl_get_error(client->ssl, rcv_len));
                 return -1;
             }
         } else {
             rcv_len = recv(client->socket, buf, CLIENT_MAX_HEADER_SIZE, 0);
-            if (rcv_len < 0) {
+            if (rcv_len <= 0) {
                 print(ERR_STR "Unable to receive: %s" CLR_STR, strerror(errno));
                 return -1;
             }