fix(sync-php): read Authorization via getallheaders and tolerate ETag forms
Apache commonly strips Authorization before PHP sees it, so every request looked unauthenticated on a stock XAMPP and answered 404. If-None-Match is now compared on the bare hash: a validator that lost its quotes, or a weak W/ tag, would never match and each request would silently re-download the whole snapshot - expensive on mobile data and invisible in the logs, a 200 looking perfectly normal.
This commit is contained in:
+20
-3
@@ -41,10 +41,22 @@ header('X-Content-Type-Options: nosniff');
|
||||
// Authentication
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/** Bearer token, compared in constant time so a wrong guess leaks no timing. */
|
||||
/**
|
||||
* Bearer token, compared in constant time so a wrong guess leaks no timing.
|
||||
*
|
||||
* Three sources on purpose: Apache commonly strips Authorization before PHP
|
||||
* sees it (it is only forwarded with CGIPassAuth on, or through a rewrite), so
|
||||
* $_SERVER alone answers empty on a stock XAMPP and every request looks
|
||||
* unauthenticated. getallheaders() reads what the client actually sent.
|
||||
*/
|
||||
function client_token(): string {
|
||||
$h = $_SERVER['HTTP_AUTHORIZATION'] ?? $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] ?? '';
|
||||
if (stripos($h, 'Bearer ') === 0) return substr($h, 7);
|
||||
if ($h === '' && function_exists('getallheaders')) {
|
||||
foreach (getallheaders() as $name => $value) {
|
||||
if (strcasecmp($name, 'Authorization') === 0) { $h = $value; break; }
|
||||
}
|
||||
}
|
||||
if (stripos($h, 'Bearer ') === 0) return trim(substr($h, 7));
|
||||
return '';
|
||||
}
|
||||
|
||||
@@ -85,7 +97,12 @@ if ($method === 'HEAD' || $method === 'GET') {
|
||||
header('Last-Modified: ' . gmdate('D, d M Y H:i:s', (int)filemtime(SYNC_FILE)) . ' GMT');
|
||||
|
||||
// Save the round trip when the client already holds this version.
|
||||
if (trim($_SERVER['HTTP_IF_NONE_MATCH'] ?? '') === $etag) {
|
||||
// Compared on the bare hash: a validator that loses its quotes or arrives
|
||||
// as a weak tag (W/"…") would otherwise never match, and every request
|
||||
// would silently download the whole snapshot again — costly on mobile data
|
||||
// and invisible in the logs, since a 200 looks perfectly normal.
|
||||
$sent = trim($_SERVER['HTTP_IF_NONE_MATCH'] ?? '');
|
||||
if ($sent !== '' && trim($sent, 'W/" ') === trim($etag, '" ')) {
|
||||
http_response_code(304);
|
||||
exit;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user