Refactor for shared library use
This commit is contained in:
		
							
								
								
									
										539
									
								
								src/lib/fastcgi.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										539
									
								
								src/lib/fastcgi.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,539 @@ | ||||
| /** | ||||
|  * Necronda Web Server | ||||
|  * FastCGI interface implementation | ||||
|  * src/lib/fastcgi.c | ||||
|  * Lorenz Stechauner, 2020-12-26 | ||||
|  */ | ||||
|  | ||||
| #include "fastcgi.h" | ||||
| #include "utils.h" | ||||
| #include "../client.h" | ||||
| #include "../necronda-server.h" | ||||
| #include <sys/un.h> | ||||
| #include <zlib.h> | ||||
| #include <sys/socket.h> | ||||
| #include <errno.h> | ||||
| #include <string.h> | ||||
|  | ||||
| char *fastcgi_add_param(char *buf, const char *key, const char *value) { | ||||
|     char *ptr = buf; | ||||
|     unsigned long key_len = strlen(key); | ||||
|     unsigned long val_len = strlen(value); | ||||
|  | ||||
|  | ||||
|     if (key_len <= 127) { | ||||
|         ptr[0] = (char) (key_len & 0x7F); | ||||
|         ptr++; | ||||
|     } else { | ||||
|         ptr[0] = (char) (0x80 | (key_len >> 24)); | ||||
|         ptr[1] = (char) ((key_len >> 16) & 0xFF); | ||||
|         ptr[2] = (char) ((key_len >> 8) & 0xFF); | ||||
|         ptr[3] = (char) (key_len & 0xFF); | ||||
|         ptr += 4; | ||||
|     } | ||||
|     if (val_len <= 127) { | ||||
|         ptr[0] = (char) (val_len & 0x7F); | ||||
|         ptr++; | ||||
|     } else { | ||||
|         ptr[0] = (char) (0x80 | (val_len >> 24)); | ||||
|         ptr[1] = (char) ((val_len >> 16) & 0xFF); | ||||
|         ptr[2] = (char) ((val_len >> 8) & 0xFF); | ||||
|         ptr[3] = (char) (val_len & 0xFF); | ||||
|         ptr += 4; | ||||
|     } | ||||
|  | ||||
|     memcpy(ptr, key, key_len); | ||||
|     ptr += key_len; | ||||
|     memcpy(ptr, value, val_len); | ||||
|     ptr += val_len; | ||||
|  | ||||
|     return ptr; | ||||
| } | ||||
|  | ||||
| int fastcgi_init(fastcgi_conn *conn, unsigned int client_num, unsigned int req_num, const sock *client, | ||||
|                  const http_req *req, const http_uri *uri) { | ||||
|     unsigned short req_id = (client_num & 0xFFF) << 4; | ||||
|     if (client_num == 0) { | ||||
|         req_id |= (req_num + 1) & 0xF; | ||||
|     } else { | ||||
|         req_id |= req_num & 0xF; | ||||
|     } | ||||
|     conn->req_id = req_id; | ||||
|     conn->out_buf = NULL; | ||||
|     conn->out_off = 0; | ||||
|  | ||||
|     int php_fpm = socket(AF_UNIX, SOCK_STREAM, 0); | ||||
|     if (php_fpm < 0) { | ||||
|         print(ERR_STR "Unable to create unix socket: %s" CLR_STR, strerror(errno)); | ||||
|         return -1; | ||||
|     } | ||||
|     conn->socket = php_fpm; | ||||
|  | ||||
|     struct sockaddr_un php_fpm_addr = {AF_UNIX, PHP_FPM_SOCKET}; | ||||
|     if (connect(conn->socket, (struct sockaddr *) &php_fpm_addr, sizeof(php_fpm_addr)) < 0) { | ||||
|         print(ERR_STR "Unable to connect to unix socket of PHP-FPM: %s" CLR_STR, strerror(errno)); | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
|     FCGI_Header header = { | ||||
|             .version = FCGI_VERSION_1, | ||||
|             .requestIdB1 = req_id >> 8, | ||||
|             .requestIdB0 = req_id & 0xFF, | ||||
|             .paddingLength = 0, | ||||
|             .reserved = 0 | ||||
|     }; | ||||
|  | ||||
|     header.type = FCGI_BEGIN_REQUEST; | ||||
|     header.contentLengthB1 = 0; | ||||
|     header.contentLengthB0 = sizeof(FCGI_BeginRequestBody); | ||||
|     FCGI_BeginRequestRecord begin = { | ||||
|             header, | ||||
|             {.roleB1 = (FCGI_RESPONDER >> 8) & 0xFF, .roleB0 = FCGI_RESPONDER & 0xFF, .flags = 0} | ||||
|     }; | ||||
|     if (send(conn->socket, &begin, sizeof(begin), 0) != sizeof(begin)) { | ||||
|         print(ERR_STR "Unable to send to PHP-FPM: %s" CLR_STR, strerror(errno)); | ||||
|         return -2; | ||||
|     } | ||||
|  | ||||
|     char param_buf[4096]; | ||||
|     char buf0[256]; | ||||
|     char *param_ptr = param_buf + sizeof(header); | ||||
|  | ||||
|     param_ptr = fastcgi_add_param(param_ptr, "REDIRECT_STATUS", "CGI"); | ||||
|     param_ptr = fastcgi_add_param(param_ptr, "DOCUMENT_ROOT", uri->webroot); | ||||
|     param_ptr = fastcgi_add_param(param_ptr, "GATEWAY_INTERFACE", "CGI/1.1"); | ||||
|     param_ptr = fastcgi_add_param(param_ptr, "SERVER_SOFTWARE", SERVER_STR); | ||||
|     param_ptr = fastcgi_add_param(param_ptr, "SERVER_PROTOCOL", "HTTP/1.1"); | ||||
|     param_ptr = fastcgi_add_param(param_ptr, "SERVER_NAME", http_get_header_field(&req->hdr, "Host")); | ||||
|     if (client->enc) { | ||||
|         param_ptr = fastcgi_add_param(param_ptr, "HTTPS", "on"); | ||||
|     } | ||||
|  | ||||
|     struct sockaddr_storage addr_storage; | ||||
|     struct sockaddr_in6 *addr; | ||||
|     socklen_t len = sizeof(addr_storage); | ||||
|     getsockname(client->socket, (struct sockaddr *) &addr_storage, &len); | ||||
|     addr = (struct sockaddr_in6 *) &addr_storage; | ||||
|     sprintf(buf0, "%i", addr->sin6_port); | ||||
|     param_ptr = fastcgi_add_param(param_ptr, "SERVER_PORT", buf0); | ||||
|  | ||||
|     len = sizeof(addr_storage); | ||||
|     getpeername(client->socket, (struct sockaddr *) &addr_storage, &len); | ||||
|     addr = (struct sockaddr_in6 *) &addr_storage; | ||||
|     sprintf(buf0, "%i", addr->sin6_port); | ||||
|     param_ptr = fastcgi_add_param(param_ptr, "REMOTE_PORT", buf0); | ||||
|     param_ptr = fastcgi_add_param(param_ptr, "REMOTE_ADDR", client_addr_str); | ||||
|     param_ptr = fastcgi_add_param(param_ptr, "REMOTE_HOST", client_host_str != NULL ? client_host_str : client_addr_str); | ||||
|     //param_ptr = fastcgi_add_param(param_ptr, "REMOTE_IDENT", ""); | ||||
|     //param_ptr = fastcgi_add_param(param_ptr, "REMOTE_USER", ""); | ||||
|  | ||||
|     param_ptr = fastcgi_add_param(param_ptr, "REQUEST_METHOD", req->method); | ||||
|     param_ptr = fastcgi_add_param(param_ptr, "REQUEST_URI", req->uri); | ||||
|     param_ptr = fastcgi_add_param(param_ptr, "SCRIPT_NAME", uri->filename + strlen(uri->webroot)); | ||||
|     param_ptr = fastcgi_add_param(param_ptr, "SCRIPT_FILENAME", uri->filename); | ||||
|     //param_ptr = fastcgi_add_param(param_ptr, "PATH_TRANSLATED", uri->filename); | ||||
|  | ||||
|     param_ptr = fastcgi_add_param(param_ptr, "QUERY_STRING", uri->query != NULL ? uri->query : ""); | ||||
|     if (uri->pathinfo != NULL && strlen(uri->pathinfo) > 0) { | ||||
|         sprintf(buf0, "/%s", uri->pathinfo); | ||||
|     } else { | ||||
|         buf0[0] = 0; | ||||
|     } | ||||
|     param_ptr = fastcgi_add_param(param_ptr, "PATH_INFO", buf0); | ||||
|  | ||||
|     //param_ptr = fastcgi_add_param(param_ptr, "AUTH_TYPE", ""); | ||||
|     char *content_length = http_get_header_field(&req->hdr, "Content-Length"); | ||||
|     param_ptr = fastcgi_add_param(param_ptr, "CONTENT_LENGTH", content_length != NULL ? content_length : ""); | ||||
|     char *content_type = http_get_header_field(&req->hdr, "Content-Type"); | ||||
|     param_ptr = fastcgi_add_param(param_ptr, "CONTENT_TYPE", content_type != NULL ? content_type : ""); | ||||
|     if (client_geoip != NULL) { | ||||
|         param_ptr = fastcgi_add_param(param_ptr, "REMOTE_INFO", client_geoip); | ||||
|     } | ||||
|  | ||||
|     for (int i = 0; i < req->hdr.field_num; i++) { | ||||
|         char *ptr = buf0; | ||||
|         ptr += sprintf(ptr, "HTTP_"); | ||||
|         for (int j = 0; j < strlen(req->hdr.fields[i][0]); j++, ptr++) { | ||||
|             char ch = req->hdr.fields[i][0][j]; | ||||
|             if ((ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9')) { | ||||
|                 ch = ch; | ||||
|             } else if (ch >= 'a' && ch <= 'z') { | ||||
|                 ch &= 0x5F; | ||||
|             } else { | ||||
|                 ch = '_'; | ||||
|             } | ||||
|             ptr[0] = ch; | ||||
|             ptr[1] = 0; | ||||
|         } | ||||
|         param_ptr = fastcgi_add_param(param_ptr, buf0, req->hdr.fields[i][1]); | ||||
|     } | ||||
|  | ||||
|     unsigned short param_len = param_ptr - param_buf - sizeof(header); | ||||
|     header.type = FCGI_PARAMS; | ||||
|     header.contentLengthB1 = param_len >> 8; | ||||
|     header.contentLengthB0 = param_len & 0xFF; | ||||
|     memcpy(param_buf, &header, sizeof(header)); | ||||
|     if (send(conn->socket, param_buf, param_len + sizeof(header), 0) != param_len + sizeof(header)) { | ||||
|         print(ERR_STR "Unable to send to PHP-FPM: %s" CLR_STR, strerror(errno)); | ||||
|         return -2; | ||||
|     } | ||||
|  | ||||
|     header.type = FCGI_PARAMS; | ||||
|     header.contentLengthB1 = 0; | ||||
|     header.contentLengthB0 = 0; | ||||
|     if (send(conn->socket, &header, sizeof(header), 0) != sizeof(header)) { | ||||
|         print(ERR_STR "Unable to send to PHP-FPM: %s" CLR_STR, strerror(errno)); | ||||
|         return -2; | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int fastcgi_close_stdin(fastcgi_conn *conn) { | ||||
|     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 | ||||
|     }; | ||||
|  | ||||
|     if (send(conn->socket, &header, sizeof(header), 0) != sizeof(header)) { | ||||
|         print(ERR_STR "Unable to send to PHP-FPM: %s" CLR_STR, strerror(errno)); | ||||
|         return -2; | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int fastcgi_php_error(const char *msg, int msg_len, char *err_msg) { | ||||
|     char *msg_str = malloc(msg_len + 1); | ||||
|     char *ptr0 = msg_str; | ||||
|     strncpy(msg_str, msg, msg_len); | ||||
|     char *ptr1 = NULL; | ||||
|     int len; | ||||
|     int err = 0; | ||||
|     // FIXME *msg is part of a stream, handle fragmented lines | ||||
|     while (1) { | ||||
|         int msg_type = 0; | ||||
|         int msg_pre_len = 0; | ||||
|         ptr1 = strstr(ptr0, "PHP message: "); | ||||
|         if (ptr1 == NULL) { | ||||
|             len = (int) (msg_len - (ptr0 - msg_str)); | ||||
|             if (ptr0 == msg_str) msg_type = 2; | ||||
|         } else { | ||||
|             len = (int) (ptr1 - ptr0); | ||||
|         } | ||||
|         if (len == 0) { | ||||
|             goto next; | ||||
|         } | ||||
|  | ||||
|         if (len >= 14 && strncmp(ptr0, "PHP Warning:  ", 14) == 0) { | ||||
|             msg_type = 1; | ||||
|             msg_pre_len = 14; | ||||
|         } else if (len >= 18 && strncmp(ptr0, "PHP Fatal error:  ", 18) == 0) { | ||||
|             msg_type = 2; | ||||
|             msg_pre_len = 18; | ||||
|         } else if (len >= 18 && strncmp(ptr0, "PHP Parse error:  ", 18) == 0) { | ||||
|             msg_type = 2; | ||||
|             msg_pre_len = 18; | ||||
|         } else if (len >= 18 && strncmp(ptr0, "PHP Notice:  ", 13) == 0) { | ||||
|             msg_type = 1; | ||||
|             msg_pre_len = 13; | ||||
|         } | ||||
|  | ||||
|         char *ptr2 = ptr0; | ||||
|         char *ptr3; | ||||
|         int len2; | ||||
|         while (ptr2 - ptr0 < len) { | ||||
|             ptr3 = strchr(ptr2, '\n'); | ||||
|             len2 = (int) (len - (ptr2 - ptr0)); | ||||
|             if (ptr3 != NULL && (ptr3 - ptr2) < len2) { | ||||
|                 len2 = (int) (ptr3 - ptr2); | ||||
|             } | ||||
|             print("%s%.*s%s", msg_type == 1 ? WRN_STR : msg_type == 2 ? ERR_STR : "", len2, ptr2, msg_type != 0 ? CLR_STR : ""); | ||||
|             if (msg_type == 2 && ptr2 == ptr0) { | ||||
|                 sprintf(err_msg, "%.*s", len2, ptr2); | ||||
|                 err = 1; | ||||
|             } | ||||
|             if (ptr3 == NULL) { | ||||
|                 break; | ||||
|             } | ||||
|             ptr2 = ptr3 + 1; | ||||
|         } | ||||
|  | ||||
|         next: | ||||
|         if (ptr1 == NULL) { | ||||
|             break; | ||||
|         } | ||||
|         ptr0 = ptr1 + 13; | ||||
|     } | ||||
|     free(msg_str); | ||||
|     return err; | ||||
| } | ||||
|  | ||||
| int fastcgi_header(fastcgi_conn *conn, http_res *res, char *err_msg) { | ||||
|     FCGI_Header header; | ||||
|     char *content; | ||||
|     unsigned short content_len, req_id; | ||||
|     int ret; | ||||
|     int err = 0; | ||||
|  | ||||
|     while (1) { | ||||
|         ret = recv(conn->socket, &header, sizeof(header), 0); | ||||
|         if (ret < 0) { | ||||
|             res->status = http_get_status(502); | ||||
|             sprintf(err_msg, "Unable to communicate with PHP-FPM."); | ||||
|             print(ERR_STR "Unable to receive from PHP-FPM: %s" CLR_STR, strerror(errno)); | ||||
|             return 1; | ||||
|         } else if (ret != sizeof(header)) { | ||||
|             res->status = http_get_status(502); | ||||
|             sprintf(err_msg, "Unable to communicate with PHP-FPM."); | ||||
|             print(ERR_STR "Unable to receive from PHP-FPM" CLR_STR); | ||||
|             return 1; | ||||
|         } | ||||
|         req_id = (header.requestIdB1 << 8) | header.requestIdB0; | ||||
|         content_len = (header.contentLengthB1 << 8) | header.contentLengthB0; | ||||
|         content = malloc(content_len + header.paddingLength); | ||||
|         ret = recv(conn->socket, content, content_len + header.paddingLength, 0); | ||||
|         if (ret < 0) { | ||||
|             res->status = http_get_status(502); | ||||
|             sprintf(err_msg, "Unable to communicate with PHP-FPM."); | ||||
|             print(ERR_STR "Unable to receive from PHP-FPM: %s" CLR_STR, strerror(errno)); | ||||
|             free(content); | ||||
|             return 1; | ||||
|         } else if (ret != (content_len + header.paddingLength)) { | ||||
|             res->status = http_get_status(502); | ||||
|             sprintf(err_msg, "Unable to communicate with PHP-FPM."); | ||||
|             print(ERR_STR "Unable to receive from PHP-FPM" CLR_STR); | ||||
|             free(content); | ||||
|             return 1; | ||||
|         } | ||||
|  | ||||
|         if (req_id != conn->req_id) { | ||||
|             continue; | ||||
|         } | ||||
|  | ||||
|         if (header.type == FCGI_END_REQUEST) { | ||||
|             FCGI_EndRequestBody *body = (FCGI_EndRequestBody *) content; | ||||
|             int app_status = (body->appStatusB3 << 24) | (body->appStatusB2 << 16) | (body->appStatusB1 << 8) | | ||||
|                              body->appStatusB0; | ||||
|             if (body->protocolStatus != FCGI_REQUEST_COMPLETE) { | ||||
|                 print(ERR_STR "FastCGI protocol error: %i" CLR_STR, body->protocolStatus); | ||||
|             } | ||||
|             if (app_status != 0) { | ||||
|                 print(ERR_STR "Script terminated with exit code %i" CLR_STR, app_status); | ||||
|             } | ||||
|             close(conn->socket); | ||||
|             conn->socket = 0; | ||||
|             free(content); | ||||
|             return 1; | ||||
|         } else if (header.type == FCGI_STDERR) { | ||||
|             err = err || fastcgi_php_error(content, content_len, err_msg); | ||||
|         } else if (header.type == FCGI_STDOUT) { | ||||
|             break; | ||||
|         } else { | ||||
|             print(ERR_STR "Unknown FastCGI type: %i" CLR_STR, header.type); | ||||
|         } | ||||
|  | ||||
|         free(content); | ||||
|     } | ||||
|     if (err) { | ||||
|         res->status = http_get_status(500); | ||||
|         return 2; | ||||
|     } | ||||
|  | ||||
|     conn->out_buf = content; | ||||
|     conn->out_len = content_len; | ||||
|     conn->out_off = (unsigned short) (strstr(content, "\r\n\r\n") - content + 4); | ||||
|  | ||||
|     char *buf = content; | ||||
|     unsigned short header_len = conn->out_off; | ||||
|     if (header_len <= 0) { | ||||
|         print(ERR_STR "Unable to parse header: End of header not found" CLR_STR); | ||||
|         return 1; | ||||
|     } | ||||
|  | ||||
|     for (int i = 0; i < header_len; i++) { | ||||
|         if ((buf[i] >= 0x00 && buf[i] <= 0x1F && buf[i] != '\r' && buf[i] != '\n') || buf[i] == 0x7F) { | ||||
|             print(ERR_STR "Unable to parse header: Header contains illegal characters" CLR_STR); | ||||
|             return 2; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     char *ptr = buf; | ||||
|     while (header_len != (ptr - buf)) { | ||||
|         char *pos0 = strstr(ptr, "\r\n"); | ||||
|         if (pos0 == NULL) { | ||||
|             print(ERR_STR "Unable to parse header: Invalid header format" CLR_STR); | ||||
|             return 1; | ||||
|         } | ||||
|  | ||||
|         ret = http_parse_header_field(&res->hdr, ptr, pos0); | ||||
|         if (ret != 0) return ret; | ||||
|         if (pos0[2] == '\r' && pos0[3] == '\n') { | ||||
|             return 0; | ||||
|         } | ||||
|         ptr = pos0 + 2; | ||||
|     } | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| int fastcgi_send(fastcgi_conn *conn, sock *client, int flags) { | ||||
|     FCGI_Header header; | ||||
|     int ret; | ||||
|     char buf0[256]; | ||||
|     int len; | ||||
|     char *content, *ptr; | ||||
|     unsigned short req_id, content_len; | ||||
|     char comp_out[4096]; | ||||
|     int finish_comp = 0; | ||||
|  | ||||
|     z_stream strm; | ||||
|     if (flags & FASTCGI_COMPRESS) { | ||||
|         int level = NECRONDA_ZLIB_LEVEL; | ||||
|         strm.zalloc = Z_NULL; | ||||
|         strm.zfree = Z_NULL; | ||||
|         strm.opaque = Z_NULL; | ||||
|         if (deflateInit(&strm, level) != Z_OK) { | ||||
|             print(ERR_STR "Unable to init deflate: %s" CLR_STR, strerror(errno)); | ||||
|             flags &= !FASTCGI_COMPRESS; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (conn->out_buf != NULL && conn->out_len > conn->out_off) { | ||||
|         content = conn->out_buf; | ||||
|         ptr = content + conn->out_off; | ||||
|         content_len = conn->out_len - conn->out_off; | ||||
|         goto out; | ||||
|     } | ||||
|  | ||||
|     while (1) { | ||||
|         ret = recv(conn->socket, &header, sizeof(header), 0); | ||||
|         if (ret < 0) { | ||||
|             print(ERR_STR "Unable to receive from PHP-FPM: %s" CLR_STR, strerror(errno)); | ||||
|             return -1; | ||||
|         } else if (ret != sizeof(header)) { | ||||
|             print(ERR_STR "Unable to receive from PHP-FPM" CLR_STR); | ||||
|             return -1; | ||||
|         } | ||||
|         req_id = (header.requestIdB1 << 8) | header.requestIdB0; | ||||
|         content_len = (header.contentLengthB1 << 8) | header.contentLengthB0; | ||||
|         content = malloc(content_len + header.paddingLength); | ||||
|         ptr = content; | ||||
|         ret = recv(conn->socket, content, content_len + header.paddingLength, 0); | ||||
|         if (ret < 0) { | ||||
|             print(ERR_STR "Unable to receive from PHP-FPM: %s" CLR_STR, strerror(errno)); | ||||
|             free(content); | ||||
|             return -1; | ||||
|         } else if (ret != (content_len + header.paddingLength)) { | ||||
|             print(ERR_STR "Unable to receive from PHP-FPM" CLR_STR); | ||||
|             free(content); | ||||
|             return -1; | ||||
|         } | ||||
|  | ||||
|         if (header.type == FCGI_END_REQUEST) { | ||||
|             FCGI_EndRequestBody *body = (FCGI_EndRequestBody *) content; | ||||
|             int app_status = (body->appStatusB3 << 24) | (body->appStatusB2 << 16) | (body->appStatusB1 << 8) | | ||||
|                              body->appStatusB0; | ||||
|             if (body->protocolStatus != FCGI_REQUEST_COMPLETE) { | ||||
|                 print(ERR_STR "FastCGI protocol error: %i" CLR_STR, body->protocolStatus); | ||||
|             } | ||||
|             if (app_status != 0) { | ||||
|                 print(ERR_STR "Script terminated with exit code %i" CLR_STR, app_status); | ||||
|             } | ||||
|             close(conn->socket); | ||||
|             conn->socket = 0; | ||||
|             free(content); | ||||
|  | ||||
|             if (flags & FASTCGI_COMPRESS) { | ||||
|                 finish_comp = 1; | ||||
|                 content_len = 0; | ||||
|                 goto out; | ||||
|                 finish: | ||||
|                 deflateEnd(&strm); | ||||
|             } | ||||
|  | ||||
|             if (flags & FASTCGI_CHUNKED) { | ||||
|                 sock_send(client, "0\r\n\r\n", 5, 0); | ||||
|             } | ||||
|  | ||||
|             return 0; | ||||
|         } else if (header.type == FCGI_STDERR) { | ||||
|             fastcgi_php_error(content, content_len, buf0); | ||||
|         } else if (header.type == FCGI_STDOUT) { | ||||
|             out: | ||||
|             if (flags & FASTCGI_COMPRESS) { | ||||
|                 strm.avail_in = content_len; | ||||
|                 strm.next_in = (unsigned char *) ptr; | ||||
|             } | ||||
|             do { | ||||
|                 int buf_len = content_len; | ||||
|                 if (flags & FASTCGI_COMPRESS) { | ||||
|                     strm.avail_out = sizeof(comp_out); | ||||
|                     strm.next_out = (unsigned char *) comp_out; | ||||
|                     deflate(&strm, finish_comp ? Z_FINISH : Z_NO_FLUSH); | ||||
|                     strm.avail_in = 0; | ||||
|                     ptr = comp_out; | ||||
|                     buf_len = (int) (sizeof(comp_out) - strm.avail_out); | ||||
|                 } | ||||
|                 if (buf_len != 0) { | ||||
|                     len = sprintf(buf0, "%X\r\n", buf_len); | ||||
|                     if (flags & FASTCGI_CHUNKED) sock_send(client, buf0, len, 0); | ||||
|                     sock_send(client, ptr, buf_len, 0); | ||||
|                     if (flags & FASTCGI_CHUNKED) sock_send(client, "\r\n", 2, 0); | ||||
|                 } | ||||
|             } while ((flags & FASTCGI_COMPRESS) && strm.avail_out == 0); | ||||
|             if (finish_comp) goto finish; | ||||
|         } else { | ||||
|             print(ERR_STR "Unknown FastCGI type: %i" CLR_STR, header.type); | ||||
|         } | ||||
|         free(content); | ||||
|     } | ||||
| } | ||||
|  | ||||
| int fastcgi_receive(fastcgi_conn *conn, sock *client, unsigned long len) { | ||||
|     unsigned long rcv_len = 0; | ||||
|     char *buf[16384]; | ||||
|     long 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 | ||||
|     }; | ||||
|  | ||||
|     if (client->buf != NULL && client->buf_len - client->buf_off > 0) { | ||||
|         ret = (int) (client->buf_len - client->buf_off); | ||||
|         memcpy(buf, client->buf + client->buf_off, ret); | ||||
|         goto send; | ||||
|     } | ||||
|  | ||||
|     while (rcv_len < len) { | ||||
|         ret = sock_recv(client, buf, sizeof(buf), 0); | ||||
|         if (ret <= 0) { | ||||
|             print(ERR_STR "Unable to receive: %s" CLR_STR, sock_strerror(client)); | ||||
|             return -1; | ||||
|         } | ||||
|  | ||||
|         send: | ||||
|         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: | ||||
|             print(ERR_STR "Unable to send to PHP-FPM: %s" CLR_STR, strerror(errno)); | ||||
|             return -2; | ||||
|         } | ||||
|     } | ||||
|     return 0; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user