Skip to content

Instantly share code, notes, and snippets.

@win-t
Created July 6, 2020 04:58
Show Gist options
  • Save win-t/d41e7bae17f7d8b13c8874bfb50df30f to your computer and use it in GitHub Desktop.
Save win-t/d41e7bae17f7d8b13c8874bfb50df30f to your computer and use it in GitHub Desktop.

Revisions

  1. win-t created this gist Jul 6, 2020.
    103 changes: 103 additions & 0 deletions php simple proxy
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,103 @@
    <?php

    namespace main;

    define("BACKEND_SOCKET", '<where the unix socket>');
    define("BASE_URL", '<where this file located>');

    function exit_500($msg) {
    $msg = rtrim($msg, "\n") . "\nDebug trace:\n";
    foreach(debug_backtrace() as $trace) {
    if(isset($trace['file']) && isset($trace['line'])) {
    $msg .= '- ' . $trace['file'] . ':' . $trace['line'] . "\n";
    }
    }
    error_log(substr($msg, 0, 2048));
    if(!headers_sent()) {
    http_response_code(500);
    header('Content-Type: text/plain');
    $level = ob_get_level();
    for($i = 0; $i < $level; $i++) ob_end_clean();
    echo "500 Internal Server error\n\n$msg";
    }
    exit();
    }

    set_error_handler(function($no, $msg) { exit_500("error: level errno $no: msg: $msg"); });
    set_exception_handler(function($exception) { exit_500("exception: $exception"); });
    ini_set('display_errors', 0);
    error_reporting(0);

    $stat = stat(BACKEND_SOCKET);
    if(($stat !== FALSE) && (!(($stat['mode'] & 0170000) == 0140000))) {
    exit_500("gateway error: " . BACKEND_SOCKET . " is not a unix socket");
    }

    $method = strtoupper($_SERVER['REQUEST_METHOD']);

    $uri = isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : "/";
    if(isset($_SERVER['QUERY_STRING']) && strlen($_SERVER['QUERY_STRING']) > 0) {
    $uri .= "?{$_SERVER['QUERY_STRING']}";
    }

    $header_in = apache_request_headers();
    $header_tobe_removed = array(
    'connection', 'keep-alive', 'proxy-authenticate', 'proxy-authorization', 'proxy-connection'
    'te', 'trailer', 'transfer-encoding', 'upgrade',
    'host', 'x-real-ip', 'x-forwarded-for'
    );
    foreach($header_in as $k => $v) {
    if(strtolower($k) == 'connection') {
    foreach(explode(",", $v) as $h) array_push($header_tobe_removed, strtolower(trim($h)));
    }
    }

    $header_out = array();
    foreach($header_in as $k => $v) {
    if(!in_array(strtolower($k), $header_tobe_removed)) {
    array_push($header_out, "$k: $v");
    };
    }
    array_push($header_out, "Host: " . 'service');
    array_push($header_out, "X-Real-IP: " . $_SERVER['REMOTE_ADDR']);
    array_push($header_out, "X-Forwarded-For: " . $_SERVER['REMOTE_ADDR']);
    array_push($header_out, "X-Base-Url: " . BASE_URL);

    $stdin = fopen('php://input', 'rb');
    $stdout = fopen('php://output', 'wb');
    $curl = curl_init();

    curl_setopt($curl, CURLOPT_UNIX_SOCKET_PATH, BACKEND_SOCKET);
    curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
    curl_setopt($curl, CURLOPT_URL, "http://service$uri");
    curl_setopt($curl, CURLOPT_HTTPHEADER, $header_out);
    if (
    $method == "POST" ||
    $method == "PUT" ||
    $method == "PATCH" ||
    $method == "OPTIONS" ||
    isset($_SERVER['HTTP_TRANSFER_ENCODING']) ||
    isset($_SERVER['CONTENT_LENGTH'])
    ) {
    curl_setopt($curl, CURLOPT_UPLOAD, TRUE);
    curl_setopt($curl, CURLOPT_INFILE, $stdin);
    }
    curl_setopt($curl, CURLOPT_HEADERFUNCTION, function($curl, $data) {
    // TODO(win-t): remove hop-by-hop response header
    header($data);
    return strlen($data);
    });
    curl_setopt($curl, CURLOPT_FILE, $stdout);

    $curl_result = curl_exec($curl);
    $curl_errno = curl_errno($curl);
    if(($curl_result === FALSE) || ($curl_errno != 0)) {
    $errstr = curl_strerror($curl_errno);
    exit_500("curl error: $errstr");
    }

    curl_close($curl);
    fclose($stdout);
    fclose($stdin);

    // TODO(win-t): handle response 101 Switching Protocol