369 lines
22 KiB
Markdown
369 lines
22 KiB
Markdown
# FastCGI Protocol Flow Documentation
|
|
|
|
This document provides ASCII flow charts to understand how FastCGI works with nginx for the ginxsom blossom server.
|
|
|
|
## FastCGI Overview
|
|
|
|
FastCGI is a binary protocol that allows web servers (like nginx) to communicate with application servers efficiently. Unlike CGI which spawns a new process per request, FastCGI applications are persistent and can handle multiple concurrent requests.
|
|
|
|
## 1. FastCGI Connection Setup Flow
|
|
|
|
```
|
|
┌─────────────────┐ Socket ┌─────────────────┐
|
|
│ nginx │◄──────────────►│ FastCGI App │
|
|
│ Web Server │ Connection │ (ginxsom) │
|
|
└─────────────────┘ └─────────────────┘
|
|
│ │
|
|
│ 1. Create Unix socket │
|
|
│ /tmp/ginxsom.sock │
|
|
│ │
|
|
│ 2. FastCGI app binds & listens │
|
|
│◄───────────────────────────────────│
|
|
│ │
|
|
│ 3. nginx connects when needed │
|
|
│───────────────────────────────────►│
|
|
│ │
|
|
│ 4. Connection established │
|
|
│◄──────────────────────────────────►│
|
|
```
|
|
|
|
## 2. HTTP Request Processing Flow
|
|
|
|
```
|
|
┌─────────┐ HTTP ┌─────────┐ FastCGI ┌─────────┐
|
|
│ Client │────────────►│ nginx │─────────────►│ ginxsom │
|
|
│Browser │ │ │ │ FastCGI │
|
|
└─────────┘ └─────────┘ └─────────┘
|
|
│ │ │
|
|
│ HTTP Request │ │
|
|
│ PUT /upload │ │
|
|
│────────────────────────► │
|
|
│ │ │
|
|
│ │ FCGI_BEGIN_REQUEST │
|
|
│ │───────────────────────►│
|
|
│ │ │
|
|
│ │ FCGI_PARAMS │
|
|
│ │ (HTTP headers, etc) │
|
|
│ │───────────────────────►│
|
|
│ │ │
|
|
│ │ FCGI_STDIN │
|
|
│ │ (Request body) │
|
|
│ │───────────────────────►│
|
|
│ │ │
|
|
│ │ Process │
|
|
│ │◄───────Request─────────│
|
|
│ │ │
|
|
│ │ FCGI_STDOUT │
|
|
│ │ (Response headers) │
|
|
│ │◄───────────────────────│
|
|
│ │ │
|
|
│ │ FCGI_STDOUT │
|
|
│ │ (Response body) │
|
|
│ │◄───────────────────────│
|
|
│ │ │
|
|
│ │ FCGI_END_REQUEST │
|
|
│ │◄───────────────────────│
|
|
│ │ │
|
|
│ HTTP Response │ │
|
|
│◄──────────────────────│ │
|
|
```
|
|
|
|
## 3. FastCGI Record Structure
|
|
|
|
```
|
|
FastCGI Record Format:
|
|
┌─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┬─────────┐
|
|
│ Version │ Type │RequestID│RequestID│ Length │ Length │ Padding │Reserved │
|
|
│ (1) │ (1) │ Hi │ Lo │ Hi │ Lo │ Length │ (1) │
|
|
│ │ │ (1) │ (1) │ (1) │ (1) │ (1) │ │
|
|
└─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┴─────────┘
|
|
│◄────────────────── 8 bytes header ──────────────────────►│
|
|
│ │
|
|
│◄─────────────────── Content (Length bytes) ─────────────►│
|
|
│ │
|
|
│◄───── Padding (Padding Length bytes) ────►│
|
|
|
|
Record Types:
|
|
- FCGI_BEGIN_REQUEST (1) - Start new request
|
|
- FCGI_PARAMS (4) - Environment variables
|
|
- FCGI_STDIN (5) - Request body data
|
|
- FCGI_STDOUT (6) - Response data
|
|
- FCGI_END_REQUEST (3) - End of request
|
|
```
|
|
|
|
## 4. Ginxsom Endpoint Handling Flow
|
|
|
|
### 4a. Static File Request (Direct nginx)
|
|
|
|
```
|
|
┌─────────┐ ┌─────────┐
|
|
│ Client │ │ nginx │
|
|
└─────────┘ └─────────┘
|
|
│ │
|
|
│ GET /{sha256hash} │
|
|
│───────────────────────►│
|
|
│ │
|
|
│ │ Check file exists:
|
|
│ │ /var/lib/ginxsom/files/
|
|
│ │ {first2}/{remaining}
|
|
│ │
|
|
│ │ ┌─ File exists? ─┐
|
|
│ │ │ YES │
|
|
│ │ └────────────────┘
|
|
│ │ │
|
|
│ HTTP 200 + File │ │ Serve directly
|
|
│◄──────────────────────│◄──────┘
|
|
│ │
|
|
|
|
Alternative flow:
|
|
│ │ ┌─ File exists? ─┐
|
|
│ │ │ NO │
|
|
│ │ └────────────────┘
|
|
│ │ │
|
|
│ HTTP 404 Not Found │ │
|
|
│◄──────────────────────│◄──────┘
|
|
```
|
|
|
|
### 4b. Upload Request (FastCGI)
|
|
|
|
```
|
|
┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐
|
|
│ Client │ │ nginx │ │ ginxsom │ │ File │
|
|
│ │ │ │ │ FastCGI │ │ System │
|
|
└─────────┘ └─────────┘ └─────────┘ └─────────┘
|
|
│ │ │ │
|
|
│ PUT /upload │ │ │
|
|
│ Auth: xyz │ │ │
|
|
│ Body: file │ │ │
|
|
│─────────────►│ │ │
|
|
│ │ │ │
|
|
│ │ FCGI_PARAMS │ │
|
|
│ │ METHOD=PUT │ │
|
|
│ │ URI=/upload │ │
|
|
│ │ AUTH=xyz │ │
|
|
│ │─────────────►│ │
|
|
│ │ │ │
|
|
│ │ FCGI_STDIN │ │
|
|
│ │ (file data) │ │
|
|
│ │─────────────►│ │
|
|
│ │ │ │
|
|
│ │ │ Verify Auth │
|
|
│ │ │ (nostr sig) │
|
|
│ │ │ │
|
|
│ │ │ Calculate │
|
|
│ │ │ SHA-256 │
|
|
│ │ │ │
|
|
│ │ │ Write file │
|
|
│ │ │─────────────►│
|
|
│ │ │ │
|
|
│ │ │ Store │
|
|
│ │ │ metadata │
|
|
│ │ │────────────────────►
|
|
│ │ │ │ DB
|
|
│ │ │ │
|
|
│ │ FCGI_STDOUT │ │
|
|
│ │ 200 OK │ │
|
|
│ │ {sha256} │ │
|
|
│ │◄─────────────│ │
|
|
│ │ │ │
|
|
│ HTTP 200 OK │ │ │
|
|
│ {sha256} │ │ │
|
|
│◄─────────────│ │ │
|
|
```
|
|
|
|
### 4c. HEAD Request for Metadata (FastCGI)
|
|
|
|
```
|
|
┌─────────┐ ┌─────────┐ ┌─────────┐
|
|
│ Client │ │ nginx │ │ ginxsom │
|
|
│ │ │ │ │ FastCGI │
|
|
└─────────┘ └─────────┘ └─────────┘
|
|
│ │ │
|
|
│ HEAD /{sha256} │ │
|
|
│──────────────────►│ │
|
|
│ │ │
|
|
│ │ FCGI_PARAMS │
|
|
│ │ METHOD=HEAD │
|
|
│ │ BLOSSOM_HASH=... │
|
|
│ │──────────────────►│
|
|
│ │ │
|
|
│ │ │ Query DB for
|
|
│ │ │ file metadata
|
|
│ │ │
|
|
│ │ FCGI_STDOUT │
|
|
│ │ Content-Length: X │
|
|
│ │ Content-Type: Y │
|
|
│ │ x-sha256: hash │
|
|
│ │◄──────────────────│
|
|
│ │ │
|
|
│ HTTP Headers Only │ │
|
|
│◄──────────────────│ │
|
|
```
|
|
|
|
## 5. Development vs Production Deployment
|
|
|
|
### Development Mode
|
|
```
|
|
┌─────────────┐ ┌─────────────┐
|
|
│ Terminal │ │ nginx │
|
|
│ │ │ │
|
|
│ ./ginxsom │◄──────────────►│ Config: │
|
|
│ --fastcgi │ Unix Socket │ fastcgi_pass│
|
|
│ --socket │ /tmp/ginxsom │ unix:/tmp/ │
|
|
│ /tmp/... │ .sock │ ginxsom.sock│
|
|
└─────────────┘ └─────────────┘
|
|
│ │
|
|
│ Direct execution │ sudo systemctl
|
|
│ Easy debugging │ reload nginx
|
|
│ Ctrl+C to stop │ (config changes)
|
|
│ Real-time logs │
|
|
```
|
|
|
|
### Production Mode
|
|
```
|
|
┌─────────────┐ ┌─────────────┐
|
|
│ systemd │ │ nginx │
|
|
│ │ │ │
|
|
│ ginxsom │◄──────────────►│ Config: │
|
|
│ .service │ Unix Socket │ fastcgi_pass│
|
|
│ │ /run/ginxsom/ │ unix:/run/ │
|
|
│ Auto-start │ ginxsom.sock │ ginxsom/... │
|
|
│ Auto-restart│ │ │
|
|
│ Log to file │ │ │
|
|
└─────────────┘ └─────────────┘
|
|
```
|
|
|
|
## 6. Complete nginx + FastCGI Request Flow
|
|
|
|
```
|
|
┌───────┐ ┌─────────────────────────────────────────────────┐ ┌─────────┐
|
|
│Client │ │ nginx │ │ginxsom │
|
|
└───────┘ └─────────────────────────────────────────────────┘ │FastCGI │
|
|
│ │ └─────────┘
|
|
│ GET /abc123...def │ │
|
|
│───────────────────────►│ │
|
|
│ │ │
|
|
│ │ location ~ ^/([a-f0-9]{64})$ { │
|
|
│ │ # Check if static file exists │
|
|
│ │ try_files /$prefix/$suffix =404 │
|
|
│ │ } │
|
|
│ │ │
|
|
│ │ ┌─ File exists? ─┐ │
|
|
│ │ │ YES │ │
|
|
│ │ └────────────────┘ │
|
|
│ │ │ │
|
|
│ │ │ Serve directly (fast!) │
|
|
│ HTTP 200 + File │ │ │
|
|
│◄──────────────────────│◄──────┘ │
|
|
│ │ │
|
|
│ │ │
|
|
│ PUT /upload │ │
|
|
│ Authorization: xyz │ │
|
|
│───────────────────────►│ │
|
|
│ │ │
|
|
│ │ location /upload { │
|
|
│ │ fastcgi_pass unix:/tmp/ │
|
|
│ │ ginxsom.sock; │
|
|
│ │ } │
|
|
│ │ │
|
|
│ │ ┌─ FastCGI Protocol ─┐ │
|
|
│ │ │ FCGI_BEGIN_REQUEST │─────────────►│
|
|
│ │ │ FCGI_PARAMS │─────────────►│
|
|
│ │ │ FCGI_STDIN │─────────────►│
|
|
│ │ └─────────────────────┘ │
|
|
│ │ │
|
|
│ │ │ Verify
|
|
│ │ │ nostr
|
|
│ │ │ signature
|
|
│ │ │
|
|
│ │ │ Calculate
|
|
│ │ │ SHA-256
|
|
│ │ │
|
|
│ │ │ Store file
|
|
│ │ │ & metadata
|
|
│ │ │
|
|
│ │ ┌─ FastCGI Response ─┐ │
|
|
│ │ │ FCGI_STDOUT │◄─────────────│
|
|
│ │ │ FCGI_END_REQUEST │◄─────────────│
|
|
│ │ └─────────────────────┘ │
|
|
│ │ │
|
|
│ HTTP 200 OK │ │
|
|
│ {"sha256": "..."} │ │
|
|
│◄──────────────────────│ │
|
|
```
|
|
|
|
## 7. libfcgi Library Usage
|
|
|
|
### Basic FastCGI Application Structure
|
|
|
|
```c
|
|
#include <fcgiapp.h>
|
|
|
|
int main() {
|
|
FCGX_Request request;
|
|
|
|
// Initialize FastCGI library
|
|
FCGX_Init();
|
|
FCGX_InitRequest(&request, 0, 0);
|
|
|
|
// Main request processing loop
|
|
while (FCGX_Accept_r(&request) == 0) {
|
|
|
|
// Read environment variables (HTTP headers, etc)
|
|
char* method = FCGX_GetParam("REQUEST_METHOD", request.envp);
|
|
char* uri = FCGX_GetParam("REQUEST_URI", request.envp);
|
|
char* auth = FCGX_GetParam("HTTP_AUTHORIZATION", request.envp);
|
|
|
|
// Route requests
|
|
if (strcmp(uri, "/health") == 0) {
|
|
handle_health(&request);
|
|
} else if (strcmp(uri, "/upload") == 0) {
|
|
handle_upload(&request);
|
|
} else if (strncmp(uri, "/head/", 6) == 0) {
|
|
handle_head(&request);
|
|
}
|
|
|
|
// Finish this request
|
|
FCGX_Finish_r(&request);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
```
|
|
|
|
### Reading Request Data
|
|
|
|
```
|
|
┌─────────────────┐ ┌─────────────────┐
|
|
│ nginx sends: │ │ ginxsom reads: │
|
|
├─────────────────┤ ├─────────────────┤
|
|
│ FCGI_PARAMS │────────►│ FCGX_GetParam() │
|
|
│ REQUEST_METHOD │ │ "PUT" │
|
|
│ REQUEST_URI │ │ "/upload" │
|
|
│ CONTENT_LENGTH │ │ "1024" │
|
|
│ HTTP_* │ │ headers │
|
|
├─────────────────┤ ├─────────────────┤
|
|
│ FCGI_STDIN │────────►│ FCGX_GetStr() │
|
|
│ (request body) │ │ file data │
|
|
└─────────────────┘ └─────────────────┘
|
|
```
|
|
|
|
### Writing Response Data
|
|
|
|
```
|
|
┌─────────────────┐ ┌─────────────────┐
|
|
│ ginxsom writes: │ │ nginx sends: │
|
|
├─────────────────┤ ├─────────────────┤
|
|
│ FCGX_PutS() │────────►│ HTTP Response │
|
|
│ "Content-Type: │ │ Headers │
|
|
│ application/ │ │ │
|
|
│ json\r\n\r\n" │ │ │
|
|
├─────────────────┤ ├─────────────────┤
|
|
│ FCGX_PutS() │────────►│ HTTP Response │
|
|
│ '{"status": │ │ Body │
|
|
│ "ok"}' │ │ │
|
|
└─────────────────┘ └─────────────────┘
|
|
```
|
|
|
|
This documentation shows how FastCGI enables nginx to efficiently serve static blossom files directly while delegating authenticated operations to the ginxsom FastCGI application.
|