raliiev%mozilla.com bcbf866627 Bug 1102283 - Add suport for locale based throttling. r=nthomas,rhelmer
git-svn-id: svn://10.0.0.236/trunk@265692 18797224-902f-48f8-a5cc-f745e15eee43
2014-11-26 16:24:25 +00:00

415 lines
16 KiB
PHP

<?php
// ***** BEGIN LICENSE BLOCK *****
//
// Version: MPL 1.1/GPL 2.0/LGPL 2.1
//
// The contents of this file are subject to the Mozilla Public License Version
// 1.1 (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
// http://www.mozilla.org/MPL/
//
// Software distributed under the License is distributed on an "AS IS" basis,
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
// for the specific language governing rights and limitations under the
// License.
//
// The Original Code is AUS.
//
// The Initial Developer of the Original Code is Mike Morgan.
//
// Portions created by the Initial Developer are Copyright (C) 2006
// the Initial Developer. All Rights Reserved.
//
// Contributor(s):
// Mike Morgan <morgamic@mozilla.com>
//
// Alternatively, the contents of this file may be used under the terms of
// either the GNU General Public License Version 2 or later (the "GPL"), or
// the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
// in which case the provisions of the GPL or the LGPL are applicable instead
// of those above. If you wish to allow use of your version of this file only
// under the terms of either the GPL or the LGPL, and not to allow others to
// use your version of this file under the terms of the MPL, indicate your
// decision by deleting the provisions above and replace them with the notice
// and other provisions required by the GPL or the LGPL. If you do not delete
// the provisions above, a recipient may use your version of this file under
// the terms of any one of the MPL, the GPL or the LGPL.
//
// ***** END LICENSE BLOCK *****
/**
* AUS main script.
* @package aus
* @subpackage docs
* @author Mike Morgan
*
* This script handles incoming requests, reads the related build
* snippet and returns a properly formatted XML file for testing.
*/
// Require config and supporting libraries.
require_once('./inc/init.php');
// Instantiate XML object.
$xml = new Xml();
//Are we behind a proxy and given the IP via an alternate enviroment variable? If so, use it.
if (!empty($_SERVER["HTTP_X_FORWARDED_FOR"])) {
list($ip) = explode(', ',$_SERVER["HTTP_X_FORWARDED_FOR"]);
} else {
$ip = $_SERVER["REMOTE_ADDR"];
}
//We need to give the user a unique cookie and make it expire in 5 years.
if (!array_key_exists(COOKIE_NAME, $_COOKIE)) {
setcookie(COOKIE_NAME, $ip . '.' . microtime(true), time() + 157784630, '/', COOKIE_DOMAIN);
}
// Find everything between our CWD and 255 in QUERY_STRING.
$rawPath = substr(urldecode($_SERVER['QUERY_STRING']),5,255);
// Munge he resulting string and store it in $path.
$path = explode('/',$rawPath);
// Check to see if the user is requesting channel changing.
if ( !(empty($_GET['newchannel']))) {
$newchannel = $_GET['newchannel'];
}
// Determine incoming request and clean inputs.
$clean = Array();
$clean['updateVersion'] = isset($path[0]) ? intval($path[0]) : null;
$clean['product'] = isset($path[1]) ? trim($path[1]) : null;
$clean['version'] = isset($path[2]) ? urlencode($path[2]) : null;
$clean['build'] = isset($path[3]) ? trim($path[3]) : null;
$clean['platform'] = isset($path[4]) ? trim($path[4]) : null;
$clean['locale'] = isset($path[5]) ? trim($path[5]) : null;
$clean['channel'] = isset($path[6]) ? trim($path[6]) : null;
$clean['platformVersion'] = isset($path[7]) ? trim($path[7]) : null;
$clean['dist'] = isset($path[8]) ? trim($path[8]) : null;
$clean['distVersion'] = isset($path[9]) ? trim($path[9]) : null;
$clean['newchannel'] = isset($newchannel) ? trim($newchannel) : null;
// Check to see if we have a beta on PPC, and if so don't update since beta 4
// doesn't work on PPC. See bug 588412.
if ( $clean['product'] == 'Firefox'
&& (preg_match('/^4\.0.*$/', $clean['version']) || preg_match('/^3\.7.*$/', $clean['version']))
&& strpos($_SERVER['HTTP_USER_AGENT'], 'PPC')) {
$xml->printXml();
exit;
}
// Check to see if the user is explicitly requesting an update. If they are,
// skip throttling. If they aren't, and throttling is enabled, first check
// explicit throttling. If no specific rules exist, fallback to global rules.
// In either case, updates will be served based on the configured random seed.
if ( (empty($_GET['force']) || $_GET['force']!=1) ) {
// Default to false. If conditions are met, flip it.
$throttleMe = false;
$aus = new AUS_Object();
// Check explicit throttling.
if ( !$aus->isThrottleException($clean['version'], $clean['channel']) ) {
// check if locale based throttling is set. Do not use product based throttling if set
if ( isset($localeThrottling[$clean['product']][$clean['version']][$clean['locale']]) ) {
if ( mt_rand(0,99) >= $localeThrottling[$clean['product']][$clean['version']][$clean['locale']] ){
$throttleMe = true;
}
} elseif ( isset($productThrottling[$clean['product']][$clean['version']])
&& mt_rand(0,99) >= $productThrottling[$clean['product']][$clean['version']] ) {
$throttleMe = true;
}
// Check global throttling.
} elseif ( defined('THROTTLE_GLOBAL') && THROTTLE_GLOBAL &&
defined('THROTTLE_LEVEL') &&
mt_rand(0,99) >= THROTTLE_LEVEL ) {
$throttleMe = true;
}
if ($throttleMe) {
if (defined('THROTTLE_LOGGING') && THROTTLE_LOGGING) {
error_log('AUS2 THROTTLE: '.$ip.' '.$_SERVER['REQUEST_URI']);
}
$xml->printXml();
exit;
}
}
// Connect to memcache and try to pull output.
$memcache = new Memcaching();
$_cached_xml = $memcache->get($rawPath);
if ($_cached_xml) {
$xml = $_cached_xml;
} else {
/**
* For each updateVersion, we will run separate code when it differs.
* Our case statements below are ordered by date added, desc (recent ones first).
*
* If the only difference is an added parameter, etc., then we may blend cases
* together by omitting a break.
*/
switch ($clean['updateVersion']) {
/*
* This is for the fifth revision, adding %PLATFORM_VERSION%.
* /update/4/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/%PLATFORM_VERSION%/update.xml
*/
case 4:
// Nothing special.
/*
* This is for the fourth revision, adding %DISTRIBUTION% and
* %DISTRIBUTION_VERSION%.
* /update/3/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/%DISTRIBUTION%/%DISTRIBUTION_VERSION%/update.xml
*/
case 3:
// Nothing special.
/*
* This is for the third revision of the URI schema, with %OS_VERSION%.
* /update2/2/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/%OS_VERSION%/update.xml
*/
case 2:
// Check for OS_VERSION values and scrub the URI to make sure we aren't getting a malformed request
// from a client suffering from bug 360127.
if (empty($clean['platformVersion']) || $clean['platformVersion']=='%OS_VERSION%' || preg_match('/^1\.5.*$/',$clean['version'])) {
break;
}
/*
* This is for the second revision of the URI schema, with %CHANNEL% added.
* /update2/1/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/%CHANNEL%/update.xml
*/
case 1:
// Set a default for platformVersion.
if (empty($clean['platformVersion'])) {
$clean['platformVersion'] = null;
}
// Check for a set channel.
// Instantiate Update object and set updateVersion.
$update = new Update();
// Instantiate our complete patch.
$completePatch = new Patch($productBranchVersions,$nightlyChannels,'complete',$latestRelease);
$channel = $clean['channel'];
if (isset($clean['newchannel'])) {
$completePatch->setChangingChannel(true);
$channel = $clean['newchannel'];
}
// If our complete patch exists and is valid, set the patch line.
if ($completePatch->findPatch($clean['product'],$clean['platform'],$clean['locale'],$clean['version'],$clean['build'],$channel) && $completePatch->isPatch()) {
// Set our patchLine.
$xml->setPatchLine($completePatch);
// If available, pull update information from the build snippet.
// FIXME hasUpdateInfo not used by snippet schema v2, needs refactoring
if ($completePatch->hasUpdateInfo()) {
$update->setVersion($completePatch->updateVersion);
$update->setExtensionVersion($completePatch->updateExtensionVersion);
}
if (isset($completePatch->build)) {
$update->setBuild($completePatch->build);
}
// If there is details url information, add it to the update object.
if ($completePatch->hasDetailsUrl()) {
$update->setDetails($completePatch->detailsUrl);
}
// If we found an update type, pass it along.
if ($completePatch->hasUpdateType()) {
$update->setType($completePatch->updateType);
}
// If we have a license URL, pass it along.
if ($completePatch->hasLicenseUrl()) {
$update->setLicense($completePatch->licenseUrl);
}
// If we have a billboard URL, pass it along.
if ($completePatch->hasBillboardUrl()) {
$update->setBillboard($completePatch->billboardURL);
}
// If showPrompt is set, pass it along.
if ($completePatch->hasShowPrompt()) {
$update->setShowPrompt($completePatch->showPrompt);
}
// If showNeverForVersion is set, pass it along.
if ($completePatch->hasShowNeverForVersion()) {
$update->setShowNeverForVersion($completePatch->showNeverForVersion);
}
// If showSurvey is set, pass it along.
if ($completePatch->hasShowSurvey()) {
$update->setShowSurvey($completePatch->showSurvey);
}
// If actions is set, pass it along.
if ($completePatch->hasActions()) {
$update->setActions($completePatch->actions);
}
// If we have a open URL, pass it along.
if ($completePatch->hasOpenUrl()) {
$update->setOpen($completePatch->openURL);
}
// If we have a notification URL, pass it along.
if ($completePatch->hasNotificationUrl()) {
$update->setNotification($completePatch->notificationURL);
}
// If we have a alert URL, pass it along.
if ($completePatch->hasAlertUrl()) {
$update->setAlert($completePatch->alertURL);
}
// If we have prompt wait time, pass it along.
if ($completePatch->hasPromptWaitTime()) {
$update->setPromptWaitTime($completePatch->promptWaitTime);
}
// If we have a display version, pass it along.
if ($completePatch->hasDisplayVersion()) {
$update->setDisplayVersion($completePatch->displayVersion);
}
// If we have an app version, pass it along.
if ($completePatch->hasAppVersion()) {
$update->setAppVersion($completePatch->appVersion);
}
// If we have a platform version, pass it along.
if ($completePatch->hasPlatformVersion()) {
$update->setPlatformVersion($completePatch->platformVersion);
}
// If we have a snippet schema version, pass it along.
if ($completePatch->hasSnippetSchemaVersion()) {
$update->setSnippetSchemaVersion($completePatch->snippetSchemaVersion);
}
}
// if we are channel-switching, do not check for partial updates.
if (!isset($clean['newchannel'])) {
// Instantiate our partial patch.
$partialPatch = new Patch($productBranchVersions,$nightlyChannels,'partial');
// If our partial patch exists and is valid, set the patch line.
if ($partialPatch->findPatch($clean['product'],$clean['platform'],$clean['locale'],$clean['version'],$clean['build'],$clean['channel'])
&& $partialPatch->isPatch()
&& $partialPatch->isOneStepFromLatest($completePatch->build)) {
$xml->setPatchLine($partialPatch);
}
}
// If we have valid patchLine(s), set up our output.
if ($xml->hasPatchLine() && $completePatch->isSupported($completePatch->updateType, $clean['product'], $completePatch->updateExtensionVersion, $clean['platformVersion'], $unsupportedPlatforms)) {
$xml->startUpdate($update);
$xml->drawPatchLines();
$xml->endUpdate();
}
break;
/*
* This is for the first revision of the URI schema.
* /update2/0/%PRODUCT%/%VERSION%/%BUILD_ID%/%BUILD_TARGET%/%LOCALE%/update.xml
*/
case 0:
default:
// Instantiate Update object and set updateVersion.
$update = new Update();
// Instantiate Patch object and set Path based on passed args.
$patch = new Patch($productBranchVersions,$nightlyChannels,'complete');
$patch->findPatch($clean['product'],$clean['platform'],$clean['locale'],$clean['version'],$clean['build'],null);
if ($patch->isPatch()) {
$xml->setPatchLine($patch);
}
// If we have a new build, draw the update block and patch line.
// If there is no valid patch file, client will receive no updates by default.
if ($xml->hasPatchLine()) {
$xml->startUpdate($update);
$xml->drawPatchLines();
$xml->endUpdate();
}
break;
}
}
// If we are debugging output plaintext and exit.
if ( defined('DEBUG') && DEBUG == true ) {
echo '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">'."\n";
echo '<html xmlns="http://www.w3.org/1999/xhtml">'."\n";
echo '<head>'."\n";
echo '<title>AUS Debug Information</title>'."\n";
echo '</head>'."\n";
echo '<body>'."\n";
echo '<h1>AUS Debug Information</h1>'."\n";
echo '<h2>XML Output</h2>'."\n";
echo '<pre>'."\n";
echo htmlentities($xml->getOutput());
echo '</pre>'."\n";
if (!empty($clean)) {
echo '<h2>Inputs</h2>'."\n";
echo '<pre>'."\n";
print_r($clean);
echo '</pre>'."\n";
}
echo '<h2>Patch Objects</h2>'."\n";
echo '<pre>'."\n";
if (!empty($patch)) {
print_r($patch);
}
if (!empty($completePatch)) {
print_r($completePatch);
}
if (!empty($partialPatch)) {
print_r($partialPatch);
}
echo '</pre>'."\n";
if (!empty($update)) {
echo '<h2>Update Object</h2>'."\n";
echo '<pre>'."\n";
print_r($update);
echo '</pre>'."\n";
}
echo '</body>'."\n";
echo '</html>';
exit;
}
// Set header and send info.
$memcache->set($rawPath,$xml);
$xml->printXml();
exit;
?>