Files
ginxsom/FASTCGI.md
2025-08-18 21:51:54 -04:00

22 KiB

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

#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.