listen($socket);
echo 'listen on ', ADDR , ':', PORT, PHP_EOL;
$loop->run();
function handler(Psr\Http\Message\ServerRequestInterface $req) {
$time = date('Y-m-d H:i:s');
$ip = $req->getHeader('REMOTE_ADDR');
if (!$ip) {
// app deal http requests
$ip = $req->getServerParams()['REMOTE_ADDR'];
} else {
// app is behind nginx
$ip = $ip[0];
}
$url = $req->getUri()->getPath();
// strip start /
$url = substr($url, 1);
echo "$time IP: $ip, request url: $url", PHP_EOL;
if (substr($url, 0, 4) !== 'http') {
return serveStaticFiles($url);
}
// @notice: uncomment the following line to proxy any url!
// return proxy($req);
$exp1 = '/^https?:\/\/?github\.com\/.+?\/.+?\/(?:releases|archive)\/.*$/i';
$exp2 = '/^https?:\/\/?github\.com\/.+?\/.+?\/(?:blob)\/.*$/i';
$exp3 = '/^https?:\/\/?github\.com\/.+?\/.+?\/(?:info|git-).*$/i';
$exp4 = '/^https?:\/\/?raw\.githubusercontent\.com\/.+?\/.+?\/.+?\/.+$/i';
$exp5 = '/^https?:\/\/?api\.github\.com\/.+?\/.+?\/.+?\/.+$/i';
if (preg_match($exp1, $url) || preg_match($exp5, $url) || !CNPMJS && (preg_match($exp3, $url) || preg_match($exp4, $url))) {
return proxy($req);
} else if (preg_match($exp2, $url)) {
if (JSDELIVR){
$url = str_replace('/blob/', '@', $url);
$url = preg_replace('/^https?:\/\/github\.com/', 'https://cdn.jsdelivr.net/gh', $url);
return new React\Http\Message\Response(
302,
array(
'Location' => $url
)
);
}else{
$url = str_replace('/blob/', '/raw/', $url);
return proxy($req);
}
} else if (preg_match($exp3, $url)) {
$url = preg_replace('/^https?:\/\/github\.com/', 'https://github.com.cnpmjs.org', $url);
return new React\Http\Message\Response(
302,
array(
'Location' => $url
)
);
} else if (preg_match($exp4, $url)) {
$url = preg_replace('/(com\/.+?\/.+?)\/(.+?\/)/', '$1@$2', $url);
$url = preg_replace('/^https?:\/\/raw\.githubusercontent\.com/', 'https://cdn.jsdelivr.net/gh', $url);
return new React\Http\Message\Response(
302,
array(
'Location' => $url
)
);
}
return new React\Http\Message\Response(
500,
array(
),
"
unable to deal with request: $url
"
);
}
function serveStaticFiles(string $url) {
if ($url == "") $url = "index.html";
$path = ROOT . "/$url";
$path = realpath($path);
if (strpos(ROOT, $path) === 0 && is_file($path)) {
header('Content-Type:' . mime_content_type($path));
readfile($path);
return;
}
return new React\Http\Message\Response(
404,
array(
),
"File Not Found!
"
);
}
function proxy(Psr\Http\Message\ServerRequestInterface $req) {
$requestMethod = $req->getMethod();
if ($requestMethod === 'OPTIONS' &&
isset($req->header['access-control-request-headers'])) {
return new React\Http\Message\Response(
204,
array(
'access-control-allow-origin' => '*',
'access-control-allow-methods' => 'GET,POST,PUT,PATCH,TRACE,DELETE,HEAD,OPTIONS',
'access-control-max-age' => '1728000',
)
);
}
return fetch($req);
}
function fetch(Psr\Http\Message\ServerRequestInterface $req) {
global $loop;
$url = $req->getUri()->getPath();
// strip start /
$url = substr($url, 1);
$client = new React\Http\Browser($loop);
// catch any response
$client = $client->withRejectErrorResponse(false);
// see https://github.com/reactphp/http#streaming-response
return $client->requestStreaming($req->getMethod(), $url)->then(function (Psr\Http\Message\ResponseInterface $response) {
$headers = $response->getHeaders();
$body = $response->getBody();
assert($body instanceof Psr\Http\Message\StreamInterface);
assert($body instanceof React\Stream\ReadableStreamInterface);
if (isset($headers['Content-Length']) && intval($headers['Content-Length'][0]) > SIZE_LIMIT) {
echo 'length: ', normalizeSize(intval($headers['Content-Length'][0])), "exceed limit", PHP_EOL;
// return direct link instead of error
return new React\Http\Message\Response(
302,
array(
'Location' => $url
)
);
}
$headers['access-control-expose-headers'] = '*';
$headers['access-control-allow-origin'] = '*';
unset($headers['content-security-policy']);
unset($headers['content-security-policy-report-only']);
unset($headers['clear-site-data']);
$res = new React\Http\Message\Response(
200,
$headers
);
return $res->withBody($body);
});
}
function normalizeSize(int $size) {
$BASE = 1024;
$units = [
'KB',
'MB',
'GB',
];
foreach ($units as $unit) {
$size /= $BASE;
if ($size < 1024) {
return round($size, 2) . $unit;
}
}
return round($size, 2) . 'GB';
}