this repo has no description
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

checkpoint

+99 -93
+65 -12
bin/fcgi_server.ml
··· 7 7 let addr = `Tcp (Eio.Net.Ipaddr.V4.loopback, port) in 8 8 let server_socket = Eio.Net.listen net ~backlog:10 ~reuse_addr:true ~sw addr in 9 9 Eio.traceln "FastCGI server listening on port %d" port; 10 - Eio.Net.run_server server_socket ~on_error:(fun ex -> Eio.traceln "Error: %s" (Printexc.to_string ex)) 11 - @@ fun flow addr -> 12 - Eio.traceln "Accepted connection from %a" Eio.Net.Sockaddr.pp addr; 13 - (* Here you would handle the FastCGI protocol, but for simplicity, we just echo a string. *) 14 - let req = Fastcgi.read_request_from_flow ~sw flow in 15 - match req with 16 - | Error msg -> 17 - Eio.traceln "Failed to read request: %s" msg; 18 - Eio.Flow.close flow 19 - | Ok req -> 20 - Eio.traceln "Received request: %a" Fastcgi.Request.pp req; 21 - Eio.Flow.close flow 10 + 11 + (* Handler function that processes FastCGI requests *) 12 + let handler ~sw:_ request output = 13 + Eio.traceln "Processing request: %a" Fastcgi.Request.pp request; 14 + 15 + (* Get request parameters *) 16 + let params = request.Fastcgi.Request.params in 17 + let method_ = Fastcgi.Record.KV.find_opt "REQUEST_METHOD" params |> Option.value ~default:"GET" in 18 + let uri = Fastcgi.Record.KV.find_opt "REQUEST_URI" params |> Option.value ~default:"/" in 19 + let script_name = Fastcgi.Record.KV.find_opt "SCRIPT_NAME" params |> Option.value ~default:"" in 20 + 21 + (* Log request info *) 22 + Eio.traceln " Method: %s" method_; 23 + Eio.traceln " URI: %s" uri; 24 + Eio.traceln " Script: %s" script_name; 25 + 26 + (* Generate simple HTTP response *) 27 + let response_body = 28 + Printf.sprintf 29 + "<!DOCTYPE html>\n\ 30 + <html>\n\ 31 + <head><title>FastCGI OCaml Server</title></head>\n\ 32 + <body>\n\ 33 + <h1>FastCGI OCaml Server</h1>\n\ 34 + <p>Request processed successfully!</p>\n\ 35 + <ul>\n\ 36 + <li>Method: %s</li>\n\ 37 + <li>URI: %s</li>\n\ 38 + <li>Script: %s</li>\n\ 39 + </ul>\n\ 40 + <h2>All Parameters:</h2>\n\ 41 + <pre>%s</pre>\n\ 42 + </body>\n\ 43 + </html>\n" 44 + method_ uri script_name 45 + (let params_seq = Fastcgi.Record.KV.to_seq params in 46 + let params_list = List.of_seq params_seq in 47 + String.concat "\n" (List.map (fun (k, v) -> Printf.sprintf "%s = %s" k v) params_list)) 48 + in 49 + 50 + (* Write HTTP response using FastCGI STDOUT records *) 51 + let response_headers = 52 + Printf.sprintf 53 + "Status: 200 OK\r\n\ 54 + Content-Type: text/html; charset=utf-8\r\n\ 55 + Content-Length: %d\r\n\ 56 + \r\n" 57 + (String.length response_body) 58 + in 59 + let full_response = response_headers ^ response_body in 60 + 61 + (* Write STDOUT content *) 62 + Fastcgi.Request.write_stdout_records output request.Fastcgi.Request.request_id full_response; 63 + 64 + (* Write empty STDERR (no errors) *) 65 + Fastcgi.Request.write_stderr_records output request.Fastcgi.Request.request_id ""; 66 + 67 + (* Write END_REQUEST with success status *) 68 + Fastcgi.Request.write_end_request output request.Fastcgi.Request.request_id 0 Fastcgi.Request.Request_complete 69 + in 70 + 71 + (* Run the FastCGI server *) 72 + Fastcgi.run server_socket 73 + ~on_error:(fun ex -> Eio.traceln "Error: %s" (Printexc.to_string ex)) 74 + handler 22 75 23 76 let port = 24 77 let doc = "Port to listen on" in
+7
config/Caddyfile
··· 1 + { 2 + debug 3 + } 4 + 5 + localhost:80 { 6 + php_fastcgi 127.0.0.1:9000 7 + }
+19 -50
lib/fastcgi.ml
··· 9 9 stderr:Eio.Flow.sink_ty Eio.Resource.t -> 10 10 Request.app_status 11 11 12 - (** [read_request_from_flow ~sw flow] reads a complete FastCGI request from flow. 13 - Processes BEGIN_REQUEST, PARAMS, STDIN, and DATA records until complete. 14 - Returns the populated request context. *) 15 - let read_request_from_flow ~sw:_ flow = 16 - let buf_read = Eio.Buf_read.of_flow flow ~max_size:1000000 in 17 - Request.read_request buf_read 18 12 19 13 (** [write_response ~sw request ~stdout ~stderr sink app_status] writes FastCGI response. 20 14 Reads from stdout and stderr flows, converts to FastCGI records, and writes to sink. ··· 55 49 56 50 write_response ~sw request ~stdout:stdout_source ~stderr:stderr_source sink app_status 57 51 58 - (** [process_request_with_flows ~sw request ~stdout ~stderr sink app_status] 59 - processes request using provided output flows. *) 60 - let process_request_with_flows ~sw request ~stdout ~stderr sink app_status = 61 - write_response ~sw request ~stdout ~stderr sink app_status 62 52 63 - (** {1 Connection Management} *) 64 - 65 - (** [handle_connection ~sw flow handler] handles complete FastCGI connection. 66 - Reads requests from flow, processes them with handler, multiplexes responses. 67 - Continues until connection is closed. *) 68 - let handle_connection ~sw flow handler = 69 - let rec loop () = 70 - try 71 - (* Read next request *) 72 - match read_request_from_flow ~sw flow with 73 - | Error msg -> 74 - (* Log error and continue or close connection *) 75 - Printf.eprintf "Error reading request: %s\n%!" msg 76 - | Ok request -> 77 - (* Process request *) 78 - let response_buf = Buffer.create 4096 in 79 - let response_sink = Eio.Flow.buffer_sink response_buf in 80 - 81 - process_request ~sw request handler response_sink; 82 - 83 - (* Write response to connection *) 84 - let response_data = Buffer.contents response_buf in 85 - Eio.Flow.copy (Eio.Flow.string_source response_data) flow; 86 - 87 - (* Continue if keep_conn is true *) 88 - if request.Request.keep_conn then 89 - loop () 90 - with 91 - | End_of_file -> () (* Connection closed *) 92 - | exn -> 93 - Printf.eprintf "Connection error: %s\n%!" (Printexc.to_string exn) 94 - in 95 - loop () 96 - 97 - (** [serve ~sw ~backlog ~port handler] creates FastCGI server. 98 - Listens on port, accepts connections, handles each with handler. *) 99 - let serve ~sw:_ ~backlog:_ ~port:_ _handler = 100 - (* This would typically use Eio.Net to create a listening socket *) 101 - (* For now, we'll provide a placeholder implementation *) 102 - failwith "serve: Implementation requires Eio.Net integration" 53 + let run ?max_connections ?additional_domains ?stop ~on_error socket handler = 54 + Eio.Net.run_server socket ?max_connections ?additional_domains ?stop ~on_error 55 + (fun socket peer_address -> 56 + Eio.Switch.run @@ fun sw -> 57 + Eio.traceln "%a: accept connection" Eio.Net.Sockaddr.pp peer_address; 58 + let input = Eio.Buf_read.of_flow ~max_size:max_int socket in 59 + try begin 60 + Eio.Buf_write.with_flow socket @@ fun output -> 61 + match Request.read_request input with 62 + | Error msg -> 63 + Eio.traceln "%a: failed to read request: %s" Eio.Net.Sockaddr.pp peer_address msg; 64 + Eio.Flow.close socket 65 + | Ok req -> 66 + Eio.traceln "%a: read request %a" Eio.Net.Sockaddr.pp peer_address Request.pp req; 67 + handler ~sw req output; 68 + end 69 + with Eio.Io (Eio.Net.E (Connection_reset _), _) -> 70 + Eio.traceln "%a: connection reset" Eio.Net.Sockaddr.pp peer_address 71 + )
+8 -31
lib/fastcgi.mli
··· 20 20 stderr:Eio.Flow.sink_ty Eio.Resource.t -> 21 21 Request.app_status 22 22 23 - (** [read_request_from_flow ~sw flow] reads a complete FastCGI request from flow. 24 - Processes BEGIN_REQUEST, PARAMS, STDIN, and DATA records until complete. 25 - Returns the populated request context. *) 26 - val read_request_from_flow : sw:Eio.Switch.t -> 'a Eio.Flow.source -> (Request.t, string) result 27 - 28 23 (** [write_response ~sw request ~stdout ~stderr sink app_status] writes FastCGI response. 29 24 Reads from stdout and stderr flows, converts to FastCGI records, and writes to sink. 30 25 Automatically handles stream termination and END_REQUEST. *) ··· 44 39 handler -> 45 40 Eio.Flow.sink_ty Eio.Resource.t -> unit 46 41 47 - (** [process_request_with_flows ~sw request ~stdout ~stderr sink app_status] 48 - processes request using provided output flows. *) 49 - val process_request_with_flows : 50 - sw:Eio.Switch.t -> 51 - Request.t -> 52 - stdout:'a Eio.Flow.source -> 53 - stderr:'a Eio.Flow.source -> 54 - 'a Eio.Flow.sink -> 55 - Request.app_status -> unit 56 - 57 - (** {1 Connection Management} *) 58 - 59 42 (** [handle_connection ~sw flow handler] handles complete FastCGI connection. 60 43 Reads requests from flow, processes them with handler, multiplexes responses. 61 44 Continues until connection is closed. *) 62 - val handle_connection : 63 - sw:Eio.Switch.t -> 64 - Eio.Flow.two_way_ty Eio.Resource.t -> 65 - handler -> 66 - unit 67 - 68 - (** [serve ~sw ~backlog ~port handler] creates FastCGI server. 69 - Listens on port, accepts connections, handles each with handler. *) 70 - val serve : 71 - sw:Eio.Switch.t -> 72 - backlog:int -> 73 - port:int -> 74 - handler -> 75 - unit 45 + val run : 46 + ?max_connections:int -> 47 + ?additional_domains:[> Eio.Domain_manager.ty ] Eio.Resource.t * 48 + int -> 49 + ?stop:'a Eio__core.Promise.t -> 50 + on_error:(exn -> unit) -> 51 + [> [> `Generic ] Eio.Net.listening_socket_ty ] Eio.Resource.t -> 52 + (sw:Eio.Switch.t -> Request.t -> Eio.Buf_write.t -> unit) -> 'a