123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550 |
- #include "pyutils.h"
-
- void pyinit()
- {
- char *venv_path;
- PyObject *sitemod, *mainfun, *wsgi;
-
-
- if( (venv_path = getenv("VIRTUAL_ENV")) )
- {
- setenv("PYTHONHOME", venv_path, 1);
- swprintf(PyFCGI_conf.context.venv_path, PATH_MAX, L"%s",
- venv_path);
- Py_SetPythonHome(PyFCGI_conf.context.venv_path);
- pyfcgi_log(LOG_INFO, "Virtualenv found : '%s'",
- venv_path);
-
- swprintf(PyFCGI_conf.context.python_path, PATH_MAX,
- L"%s/bin/python3", venv_path);
- Py_SetProgramName(PyFCGI_conf.context.python_path);
- }
-
- Py_Initialize();
- sitemod = PyImport_ImportModule("site");
- mainfun = PyObject_GetAttrString(sitemod, "main");
- PyObject_CallObject(mainfun, NULL);
-
- //Append "." to sys.path
- sitemod = PySys_GetObject("path");
- PyList_Append(sitemod, PyUnicode_FromString("."));
-
- //Initialize the wsgi PEP333 dict
- wsgi = PyFCGI_conf.context.wsgi_dict = PyDict_New();
- PyDict_SetItemString(wsgi, "wsgi.version", Py_BuildValue("ii", 1,0));
-
- PyDict_SetItemString(wsgi, "wsgi.multithread", Py_False);
- PyDict_SetItemString(wsgi, "wsgi.multiprocess", Py_True);
- PyDict_SetItemString(wsgi, "wsgi.run_once", Py_False);
- }
-
- void update_python_path()
- {
- wchar_t *ppath, *wcwd, *wtmp;
- char *cwd, *ncwd, *err_fmt;
- size_t wcwd_sz, ppath_sz;
- int err;
-
- // Add a ':' in front of CWD and convert to wchar_t*
- cwd = get_current_dir_name();
- if(!cwd)
- {
- err = errno;
- err_fmt = "Unable to fecth CWD : %s";
- goto update_python_path_err;
- }
- ncwd = malloc(sizeof(char) * (strlen(cwd) + 2));
- if(!ncwd)
- {
- err = errno;
- err_fmt = "Unable to allocate memory for new CWD : %s";
- goto update_python_path_err_cwd;
- }
- ncwd[0] = ':';
- strcpy(ncwd+1, cwd);
- free(cwd);
- cwd = ncwd;
-
- wcwd_sz = mbstowcs(NULL, cwd, 0);
- if(wcwd_sz == (size_t)-1)
- {
- err = errno;
- err_fmt = "Unable to convert CWD to wchar : %s";
- goto update_python_path_err_cwd;
- }
- wcwd_sz++;
- wcwd = malloc(sizeof(wchar_t) * wcwd_sz);
- if(!wcwd)
- {
- err = errno;
- err_fmt = "Unable to allocate wchar for CWD : %s";
- goto update_python_path_err_cwd;
-
- }
- if(mbstowcs(wcwd, cwd, wcwd_sz) == -1)
- {
- err = errno;
- err_fmt = "Unable to convert CWD to wchar : %s";
- goto update_python_path_err_wcwd;
- }
-
- // Fetch, dup & update the python path
- ppath = Py_GetPath();
- if(!ppath)
- {
- if(PyErr_Occurred())
- {
- log_expt(LOG_ALERT);
- }
- else
- {
- pyfcgi_log(LOG_ALERT, "Unable to fetch python path, got NULL.");
- }
- err_fmt = NULL;
- err = 0;
- goto update_python_path_err_wcwd;
- }
- ppath = wcsdup(ppath);
- dprintf(2, "%ls\n", ppath);
- if(!wcwd)
- {
- err = errno;
- err_fmt = "Unable to dup the python PATH : %s";
- goto update_python_path_err_wcwd;
- }
-
- ppath_sz = wcslen(ppath);
- wtmp = realloc(ppath, sizeof(wchar_t) * (ppath_sz + wcwd_sz + 1));
- if(!wtmp)
- {
- err = errno;
- err_fmt = "Unable reallocate new python path : %s";
- goto update_python_path_err_ppath;
- }
- ppath = wtmp;
- wcsncpy(ppath+ppath_sz, wcwd, wcwd_sz);
- dprintf(2, "%ls\n", ppath);
- Py_SetPath(ppath);
-
- free(ppath);
- free(wcwd);
- free(cwd);
-
- return;
-
- update_python_path_err_ppath:
- free(ppath);
- update_python_path_err_wcwd:
- free(wcwd);
- update_python_path_err_cwd:
- free(cwd);
- update_python_path_err:
- if(err_fmt)
- {
- pyfcgi_log( LOG_ALERT, err_fmt, strerror(err));
- }
- exit(err);
- }
-
- static PyObject* _fetch_pyflush(const char *fdname)
- {
- PyObject *pyfd, *pyflush;
- pyfd = PySys_GetObject(fdname);
- if(!pyfd)
- {
- pyfcgi_log(LOG_ALERT, "Unable to fetch sys.%s", fdname);
- log_expt(LOG_ALERT);
- Py_Exit(EXIT_PYERR);
- }
- pyflush = PyObject_GetAttrString(pyfd, "flush");
- Py_DECREF(pyfd);
- if(!pyflush)
- {
- pyfcgi_log(LOG_ALERT, "Unable to fetch sys.%s.flush", fdname);
- log_expt(LOG_ALERT);
- Py_Exit(EXIT_PYERR);
- }
- if(!PyCallable_Check(pyflush))
- {
- pyfcgi_log(LOG_ALERT, "sys.%s.flush is not callable !",
- fdname);
- Py_Exit(EXIT_PYERR);
- }
-
- return pyflush;
- }
-
- void fetch_pyflush(PyObject** pystdout_flush, PyObject** pystderr_flush)
- {
- *pystdout_flush = _fetch_pyflush("stdout");
- *pystderr_flush = _fetch_pyflush("stderr");
- }
-
- void update_python_fd(int pipe_out[2], int pipe_err[2])
- {
- int pri, err;
- char *err_fmt;
- PyObject *os_mod, *pyfdopen, *args, *new_fd;
-
- pri = LOG_ALERT;
-
- if(pipe2(pipe_out, O_DIRECT) == -1)
- {
- err = errno;
- err_fmt = "Unable to create pipe for python stdout : %s";
- goto update_python_fd_err;
- }
- if(pipe2(pipe_err, O_DIRECT) == -1)
- {
- err = errno;
- err_fmt = "Unable to create pipe for python stderr : %s";
- goto update_python_fd_err_pipeout;
- }
-
- os_mod = PyImport_ImportModule("os");
- if(!os_mod)
- {
- if(PyErr_Occurred())
- {
- log_expt(LOG_ALERT);
- }
- else
- {
- pyfcgi_log( LOG_ALERT,
- "Unable to import python os module, got NULL.");
- }
- err_fmt = NULL;
- goto update_python_fd_err_pipes;
- }
- pyfdopen = PyObject_GetAttrString(os_mod, "fdopen");
- Py_DECREF(os_mod);
- if(!pyfdopen)
- {
- if(PyErr_Occurred())
- {
- log_expt(LOG_ALERT);
- }
- else
- {
- pyfcgi_log( LOG_ALERT,
- "Unable to fetch os.fdopen() , got NULL.");
- }
- err_fmt = NULL;
- goto update_python_fd_err_pipes;
- }
-
- args = Py_BuildValue("is", pipe_out[1], "w");
- if(!args)
- {
- pyfcgi_log( LOG_ERR, "Error building values with '%d', '%s' for stdout",
- pipe_out[1], "w");
- log_expt(LOG_ALERT);
- err_fmt = NULL;
- goto update_python_fd_err_fdopen;
- }
- new_fd = PyObject_CallObject(pyfdopen, args);
- if(!new_fd || PyErr_Occurred())
- {
- pyfcgi_log( LOG_ERR, "Error calling fdopen(%d, '%s')",
- pipe_out[1], "w");
- log_expt(LOG_ALERT);
- err_fmt = NULL;
- goto update_python_fd_err_args;
- }
- Py_DECREF(args);
- if(PySys_SetObject("stdout", new_fd))
- {
- pyfcgi_log(LOG_ERR, "Unable to set sys.stdout");
- log_expt(LOG_ALERT);
- goto update_python_fd_err_newfd;
- }
- Py_DECREF(new_fd);
-
- args = Py_BuildValue("is", pipe_err[1], "w");
- if(!args)
- {
- pyfcgi_log( LOG_ERR, "Error building values with '%d', '%s' for stderr",
- pipe_out[1], "w");
- log_expt(LOG_ALERT);
- err_fmt = NULL;
- goto update_python_fd_err_fdopen;
- }
- new_fd = PyObject_CallObject(pyfdopen, args);
- if(!new_fd || PyErr_Occurred())
- {
- pyfcgi_log( LOG_ERR, "Error calling fdopen(%d, '%s')",
- pipe_out[1], "w");
- log_expt(LOG_ALERT);
- err_fmt = NULL;
- goto update_python_fd_err_args;
- }
- Py_DECREF(args);
-
- PyDict_SetItemString(PyFCGI_conf.context.wsgi_dict, "wsgi.errors", new_fd);
-
- if(PySys_SetObject("stderr", new_fd))
- {
- pyfcgi_log(LOG_ERR, "Unable to set sys.stderr");
- log_expt(LOG_ALERT);
- goto update_python_fd_err_newfd;
- }
- Py_DECREF(new_fd);
-
- return;
-
- update_python_fd_err_newfd:
- Py_DECREF(new_fd);
- update_python_fd_err_args:
- Py_DECREF(args);
- update_python_fd_err_fdopen:
- Py_DECREF(fdopen);
- update_python_fd_err_pipes:
- close(pipe_err[0]);
- close(pipe_err[1]);
- update_python_fd_err_pipeout:
- close(pipe_out[0]);
- close(pipe_out[1]);
- update_python_fd_err:
- if(err_fmt)
- {
- pyfcgi_log(pri, err_fmt, strerror(err));
- }
- exit(1);
- }
-
-
- PyObject* update_pyenv(PyObject *py_osmod, char **environ)
- {
- PyObject *pyenv, *pykey, *pyval;
- char *key, *value, **cur;
-
- cur = environ;
-
- pyenv = PyObject_GetAttrString(py_osmod, "environ");
- if(!pyenv)
- {
- pyfcgi_log(LOG_WARNING, "Unable to get os.environ");
- log_expt(LOG_ALERT);
- }
- else
- {
- Py_DECREF(pyenv);
- }
- pyenv = PyDict_New();
-
-
-
- while(*cur)
- {
- key = value = *cur;
- while(*value && *value != '=')
- {
- value++;
- }
- if(!*value)
- {
- pyfcgi_log(LOG_WARNING, "Droping environment value without value : '%s'",
- key);
- cur++;
- continue;
- }
- value++;
- *(value-1) = '\0'; // dirty modification of **environ
- //pyfcgi_log(LOG_DEBUG, "PySetEnv '%s'='%s'", key, value);
- pykey = PyUnicode_DecodeLocale(key, "surrogateescape");
- if(!pykey)
- {
- *(value-1) = '='; // **environ restore
- pyfcgi_log(LOG_ALERT, "Unable to parse environ key string '%s'",
- key);
- log_expt(LOG_ALERT);
- Py_Exit(EXIT_PYERR);
- }
- *(value-1) = '='; // **environ restore
- pyval = PyUnicode_DecodeFSDefault(value);
- if(!pyval)
- {
- pyfcgi_log(LOG_ALERT, "Unable to parse environ val string '%s'",
- value);
- log_expt(LOG_ALERT);
- Py_Exit(EXIT_PYERR);
- }
- if(PyDict_SetItem(pyenv, pykey, pyval) == -1)
- {
- pyfcgi_log(LOG_ERR, "Unable to set environ '%s'='%s'",
- key, value);
- log_expt(LOG_ERR);
- }
- Py_DECREF(pyval);
- Py_DECREF(pykey);
- cur++;
- }
- /**@todo set given headers */
- PyDict_SetItemString(PyFCGI_conf.context.wsgi_dict, "wsgi.url_scheme",
- Py_BuildValue("U", "http"));
-
- PyDict_Update(pyenv, PyFCGI_conf.context.wsgi_dict);
- PyObject_SetAttrString(py_osmod, "environ", pyenv);
- /*//Debug print env on stderr
- PyObject* repr = PyObject_ASCII(pyenv);
- Py_INCREF(repr);
- dprintf(2, "%s\n", PyUnicode_AsUTF8(repr));
- Py_DECREF(repr);
- */
- return pyenv;
- }
-
- PyObject* import_entrypoint()
- {
- PyObject *entry_fname, *entry_module, *entry_fun;
- entry_fname = PyUnicode_DecodeFSDefault(PyFCGI_conf.py_entrymod);
- entry_module = PyImport_Import(entry_fname);
- Py_DECREF(entry_fname);
-
- if(!entry_module)
- {
- //TODO syslog python error / traceback
- pyfcgi_log(LOG_CRIT, "Unable to import python file '%s'",
- PyFCGI_conf.py_entrymod);
- //pyfcgi_log( LOG_INFO, "%s", getcwd(NULL, 256));
- log_expt(LOG_ERR);
- return NULL;
- }
-
- // getting entrypoint function
- entry_fun = PyObject_GetAttrString(entry_module, PyFCGI_conf.py_entryfun);
- Py_DECREF(entry_module);
-
- if(!entry_fun)
- {
- //TODO syslog python error / traceback
- pyfcgi_log(LOG_CRIT,
- "Unable to import object '%s' from '%s'",
- PyFCGI_conf.py_entryfun, PyFCGI_conf.py_entrymod);
- log_expt(LOG_ERR);
- return NULL;
- }
- if(!PyCallable_Check(entry_fun))
- {
- pyfcgi_log( LOG_CRIT,
- "When imported from '%s', '%s' was not a callable",
- PyFCGI_conf.py_entrymod, PyFCGI_conf.py_entryfun);
- return NULL;
- }
- return entry_fun;
- }
-
- PyObject* pyinit_libpyfcgi()
- {
- PyObject *module;
- if(libpyfcgi.self) { return libpyfcgi.self; }
-
- module = PyInit_libpyfcgi();
- if(module == NULL)
- {
- pyfcgi_log(LOG_ERR, "Unable to create libpyfcgi python module");
- return NULL;
- }
- libpyfcgi.self = module;
- if(PySys_SetObject("stdout", (PyObject*)libpyfcgi.stdio[0]))
- {
- pyfcgi_log(LOG_ERR, "Unable to set sys.stdout");
- log_expt(LOG_ALERT);
- return NULL;
- }
- if(PySys_SetObject("stderr", (PyObject*)libpyfcgi.stdio[1]))
- {
- pyfcgi_log(LOG_ERR, "Unable to set sys.stderr");
- log_expt(LOG_ALERT);
- return NULL;
- }
- return module;
- }
-
- PyObject* get_start_response()
- {
- pyinit_libpyfcgi();
- return PyObject_GetAttrString(libpyfcgi.self, "start_response");
- }
-
- void log_expt(int priority)
- {
- if(!PyErr_Occurred())
- {
- pyfcgi_log(priority, "No exception");
- return;
- }
-
- PyObject *expt, *expt_bytes, *expt_cls,
- *expt_val, *expt_type, *traceback,
- *tbmod, *tbfmt, *tbfmt_args, *tbstr, **lines;
- Py_ssize_t i, nlines;
- char *msg, *type, *val;
- int msg_sz;
- char msg_fmt[] = "%s: %s";
-
- PyErr_Fetch(&expt_cls, &expt, &traceback);
-
- // Fetching exception message using __str__()
- expt_val = PyObject_ASCII(expt);
- expt_bytes = PyUnicode_AsUTF8String(expt_val);
-
- msg = PyBytes_AsString(expt_bytes);
- val = strndup(msg, 1024); // TODO check out of mem if !val
-
- // Fetching exception class name
- expt_type = PyObject_GetAttrString(expt_cls, "__name__");
- expt_bytes = PyUnicode_AsUTF8String(expt_type);
- msg = PyBytes_AsString(expt_bytes);
- type = strndup(msg, 1024); // TODO check out of mem if !type
-
- msg_sz = snprintf(NULL, 0, msg_fmt, type, val);
- msg_sz++;
- msg = malloc(sizeof(char) * msg_sz);
- snprintf(msg, msg_sz, msg_fmt, type, val);
-
- pyfcgi_log(priority, msg);
-
- //Fetching & logging traceback
- tbmod = PyImport_ImportModule("traceback");
- tbfmt = PyObject_GetAttrString(tbmod, "format_tb");
- tbfmt_args = Py_BuildValue("(O)", traceback);
- tbstr = PyObject_CallObject(tbfmt, tbfmt_args);
- if(!tbstr)
- {
- pyfcgi_log(LOG_ALERT,"FAILS TO FOMAT");
- PyErr_Fetch(&expt_cls, &expt, &traceback);
- pyfcgi_log(LOG_ALERT, "%s", PyUnicode_AsUTF8(PyObject_ASCII(expt)));
- return;
- }
- nlines = PySequence_Fast_GET_SIZE(tbstr);
- lines = PySequence_Fast_ITEMS(tbstr);
- for(i=0; i<nlines; i++)
- {
- pyfcgi_log(priority, PyUnicode_AsUTF8(lines[i]));
- }
- Py_DECREF(tbmod);
- Py_DECREF(tbfmt);
- Py_DECREF(tbfmt_args);
- Py_DECREF(tbstr);
-
- }
-
- void pyfcgi_python_version(char version[16])
- {
- snprintf(version, 16, "%d.%d.%d", PY_MAJOR_VERSION, PY_MINOR_VERSION,
- PY_MICRO_VERSION);
- }
-
- PyObject* python_osmod()
- {
- PyObject *ret;
- ret = PyImport_ImportModule("os");
- if(!ret)
- {
- pyfcgi_log(LOG_ALERT, "Unable to import os module");
- log_expt(LOG_ALERT);
- Py_Exit(EXIT_PYERR);
- }
- return ret;
- }
|