mirror of
https://github.com/dunglas/frankenphp.git
synced 2025-09-26 19:41:13 +08:00
fix: concurrent env access (#1409)
This commit is contained in:

committed by
GitHub

parent
3ba4e257a1
commit
c57f741d83
@@ -716,3 +716,35 @@ func testSingleIniConfiguration(tester *caddytest.Tester, key string, value stri
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func TestOsEnv(t *testing.T) {
|
||||
os.Setenv("ENV1", "value1")
|
||||
os.Setenv("ENV2", "value2")
|
||||
tester := caddytest.NewTester(t)
|
||||
tester.InitServer(`
|
||||
{
|
||||
skip_install_trust
|
||||
admin localhost:2999
|
||||
http_port `+testPort+`
|
||||
|
||||
frankenphp {
|
||||
num_threads 2
|
||||
php_ini variables_order "EGPCS"
|
||||
worker ../testdata/env/env.php 1
|
||||
}
|
||||
}
|
||||
|
||||
localhost:`+testPort+` {
|
||||
route {
|
||||
root ../testdata
|
||||
php
|
||||
}
|
||||
}
|
||||
`, "caddyfile")
|
||||
|
||||
tester.AssertGetResponse(
|
||||
"http://localhost:"+testPort+"/env/env.php?keys[]=ENV1&keys[]=ENV2",
|
||||
http.StatusOK,
|
||||
"ENV1=value1,ENV2=value2",
|
||||
)
|
||||
}
|
||||
|
115
env.go
115
env.go
@@ -1,5 +1,9 @@
|
||||
package frankenphp
|
||||
|
||||
// #cgo nocallback frankenphp_init_persistent_string
|
||||
// #cgo nocallback frankenphp_add_assoc_str_ex
|
||||
// #cgo noescape frankenphp_init_persistent_string
|
||||
// #cgo noescape frankenphp_add_assoc_str_ex
|
||||
// #include "frankenphp.h"
|
||||
import "C"
|
||||
import (
|
||||
@@ -8,67 +12,106 @@ import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func initializeEnv() map[string]*C.zend_string {
|
||||
env := os.Environ()
|
||||
envMap := make(map[string]*C.zend_string, len(env))
|
||||
|
||||
for _, envVar := range env {
|
||||
key, val, _ := strings.Cut(envVar, "=")
|
||||
envMap[key] = C.frankenphp_init_persistent_string(toUnsafeChar(val), C.size_t(len(val)))
|
||||
}
|
||||
|
||||
return envMap
|
||||
}
|
||||
|
||||
// get the main thread env or the thread specific env
|
||||
func getSandboxedEnv(thread *phpThread) map[string]*C.zend_string {
|
||||
if thread.sandboxedEnv != nil {
|
||||
return thread.sandboxedEnv
|
||||
}
|
||||
|
||||
return mainThread.sandboxedEnv
|
||||
}
|
||||
|
||||
func clearSandboxedEnv(thread *phpThread) {
|
||||
if thread.sandboxedEnv == nil {
|
||||
return
|
||||
}
|
||||
|
||||
for key, val := range thread.sandboxedEnv {
|
||||
valInMainThread, ok := mainThread.sandboxedEnv[key]
|
||||
if !ok || val != valInMainThread {
|
||||
C.free(unsafe.Pointer(val))
|
||||
}
|
||||
}
|
||||
|
||||
thread.sandboxedEnv = nil
|
||||
}
|
||||
|
||||
// if an env var already exists, it needs to be freed
|
||||
func removeEnvFromThread(thread *phpThread, key string) {
|
||||
valueInThread, existsInThread := thread.sandboxedEnv[key]
|
||||
if !existsInThread {
|
||||
return
|
||||
}
|
||||
|
||||
valueInMainThread, ok := mainThread.sandboxedEnv[key]
|
||||
if !ok || valueInThread != valueInMainThread {
|
||||
C.free(unsafe.Pointer(valueInThread))
|
||||
}
|
||||
|
||||
delete(thread.sandboxedEnv, key)
|
||||
}
|
||||
|
||||
// copy the main thread env to the thread specific env
|
||||
func cloneSandboxedEnv(thread *phpThread) {
|
||||
if thread.sandboxedEnv != nil {
|
||||
return
|
||||
}
|
||||
thread.sandboxedEnv = make(map[string]*C.zend_string, len(mainThread.sandboxedEnv))
|
||||
for key, value := range mainThread.sandboxedEnv {
|
||||
thread.sandboxedEnv[key] = value
|
||||
}
|
||||
}
|
||||
|
||||
//export go_putenv
|
||||
func go_putenv(str *C.char, length C.int) C.bool {
|
||||
func go_putenv(threadIndex C.uintptr_t, str *C.char, length C.int) C.bool {
|
||||
thread := phpThreads[threadIndex]
|
||||
envString := C.GoStringN(str, length)
|
||||
cloneSandboxedEnv(thread)
|
||||
|
||||
// Check if '=' is present in the string
|
||||
if key, val, found := strings.Cut(envString, "="); found {
|
||||
removeEnvFromThread(thread, key)
|
||||
thread.sandboxedEnv[key] = C.frankenphp_init_persistent_string(toUnsafeChar(val), C.size_t(len(val)))
|
||||
return os.Setenv(key, val) == nil
|
||||
}
|
||||
|
||||
// No '=', unset the environment variable
|
||||
removeEnvFromThread(thread, envString)
|
||||
return os.Unsetenv(envString) == nil
|
||||
}
|
||||
|
||||
//export go_getfullenv
|
||||
func go_getfullenv(threadIndex C.uintptr_t) (*C.go_string, C.size_t) {
|
||||
func go_getfullenv(threadIndex C.uintptr_t, trackVarsArray *C.zval) {
|
||||
thread := phpThreads[threadIndex]
|
||||
env := getSandboxedEnv(thread)
|
||||
|
||||
env := os.Environ()
|
||||
goStrings := make([]C.go_string, len(env)*2)
|
||||
|
||||
for i, envVar := range env {
|
||||
key, val, _ := strings.Cut(envVar, "=")
|
||||
goStrings[i*2] = C.go_string{C.size_t(len(key)), thread.pinString(key)}
|
||||
goStrings[i*2+1] = C.go_string{C.size_t(len(val)), thread.pinString(val)}
|
||||
for key, val := range env {
|
||||
C.frankenphp_add_assoc_str_ex(trackVarsArray, toUnsafeChar(key), C.size_t(len(key)), val)
|
||||
}
|
||||
|
||||
value := unsafe.SliceData(goStrings)
|
||||
thread.Pin(value)
|
||||
|
||||
return value, C.size_t(len(env))
|
||||
}
|
||||
|
||||
//export go_getenv
|
||||
func go_getenv(threadIndex C.uintptr_t, name *C.go_string) (C.bool, *C.go_string) {
|
||||
func go_getenv(threadIndex C.uintptr_t, name *C.char) (C.bool, *C.zend_string) {
|
||||
thread := phpThreads[threadIndex]
|
||||
|
||||
// Create a byte slice from C string with a specified length
|
||||
envName := C.GoStringN(name.data, C.int(name.len))
|
||||
|
||||
// Get the environment variable value
|
||||
envValue, exists := os.LookupEnv(envName)
|
||||
envValue, exists := getSandboxedEnv(thread)[C.GoString(name)]
|
||||
if !exists {
|
||||
// Environment variable does not exist
|
||||
return false, nil // Return 0 to indicate failure
|
||||
}
|
||||
|
||||
// Convert Go string to C string
|
||||
value := &C.go_string{C.size_t(len(envValue)), thread.pinString(envValue)}
|
||||
thread.Pin(value)
|
||||
|
||||
return true, value // Return 1 to indicate success
|
||||
}
|
||||
|
||||
//export go_sapi_getenv
|
||||
func go_sapi_getenv(threadIndex C.uintptr_t, name *C.go_string) *C.char {
|
||||
envName := C.GoStringN(name.data, C.int(name.len))
|
||||
|
||||
envValue, exists := os.LookupEnv(envName)
|
||||
if !exists {
|
||||
return nil
|
||||
}
|
||||
|
||||
return phpThreads[threadIndex].pinCString(envValue)
|
||||
return true, envValue // Return 1 to indicate success
|
||||
}
|
||||
|
49
frankenphp.c
49
frankenphp.c
@@ -160,18 +160,12 @@ static void frankenphp_worker_request_shutdown() {
|
||||
}
|
||||
|
||||
PHPAPI void get_full_env(zval *track_vars_array) {
|
||||
struct go_getfullenv_return full_env = go_getfullenv(thread_index);
|
||||
go_getfullenv(thread_index, track_vars_array);
|
||||
}
|
||||
|
||||
for (int i = 0; i < full_env.r1; i++) {
|
||||
go_string key = full_env.r0[i * 2];
|
||||
go_string val = full_env.r0[i * 2 + 1];
|
||||
|
||||
// create PHP string for the value
|
||||
zend_string *val_str = zend_string_init(val.data, val.len, 0);
|
||||
|
||||
// add to the associative array
|
||||
add_assoc_str_ex(track_vars_array, key.data, key.len, val_str);
|
||||
}
|
||||
void frankenphp_add_assoc_str_ex(zval *track_vars_array, char *key,
|
||||
size_t keylen, zend_string *val) {
|
||||
add_assoc_str_ex(track_vars_array, key, keylen, val);
|
||||
}
|
||||
|
||||
/* Adapted from php_request_startup() */
|
||||
@@ -219,8 +213,20 @@ static int frankenphp_worker_request_startup() {
|
||||
|
||||
php_hash_environment();
|
||||
|
||||
/* zend_is_auto_global will force a re-import of the $_SERVER global */
|
||||
zend_is_auto_global(ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_SERVER));
|
||||
|
||||
/* disarm the $_ENV auto_global to prevent it from being reloaded in worker
|
||||
* mode */
|
||||
if (zend_hash_str_exists(&EG(symbol_table), "_ENV", 4)) {
|
||||
zend_auto_global *env_global;
|
||||
if ((env_global = zend_hash_find_ptr(
|
||||
CG(auto_globals), ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_ENV))) !=
|
||||
NULL) {
|
||||
env_global->armed = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Unfinish the request */
|
||||
frankenphp_server_context *ctx = SG(server_context);
|
||||
ctx->finished = false;
|
||||
@@ -282,7 +288,7 @@ PHP_FUNCTION(frankenphp_putenv) {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
if (go_putenv(setting, (int)setting_len)) {
|
||||
if (go_putenv(thread_index, setting, (int)setting_len)) {
|
||||
RETURN_TRUE;
|
||||
} else {
|
||||
RETURN_FALSE;
|
||||
@@ -308,13 +314,11 @@ PHP_FUNCTION(frankenphp_getenv) {
|
||||
return;
|
||||
}
|
||||
|
||||
go_string gname = {name_len, name};
|
||||
|
||||
struct go_getenv_return result = go_getenv(thread_index, &gname);
|
||||
struct go_getenv_return result = go_getenv(thread_index, name);
|
||||
|
||||
if (result.r0) {
|
||||
// Return the single environment variable as a string
|
||||
RETVAL_STRINGL(result.r1->data, result.r1->len);
|
||||
RETVAL_STR(result.r1);
|
||||
} else {
|
||||
// Environment variable does not exist
|
||||
RETVAL_FALSE;
|
||||
@@ -748,6 +752,7 @@ void frankenphp_register_bulk(
|
||||
zend_string *frankenphp_init_persistent_string(const char *string, size_t len) {
|
||||
/* persistent strings will be ignored by the GC at the end of a request */
|
||||
zend_string *z_string = zend_string_init(string, len, 1);
|
||||
zend_string_hash_val(z_string);
|
||||
|
||||
/* interned strings will not be ref counted by the GC */
|
||||
GC_ADD_FLAGS(z_string, IS_STR_INTERNED);
|
||||
@@ -755,10 +760,6 @@ zend_string *frankenphp_init_persistent_string(const char *string, size_t len) {
|
||||
return z_string;
|
||||
}
|
||||
|
||||
void frankenphp_release_zend_string(zend_string *z_string) {
|
||||
zend_string_release(z_string);
|
||||
}
|
||||
|
||||
static void
|
||||
frankenphp_register_variable_from_request_info(zend_string *zKey, char *value,
|
||||
bool must_be_present,
|
||||
@@ -844,9 +845,13 @@ static void frankenphp_log_message(const char *message, int syslog_type_int) {
|
||||
}
|
||||
|
||||
static char *frankenphp_getenv(const char *name, size_t name_len) {
|
||||
go_string gname = {name_len, (char *)name};
|
||||
struct go_getenv_return result = go_getenv(thread_index, (char *)name);
|
||||
|
||||
return go_sapi_getenv(thread_index, &gname);
|
||||
if (result.r0) {
|
||||
return result.r1->val;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
sapi_module_struct frankenphp_sapi_module = {
|
||||
|
@@ -69,9 +69,10 @@ void frankenphp_register_variables_from_request_info(
|
||||
void frankenphp_register_variable_safe(char *key, char *var, size_t val_len,
|
||||
zval *track_vars_array);
|
||||
zend_string *frankenphp_init_persistent_string(const char *string, size_t len);
|
||||
void frankenphp_release_zend_string(zend_string *z_string);
|
||||
int frankenphp_reset_opcache(void);
|
||||
int frankenphp_get_current_memory_limit();
|
||||
void frankenphp_add_assoc_str_ex(zval *track_vars_array, char *key,
|
||||
size_t keylen, zend_string *val);
|
||||
|
||||
void frankenphp_register_single(zend_string *z_key, char *value, size_t val_len,
|
||||
zval *track_vars_array);
|
||||
|
@@ -45,6 +45,7 @@ type testOptions struct {
|
||||
realServer bool
|
||||
logger *zap.Logger
|
||||
initOpts []frankenphp.Option
|
||||
phpIni map[string]string
|
||||
}
|
||||
|
||||
func runTest(t *testing.T, test func(func(http.ResponseWriter, *http.Request), *httptest.Server, int), opts *testOptions) {
|
||||
@@ -67,6 +68,9 @@ func runTest(t *testing.T, test func(func(http.ResponseWriter, *http.Request), *
|
||||
initOpts = append(initOpts, frankenphp.WithWorkers(testDataDir+opts.workerScript, opts.nbWorkers, opts.env, opts.watch))
|
||||
}
|
||||
initOpts = append(initOpts, opts.initOpts...)
|
||||
if opts.phpIni != nil {
|
||||
initOpts = append(initOpts, frankenphp.WithPhpIni(opts.phpIni))
|
||||
}
|
||||
|
||||
err := frankenphp.Init(initOpts...)
|
||||
require.Nil(t, err)
|
||||
@@ -671,13 +675,13 @@ func TestEnv(t *testing.T) {
|
||||
testEnv(t, &testOptions{})
|
||||
}
|
||||
func TestEnvWorker(t *testing.T) {
|
||||
testEnv(t, &testOptions{workerScript: "test-env.php"})
|
||||
testEnv(t, &testOptions{workerScript: "env/test-env.php"})
|
||||
}
|
||||
func testEnv(t *testing.T, opts *testOptions) {
|
||||
assert.NoError(t, os.Setenv("EMPTY", ""))
|
||||
|
||||
runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) {
|
||||
req := httptest.NewRequest("GET", fmt.Sprintf("http://example.com/test-env.php?var=%d", i), nil)
|
||||
req := httptest.NewRequest("GET", fmt.Sprintf("http://example.com/env/test-env.php?var=%d", i), nil)
|
||||
w := httptest.NewRecorder()
|
||||
handler(w, req)
|
||||
|
||||
@@ -685,7 +689,7 @@ func testEnv(t *testing.T, opts *testOptions) {
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
|
||||
// execute the script as regular php script
|
||||
cmd := exec.Command("php", "testdata/test-env.php", strconv.Itoa(i))
|
||||
cmd := exec.Command("php", "testdata/env/test-env.php", strconv.Itoa(i))
|
||||
stdoutStderr, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
// php is not installed or other issue, use the hardcoded output below:
|
||||
@@ -696,6 +700,46 @@ func testEnv(t *testing.T, opts *testOptions) {
|
||||
}, opts)
|
||||
}
|
||||
|
||||
func TestEnvIsResetInNonWorkerMode(t *testing.T) {
|
||||
assert.NoError(t, os.Setenv("test", ""))
|
||||
runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) {
|
||||
putResult := fetchBody("GET", fmt.Sprintf("http://example.com/env/putenv.php?key=test&put=%d", i), handler)
|
||||
|
||||
assert.Equal(t, fmt.Sprintf("test=%d", i), putResult, "putenv and then echo getenv")
|
||||
|
||||
getResult := fetchBody("GET", "http://example.com/env/putenv.php?key=test", handler)
|
||||
|
||||
assert.Equal(t, "test=", getResult, "putenv should be reset across requests")
|
||||
}, &testOptions{})
|
||||
}
|
||||
|
||||
// TODO: should it actually get reset in worker mode?
|
||||
func TestEnvIsNotResetInWorkerMode(t *testing.T) {
|
||||
assert.NoError(t, os.Setenv("index", ""))
|
||||
runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) {
|
||||
putResult := fetchBody("GET", fmt.Sprintf("http://example.com/env/remember-env.php?index=%d", i), handler)
|
||||
|
||||
assert.Equal(t, "success", putResult, "putenv and then echo getenv")
|
||||
|
||||
getResult := fetchBody("GET", "http://example.com/env/remember-env.php", handler)
|
||||
|
||||
assert.Equal(t, "success", getResult, "putenv should not be reset across worker requests")
|
||||
}, &testOptions{workerScript: "env/remember-env.php"})
|
||||
}
|
||||
|
||||
// reproduction of https://github.com/dunglas/frankenphp/issues/1061
|
||||
func TestModificationsToEnvPersistAcrossRequests(t *testing.T) {
|
||||
runTest(t, func(handler func(http.ResponseWriter, *http.Request), _ *httptest.Server, i int) {
|
||||
for j := 0; j < 3; j++ {
|
||||
result := fetchBody("GET", "http://example.com/env/overwrite-env.php", handler)
|
||||
assert.Equal(t, "custom_value", result, "a var directly added to $_ENV should persist")
|
||||
}
|
||||
}, &testOptions{
|
||||
workerScript: "env/overwrite-env.php",
|
||||
phpIni: map[string]string{"variables_order": "EGPCS"},
|
||||
})
|
||||
}
|
||||
|
||||
func TestFileUpload_module(t *testing.T) { testFileUpload(t, &testOptions{}) }
|
||||
func TestFileUpload_worker(t *testing.T) {
|
||||
testFileUpload(t, &testOptions{workerScript: "file-upload.php"})
|
||||
|
@@ -27,6 +27,7 @@ type phpMainThread struct {
|
||||
phpIni map[string]string
|
||||
commonHeaders map[string]*C.zend_string
|
||||
knownServerKeys map[string]*C.zend_string
|
||||
sandboxedEnv map[string]*C.zend_string
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -39,11 +40,12 @@ var (
|
||||
// and reserves a fixed number of possible PHP threads
|
||||
func initPHPThreads(numThreads int, numMaxThreads int, phpIni map[string]string) (*phpMainThread, error) {
|
||||
mainThread = &phpMainThread{
|
||||
state: newThreadState(),
|
||||
done: make(chan struct{}),
|
||||
numThreads: numThreads,
|
||||
maxThreads: numMaxThreads,
|
||||
phpIni: phpIni,
|
||||
state: newThreadState(),
|
||||
done: make(chan struct{}),
|
||||
numThreads: numThreads,
|
||||
maxThreads: numMaxThreads,
|
||||
phpIni: phpIni,
|
||||
sandboxedEnv: initializeEnv(),
|
||||
}
|
||||
|
||||
// initialize the first thread
|
||||
|
13
phpthread.go
13
phpthread.go
@@ -16,12 +16,13 @@ import (
|
||||
// identified by the index in the phpThreads slice
|
||||
type phpThread struct {
|
||||
runtime.Pinner
|
||||
threadIndex int
|
||||
requestChan chan *http.Request
|
||||
drainChan chan struct{}
|
||||
handlerMu sync.Mutex
|
||||
handler threadHandler
|
||||
state *threadState
|
||||
threadIndex int
|
||||
requestChan chan *http.Request
|
||||
drainChan chan struct{}
|
||||
handlerMu sync.Mutex
|
||||
handler threadHandler
|
||||
state *threadState
|
||||
sandboxedEnv map[string]*C.zend_string
|
||||
}
|
||||
|
||||
// interface that defines how the callbacks from the C thread should be handled
|
||||
|
10
testdata/env/env.php
vendored
Normal file
10
testdata/env/env.php
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__ . '/../_executor.php';
|
||||
|
||||
return function () use (&$rememberedKey) {
|
||||
$keys = $_GET['keys'];
|
||||
|
||||
// echoes ENV1=value1,ENV2=value2
|
||||
echo join(',', array_map(fn($key) => "$key=" . $_ENV[$key], $keys));
|
||||
};
|
3
testdata/env/import-env.php
vendored
Normal file
3
testdata/env/import-env.php
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
<?php
|
||||
|
||||
return $_ENV['custom_key'];
|
12
testdata/env/overwrite-env.php
vendored
Normal file
12
testdata/env/overwrite-env.php
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__.'/../_executor.php';
|
||||
|
||||
// modify $_ENV in the global symbol table
|
||||
// the modification should persist through the worker's lifetime
|
||||
$_ENV['custom_key'] = 'custom_value';
|
||||
|
||||
return function () use (&$rememberedIndex) {
|
||||
$custom_key = require __DIR__.'/import-env.php';
|
||||
echo $custom_key;
|
||||
};
|
17
testdata/env/putenv.php
vendored
Normal file
17
testdata/env/putenv.php
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__.'/../_executor.php';
|
||||
|
||||
return function () use (&$rememberedKey) {
|
||||
$key = $_GET['key'];
|
||||
$put = $_GET['put'] ?? null;
|
||||
|
||||
if(isset($put)){
|
||||
putenv("$key=$put");
|
||||
}
|
||||
|
||||
$get = getenv($key);
|
||||
$asStr = $get === false ? '' : $get;
|
||||
|
||||
echo "$key=$asStr";
|
||||
};
|
20
testdata/env/remember-env.php
vendored
Normal file
20
testdata/env/remember-env.php
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__.'/../_executor.php';
|
||||
|
||||
$rememberedIndex = 0;
|
||||
|
||||
return function () use (&$rememberedIndex) {
|
||||
$indexFromRequest = $_GET['index'] ?? null;
|
||||
if(isset($indexFromRequest)){
|
||||
$rememberedIndex = (int)$indexFromRequest;
|
||||
putenv("index=$rememberedIndex");
|
||||
}
|
||||
|
||||
$indexInEnv = (int)getenv('index');
|
||||
if($indexInEnv === $rememberedIndex){
|
||||
echo 'success';
|
||||
return;
|
||||
}
|
||||
echo "failure: '$indexInEnv' is not '$rememberedIndex'";
|
||||
};
|
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
require_once __DIR__.'/_executor.php';
|
||||
require_once __DIR__.'/../_executor.php';
|
||||
|
||||
return function() {
|
||||
$var = 'MY_VAR_' . ($_GET['var'] ?? '');
|
@@ -61,6 +61,9 @@ func (handler *regularThread) name() string {
|
||||
}
|
||||
|
||||
func (handler *regularThread) waitForRequest() string {
|
||||
// clear any previously sandboxed env
|
||||
clearSandboxedEnv(handler.thread)
|
||||
|
||||
handler.state.markAsWaiting(true)
|
||||
|
||||
var r *http.Request
|
||||
|
@@ -99,6 +99,7 @@ func setupWorkerScript(handler *workerThread, worker *worker) {
|
||||
}
|
||||
|
||||
handler.fakeRequest = r
|
||||
clearSandboxedEnv(handler.thread)
|
||||
if c := logger.Check(zapcore.DebugLevel, "starting"); c != nil {
|
||||
c.Write(zap.String("worker", worker.fileName), zap.Int("thread", handler.thread.threadIndex))
|
||||
}
|
||||
|
Reference in New Issue
Block a user