mirror of
https://github.com/masterking32/MasterHttpRelayVPN.git
synced 2026-05-19 08:04:38 +03:00
Simple PHP relay.
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
/*
|
||||
* MasterHttpRelayVPN - Simple PHP Relay
|
||||
*
|
||||
* Test relay endpoint:
|
||||
* - Accepts the incoming HTTP request
|
||||
* - Forwards the raw request body to the configured upstream URL
|
||||
* - Returns the upstream response status/body to the caller
|
||||
*
|
||||
* Configuration:
|
||||
* 1. Edit UPSTREAM_URL below
|
||||
* 2. Or set environment variable RELAY_UPSTREAM_URL
|
||||
*/
|
||||
|
||||
const UPSTREAM_URL = 'https://example.com/relay';
|
||||
const CONNECT_TIMEOUT_SECONDS = 10;
|
||||
const REQUEST_TIMEOUT_SECONDS = 30;
|
||||
|
||||
$upstreamUrl = getenv('RELAY_UPSTREAM_URL');
|
||||
if (!is_string($upstreamUrl) || trim($upstreamUrl) === '') {
|
||||
$upstreamUrl = UPSTREAM_URL;
|
||||
}
|
||||
|
||||
if (trim($upstreamUrl) === '' || $upstreamUrl === 'https://example.com/relay') {
|
||||
http_response_code(500);
|
||||
header('Content-Type: text/plain; charset=utf-8');
|
||||
echo "PHP relay is not configured. Set RELAY_UPSTREAM_URL or edit UPSTREAM_URL.\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
$method = $_SERVER['REQUEST_METHOD'] ?? 'POST';
|
||||
$rawBody = file_get_contents('php://input');
|
||||
if ($rawBody === false) {
|
||||
http_response_code(400);
|
||||
header('Content-Type: text/plain; charset=utf-8');
|
||||
echo "Failed to read request body.\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
$incomingHeaders = function_exists('getallheaders') ? getallheaders() : [];
|
||||
$forwardHeaders = [];
|
||||
|
||||
foreach ($incomingHeaders as $name => $value) {
|
||||
$lower = strtolower((string) $name);
|
||||
if (in_array($lower, ['host', 'content-length', 'connection'], true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$forwardHeaders[] = $name . ': ' . $value;
|
||||
}
|
||||
|
||||
if (!hasHeader($forwardHeaders, 'Content-Type')) {
|
||||
$contentType = $_SERVER['CONTENT_TYPE'] ?? 'application/octet-stream';
|
||||
$forwardHeaders[] = 'Content-Type: ' . $contentType;
|
||||
}
|
||||
|
||||
$forwardHeaders[] = 'X-Relay-By: MasterHttpRelayVPN-PHP';
|
||||
$forwardHeaders[] = 'X-Forwarded-Method: ' . $method;
|
||||
|
||||
$ch = curl_init($upstreamUrl);
|
||||
if ($ch === false) {
|
||||
http_response_code(500);
|
||||
header('Content-Type: text/plain; charset=utf-8');
|
||||
echo "Failed to initialize cURL.\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
$responseHeaders = [];
|
||||
|
||||
curl_setopt_array($ch, [
|
||||
CURLOPT_CUSTOMREQUEST => $method,
|
||||
CURLOPT_POSTFIELDS => $rawBody,
|
||||
CURLOPT_HTTPHEADER => $forwardHeaders,
|
||||
CURLOPT_RETURNTRANSFER => true,
|
||||
CURLOPT_FOLLOWLOCATION => false,
|
||||
CURLOPT_CONNECTTIMEOUT => CONNECT_TIMEOUT_SECONDS,
|
||||
CURLOPT_TIMEOUT => REQUEST_TIMEOUT_SECONDS,
|
||||
CURLOPT_HEADERFUNCTION => static function ($curl, string $headerLine) use (&$responseHeaders): int {
|
||||
$trimmed = trim($headerLine);
|
||||
if ($trimmed !== '') {
|
||||
$responseHeaders[] = $trimmed;
|
||||
}
|
||||
return strlen($headerLine);
|
||||
},
|
||||
]);
|
||||
|
||||
$responseBody = curl_exec($ch);
|
||||
$curlError = curl_error($ch);
|
||||
$statusCode = (int) curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
|
||||
$responseContentType = (string) curl_getinfo($ch, CURLINFO_CONTENT_TYPE);
|
||||
curl_close($ch);
|
||||
|
||||
if ($responseBody === false) {
|
||||
http_response_code(502);
|
||||
header('Content-Type: text/plain; charset=utf-8');
|
||||
echo "Upstream relay failed: {$curlError}\n";
|
||||
exit;
|
||||
}
|
||||
|
||||
if ($statusCode > 0) {
|
||||
http_response_code($statusCode);
|
||||
}
|
||||
|
||||
if ($responseContentType !== '') {
|
||||
header('Content-Type: ' . $responseContentType);
|
||||
} else {
|
||||
header('Content-Type: application/octet-stream');
|
||||
}
|
||||
|
||||
echo $responseBody;
|
||||
|
||||
function hasHeader(array $headers, string $headerName): bool
|
||||
{
|
||||
$needle = strtolower($headerName) . ':';
|
||||
foreach ($headers as $header) {
|
||||
if (str_starts_with(strtolower($header), $needle)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
Reference in New Issue
Block a user