Calls 'update_request_info' from the C side.

This commit is contained in:
Alliballibaba
2025-08-03 14:47:57 +02:00
parent 9129024127
commit aea5064f87
3 changed files with 66 additions and 101 deletions
+51 -7
View File
@@ -21,6 +21,16 @@ import (
"github.com/dunglas/frankenphp/internal/phpheaders"
)
// Map of supported protocols to Apache ssl_mod format
// Note that these are slightly different from SupportedProtocols in caddytls/config.go
var tlsProtocolStrings = map[uint16]string{
tls.VersionTLS10: "TLSv1",
tls.VersionTLS11: "TLSv1.1",
tls.VersionTLS12: "TLSv1.2",
tls.VersionTLS13: "TLSv1.3",
}
// List of all keys in the $_SERVER array excluding headers and environment variables.
var knownServerKeys = []string{
"CONTENT_LENGTH",
"DOCUMENT_ROOT",
@@ -264,13 +274,47 @@ func splitPos(path string, splitPath []string) int {
return -1
}
// Map of supported protocols to Apache ssl_mod format
// Note that these are slightly different from SupportedProtocols in caddytls/config.go
var tlsProtocolStrings = map[uint16]string{
tls.VersionTLS10: "TLSv1",
tls.VersionTLS11: "TLSv1.1",
tls.VersionTLS12: "TLSv1.2",
tls.VersionTLS13: "TLSv1.3",
// update the sapi_request_info struct
// see: https://github.com/php/php-src/blob/345e04b619c3bc11ea17ee02cdecad6ae8ce5891/main/SAPI.h#L72
//
//export go_update_request_info
func go_update_request_info(threadIndex C.uintptr_t, info *C.sapi_request_info) {
thread := phpThreads[threadIndex]
fc := thread.getRequestContext()
request := fc.request
authUser, authPassword, ok := request.BasicAuth()
if ok && authPassword != "" {
info.auth_password = thread.pinCString(authPassword)
}
if ok && authUser != "" {
info.auth_user = thread.pinCString(authUser)
}
info.request_method = thread.pinCString(request.Method)
info.query_string = thread.pinCString(request.URL.RawQuery)
info.content_length = C.zend_long(request.ContentLength)
contentType := request.Header.Get("Content-Type")
if contentType != "" {
info.content_type = thread.pinCString(contentType)
}
if fc.pathInfo != "" {
info.path_translated = thread.pinCString(sanitizedPathJoin(fc.documentRoot, fc.pathInfo)) // Info: http://www.oreilly.com/openbook/cgi/ch02_04.html
}
info.request_uri = thread.pinCString(request.URL.RequestURI())
info.proto_num = C.int(request.ProtoMajor*1000 + request.ProtoMinor)
}
//export go_is_worker_request
func go_is_worker_request(threadIndex C.uintptr_t) C.bool {
thread := phpThreads[threadIndex]
fc := thread.getRequestContext()
return C.bool(fc.worker != nil)
}
// SanitizedPathJoin performs filepath.Join(root, reqPath) that
+15 -31
View File
@@ -75,6 +75,16 @@ __thread uintptr_t thread_index;
__thread bool is_worker_thread = false;
__thread zval *os_environment = NULL;
static void frankenphp_update_request_context(){
// update server context here ?
SG(server_context) = (void *)1;
// It is not reset by zend engine, set it to 200.
SG(sapi_headers).http_response_code = 200;
go_update_request_info(thread_index, &SG(request_info));
is_worker_thread = go_is_worker_request(thread_index);
}
static void frankenphp_free_request_context() {
if (SG(request_info).cookie_data != NULL) {
free(SG(request_info).cookie_data);
@@ -174,6 +184,8 @@ void frankenphp_add_assoc_str_ex(zval *track_vars_array, char *key,
static int frankenphp_worker_request_startup() {
int retval = SUCCESS;
frankenphp_update_request_context();
zend_try {
frankenphp_destroy_super_globals();
frankenphp_release_temporary_streams();
@@ -507,36 +519,8 @@ static void frankenphp_request_shutdown() {
zval_ptr_dtor_nogc(&PG(http_globals)[TRACK_VARS_ENV]);
array_init(&PG(http_globals)[TRACK_VARS_ENV]);
}
php_request_shutdown((void *)0);
frankenphp_free_request_context();
}
int frankenphp_update_server_context(bool is_worker_request,
const char *request_method,
char *query_string,
zend_long content_length,
char *path_translated, char *request_uri,
const char *content_type, char *auth_user,
char *auth_password, int proto_num) {
SG(server_context) = (void *)1;
is_worker_thread = is_worker_request;
// It is not reset by zend engine, set it to 200.
SG(sapi_headers).http_response_code = 200;
SG(request_info).auth_password = auth_password;
SG(request_info).auth_user = auth_user;
SG(request_info).request_method = request_method;
SG(request_info).query_string = query_string;
SG(request_info).content_type = content_type;
SG(request_info).content_length = content_length;
SG(request_info).path_translated = path_translated;
SG(request_info).request_uri = request_uri;
SG(request_info).proto_num = proto_num;
return SUCCESS;
php_request_shutdown((void *)0);
}
static int frankenphp_startup(sapi_module_struct *sapi_module) {
@@ -974,7 +958,8 @@ bool frankenphp_new_php_thread(uintptr_t thread_index) {
return true;
}
int frankenphp_request_startup() {
static int frankenphp_request_startup() {
frankenphp_update_request_context();
if (php_request_startup() == SUCCESS) {
return SUCCESS;
}
@@ -1014,7 +999,6 @@ int frankenphp_execute_script(char *file_name) {
zend_destroy_file_handle(&file_handle);
frankenphp_free_request_context();
frankenphp_request_shutdown();
return status;
-63
View File
@@ -12,8 +12,6 @@ package frankenphp
//
// We also set these flags for hardening: https://github.com/docker-library/php/blob/master/8.2/bookworm/zts/Dockerfile#L57-L59
// #cgo nocallback frankenphp_update_server_context
// #cgo noescape frankenphp_update_server_context
// #include <stdlib.h>
// #include <stdint.h>
// #include <php_variables.h>
@@ -32,7 +30,6 @@ import (
"os"
"os/signal"
"runtime"
"strconv"
"strings"
"sync"
"syscall"
@@ -317,66 +314,6 @@ func Shutdown() {
logger.Debug("FrankenPHP shut down")
}
func updateServerContext(thread *phpThread, fc *frankenPHPContext, isWorkerRequest bool) error {
request := fc.request
authUser, authPassword, ok := request.BasicAuth()
var cAuthUser, cAuthPassword *C.char
if ok && authPassword != "" {
cAuthPassword = thread.pinCString(authPassword)
}
if ok && authUser != "" {
cAuthUser = thread.pinCString(authUser)
}
cMethod := thread.pinCString(request.Method)
cQueryString := thread.pinCString(request.URL.RawQuery)
contentLengthStr := request.Header.Get("Content-Length")
contentLength := 0
if contentLengthStr != "" {
var err error
contentLength, err = strconv.Atoi(contentLengthStr)
if err != nil || contentLength < 0 {
return fmt.Errorf("invalid Content-Length header: %w", err)
}
}
contentType := request.Header.Get("Content-Type")
var cContentType *C.char
if contentType != "" {
cContentType = thread.pinCString(contentType)
}
// compliance with the CGI specification requires that
// PATH_TRANSLATED should only exist if PATH_INFO is defined.
// Info: https://www.ietf.org/rfc/rfc3875 Page 14
var cPathTranslated *C.char
if fc.pathInfo != "" {
cPathTranslated = thread.pinCString(sanitizedPathJoin(fc.documentRoot, fc.pathInfo)) // Info: http://www.oreilly.com/openbook/cgi/ch02_04.html
}
cRequestUri := thread.pinCString(request.URL.RequestURI())
ret := C.frankenphp_update_server_context(
C.bool(isWorkerRequest || fc.responseWriter == nil),
cMethod,
cQueryString,
C.zend_long(contentLength),
cPathTranslated,
cRequestUri,
cContentType,
cAuthUser,
cAuthPassword,
C.int(request.ProtoMajor*1000+request.ProtoMinor),
)
if ret > 0 {
return ErrRequestContextCreation
}
return nil
}
// ServeHTTP executes a PHP script according to the given context and options.
func ServeHTTP(responseWriter http.ResponseWriter, request *http.Request, opts ...RequestOption) error {
if !isRunning {