1

I am using the Python C library and FastCGI to run code in a file and return the output to NGINX. The problem is PyRun_SimpleString outputs to stdout, which is fine for a CLI, but is ignored by FastCGI.

The code I tried was this:

#include <Python.h>
#include <string.h>
#include <fcgi_stdio.h>

int main() {
    Py_Initialize();

    while (FCGI_Accept() >= 0) {
        printf("Content-type: text/plain\r\n\r\n");
        PyRun_SimpleString("print('hey')");
    }

    Py_Finalize();

    return 0;
}

My NGINX config:

location / {
    fastcgi_pass unix:/tmp/sock-fcgi.sock;
    include fastcgi_params;
    fastcgi_param  REQUEST_URI $uri;
    fastcgi_param SCRIPT_FILENAME $request_filename;
}

The returned value (from both curling the NGINX server and cgi-fcgi -connect /tmp/sock-fcgi.sock ./COMPILED_FILE):

Content-type: text/plain

What I was expecting:

Content-type: text/plain

hey

EDIT: Running COMPILED_FILE without cgi-fcgi as you would run any other C programme outputs the expected values.

Sidney
  • 13
  • 4
  • The question does not make sense. In both traditional CGI and FastCGI, the standard output is the primary channel for CGI code to deliver response data to the web server. And that's where `printf` sends its output, so it looks like that's working for you. The issue might be that Python is sending its output somewhere else, but my guess would be that the embedded Python interpreter is not generating output at all. – John Bollinger May 25 '23 at 14:32
  • fcgi_stdio provides the `printf` function, as well as the other functions in the stdio header. – Sidney May 25 '23 at 14:34
  • Ok. Not exactly. It looks like fcgi_stdio *hijacks* the stdio function names by providing macros that redirect calls to its own replacement functions. For many purposes, that will look the same, but there are ways in which the differences will manifest. – John Bollinger May 25 '23 at 14:45
  • So, if you want to write FastCGI in Python, have you considered doing it natively instead of trying to use a Python interpreter embedded in a C program? See, for example, [Running python through fastCGI for nginx](https://stackoverflow.com/q/7048057/2402272). – John Bollinger May 25 '23 at 14:47
  • 1
    If you're stuck with the C wrapper and your particular fastCGI library, then your best bet may be to have your Python code return its output to C as a (Python) string instead of printing it directly. Let the C code then print the string. – John Bollinger May 25 '23 at 14:50
  • Or returning it as a `bytes` might be even easier. – John Bollinger May 25 '23 at 14:57
  • I have considered writing it separately, but embedding the Python in a C program is necessary because of other parts of the project already written in C such as some pre-processing. The issue with returning as a Python string is that the python code is taken directly from the user. A hijacked print function could be a solution, but it would need to support any number of print statements which may exist in the code and return them all correctly to C. The optimal solution could be to override Python's `sys.stdout` to something usable in C. – Sidney May 25 '23 at 14:57
  • 1
    If you don't control the Python code, then it is better in every way to run it in a separate process, preferably well sandboxed, and capture its output. You can then forward that output to the fastCGI library. I don't think it's feasible to get Python to write directly, because my take is that your fastCGI library relies on output *going through its functions*, not just going to the correct underlying sink. – John Bollinger May 25 '23 at 15:02
  • Of course, we are now approaching the point of *regular* CGI running under a fastCGI wrapper. – John Bollinger May 25 '23 at 15:09
  • Assuming the wrapper itself doesn't use the standard output file descriptor, it could dup it to the 'write' end of a pipe and send any data read from the 'read' end of the pipe to FastCGI's fake standard output. – Ian Abbott May 25 '23 at 16:03
  • Agreed, @IanAbbott, but this is where my inference comes in that the fastCGI server relies on output going through the functions it provides for the purpose, not just on output going to the correct device. Plus, this particular library does not appear to provide a supported interface by which the underlying output FD could be determined. – John Bollinger May 25 '23 at 16:44

0 Answers0