Browse Source

Enable python environnement update from FCGI context

Yann Weber 5 years ago
parent
commit
13258ee647
3 changed files with 123 additions and 8 deletions
  1. 3
    4
      foo.py
  2. 104
    4
      src/pyworker.c
  3. 16
    0
      src/pyworker.h

+ 3
- 4
foo.py View File

@@ -3,10 +3,9 @@ import os
3 3
 import time
4 4
 
5 5
 def entrypoint():
6
-	sys.stderr.write('Called ! req by %s' % os.getenv('REQUEST_METHOD'))
7
-	sys.stderr.flush()
6
+	import os
7
+	sys.stderr.write('Called ! req by %s' % os.getenv('REMOTE_ADDR'))
8 8
 	env = "foo"
9
-	env = ', '.join(os.environ.keys())
9
+	env = '<br/>'.join(["'%s'='%s'" % (k, os.environ[k]) for k in os.environ.keys()])
10 10
 	msg = "Content-Type: text/html\r\n\r\nHello world !(%0.2f)\nenv : %s" % (time.time(), env)
11 11
 	sys.stdout.write(msg)
12
-	sys.stdout.flush()

+ 104
- 4
src/pyworker.c View File

@@ -44,7 +44,8 @@ pid_t spawn(char* py_entrypoint, int wrk_id, int semid, int max_reqs)
44 44
 
45 45
 int work(char* py_entrypoint, int wrk_id, int semid, int max_reqs)
46 46
 {
47
-	PyObject *entry_fun, *pystdout_flush, *pystderr_flush;
47
+	PyObject *entry_fun, *pystdout_flush, *pystderr_flush,
48
+	         *py_setenv, *py_clrenv;
48 49
 	int count, pipe_out[2], pipe_err[2], pipe_ctl[2], err, piper_status;
49 50
 	struct sigaction act;
50 51
 	sigset_t emptyset;
@@ -74,7 +75,8 @@ int work(char* py_entrypoint, int wrk_id, int semid, int max_reqs)
74 75
 	fetch_pyflush(&pystdout_flush, &pystderr_flush);
75 76
 	syslog(	LOG_INFO,
76 77
 		"Worker[%d] Python started", wrk_id);
77
-
78
+	
79
+	get_py_setenv(&py_setenv, &py_clrenv);
78 80
 	// loading module
79 81
 	entry_fun = import_entrypoint(py_entrypoint);
80 82
 
@@ -116,7 +118,7 @@ int work(char* py_entrypoint, int wrk_id, int semid, int max_reqs)
116 118
 			//printf("Content-type: text/html\r\n\r\nHello world !\n");
117 119
 			exit(1);
118 120
 		}
119
-		//TODO : update environ !!!
121
+		update_pyenv(py_setenv, py_clrenv);
120 122
 		//TODO : check if pipe_ctl lock is really needed anymore
121 123
 		close(pipe_ctl[1]);
122 124
 		PyObject_CallObject(entry_fun, NULL);
@@ -144,7 +146,7 @@ syslog(LOG_DEBUG, "PIPER UNLOCK");
144 146
 		syslog(LOG_DEBUG, "Worker[%d] request %d END [OK]",
145 147
 			wrk_id, count);
146 148
 	}
147
-	exit(count == max_reqs ?0:42);
149
+	Py_Exit(count == max_reqs ?0:42);
148 150
 }
149 151
 
150 152
 void worker_piper(int wrk_id, int req_id, int pystdout, int pystderr,
@@ -574,6 +576,104 @@ update_python_fd_err:
574 576
 	exit(1);
575 577
 }
576 578
 
579
+
580
+void update_pyenv(PyObject *py_setenv, PyObject *py_clrenv)
581
+{
582
+	PyObject *args, *pykey, *pyval, *ret;
583
+	char *key, *value, **cur;
584
+
585
+	cur = environ;
586
+
587
+	PyObject_CallObject(py_clrenv, NULL); // call os.environ.clear()
588
+	while(*cur)
589
+	{
590
+		//key = value = strdup(*cur);
591
+		key = value = *cur;
592
+		while(*value && *value != '=')
593
+		{
594
+			value++;
595
+		}
596
+		if(!*value)
597
+		{
598
+			syslog(LOG_WARNING, "Droping environment value without value : '%s'",
599
+			       key);
600
+			cur++;
601
+			continue;
602
+		}
603
+		value++;
604
+		*(value-1) = '\0'; // dirty modification of **environ
605
+syslog(LOG_DEBUG, "PySetEnv '%s'='%s'", key, value);
606
+		pykey = PyUnicode_DecodeLocale(key, "surrogateescape");
607
+		if(!pykey)
608
+		{
609
+			*(value-1) = '='; // **environ restore
610
+			syslog(LOG_ALERT, "Unable to parse environ key string '%s'",
611
+			       key);
612
+			log_expt(LOG_ALERT);
613
+			Py_Exit(EXIT_PYERR);
614
+		}
615
+		*(value-1) = '='; // **environ restore
616
+		pyval = PyUnicode_DecodeLocale(value, "surrogateescape");
617
+		if(!pykey)
618
+		{
619
+			syslog(LOG_ALERT, "Unable to parse environ val string '%s'",
620
+			       value);
621
+			log_expt(LOG_ALERT);
622
+			Py_Exit(EXIT_PYERR);
623
+		}
624
+		args = Py_BuildValue("OO", pykey, pyval);
625
+		Py_DECREF(pyval);
626
+		Py_DECREF(pykey);
627
+		cur++;
628
+		ret = PyObject_CallObject(py_setenv, args);
629
+		if(ret)
630
+		{
631
+			Py_DECREF(ret);
632
+		}
633
+		if(PyErr_Occurred())
634
+		{
635
+			log_expt(LOG_WARNING);
636
+		}
637
+		//free(key);
638
+	}
639
+
640
+}
641
+
642
+void get_py_setenv(PyObject** pyenv_setitem, PyObject** pyenv_clear)
643
+{
644
+	PyObject *osmod, *pyenv;
645
+	osmod = PyImport_ImportModule("os");
646
+	if(!osmod)
647
+	{
648
+		syslog(LOG_ALERT, "Unable to import os module");
649
+		log_expt(LOG_ALERT);
650
+		Py_Exit(EXIT_PYERR);
651
+	}
652
+	pyenv = PyObject_GetAttrString(osmod, "environ");
653
+	if(!pyenv)
654
+	{
655
+		syslog(LOG_ALERT, "Unable to get os.environ");
656
+		log_expt(LOG_ALERT);
657
+		Py_Exit(EXIT_PYERR);
658
+	}
659
+	Py_DECREF(osmod);
660
+	*pyenv_setitem = PyObject_GetAttrString(pyenv, "__setitem__");
661
+	if(!*pyenv_setitem)
662
+	{
663
+		syslog(LOG_ALERT, "Unable to get os.environ.__setitem__");
664
+		log_expt(LOG_ALERT);
665
+		Py_Exit(EXIT_PYERR);
666
+	}
667
+	*pyenv_clear = PyObject_GetAttrString(pyenv, "clear");
668
+	if(!*pyenv_clear)
669
+	{
670
+		syslog(LOG_ALERT, "Unable to get os.environ.clear()");
671
+		log_expt(LOG_ALERT);
672
+		Py_Exit(EXIT_PYERR);
673
+	}
674
+	Py_DECREF(pyenv);
675
+}
676
+
577 677
 void log_expt(int priority)
578 678
 {
579 679
 	if(!PyErr_Occurred())

+ 16
- 0
src/pyworker.h View File

@@ -40,6 +40,8 @@
40 40
 #define WPIPER_SIG 30
41 41
 #define PYENTRY_FUNNAME "entrypoint"
42 42
 
43
+extern char **environ;
44
+
43 45
 typedef unsigned long int pywrkid_t;
44 46
 
45 47
 /**@brief Spawn a worker given an entrypoint
@@ -98,6 +100,20 @@ void update_python_path();
98 100
  */
99 101
 void update_python_fd(int[2], int[2]);
100 102
 
103
+/**@brief Update python sys.environ using current FCI environ
104
+ * @note For the moment do not delete unset variables only update
105
+ * from environ and add new one
106
+ * @param PyObject* os.environ.__setitem__
107
+ * @param PyObject* os.environ.clean
108
+ */
109
+void update_pyenv(PyObject*, PyObject*);
110
+
111
+/**@brief Fetch python os.environ.__setitem__ & os.environ.clear()
112
+ * @param PyObject** setitem
113
+ * @param PyObject** clear
114
+ */
115
+void get_py_setenv(PyObject**, PyObject**);
116
+
101 117
 void log_expt(int priority);
102 118
 
103 119
 #endif

Loading…
Cancel
Save