<?php
if (!@$_SERVER['REQUEST_URI']) {
if (@$argv[1] === '--fifo') {
define('PROXY_FIFO_MODE', true);
}
else if (@$argv[1] === '--tcp') {
define('PROXY_TCP_MODE', true);
}
else {
define('PROXY_CONSOLE_MODE', true);
}
define( 'WS_CONSOLE', true );
}
else {
define('PROXY_WEB_MODE', true);
define( 'WS_WEB', true );
}
require_once("common/WebInit.php");
function serve($wiki, $title, $ns, $rev, $meta, $force, &$response) {
global $requestHeaders, $wsgProxyThrottle, $wsgProxyThrottleInterval;
if ($title===false || $title==='') $title= NULL;
if ($rev===false || $rev==='') $rev= NULL;
if (is_null($wiki) || is_null($title)) {
$response->header('Status: 400 Bad Request',true,400);
$response->write("Missing wiki or title field in request");
return false;
}
if (@$wsgProxyThrottle) {
wsfThrottle('WikiProxy', $wsgProxyThrottle, @$wsgProxyThrottleInterval ? $wsgProxyThrottleInterval : 1 );
}
#TODO: cache last wiki - in batch requests, it's likely that we use the same one x times!
$wiki=& WikiAccess::newInstance($wiki);
if (!$wiki) {
$response->header('Status: 400 Bad Request',true,400);
$response->write("Bad wiki id, use full host name");
return false;
}
if ($ns===false || $ns===NULL || $ns==='') {
$ns= 0;
if ($idx= strpos($title,':')) {
$ns= substr($title,0,$idx);
$wiki->initTranslations();
#print "TRY NS: $ns;\n";
$ns= $wiki->getNsIndex($ns);
if ($ns) {
$title= trim(substr($title,$idx+1));
}
}
}
else if (!is_numeric($ns)) {
$wiki->initTranslations();
#print "TRY NS: $ns;\n";
$ns= $wiki->getNsIndex($ns);
}
else $ns= (int)$ns;
#FIXME: add support for asking for an article by ID
$rec= $wiki->fetchPageRecord($title,$ns,$rev);
if (!$rec) {
$response->header("HTTP/1.1 404 Not Found",true,404);
$response->header('Content-Type: text/plain; charset=utf-8',true,404);
if ($meta) $response->write("Not found!");
else $response->write("\0");
}
else if ($meta) {
$response->header('Content-Type: text/plain; charset=utf-8', true, NULL);
$response->header('Content-Length: '.strlen($rec['text']), true, NULL);
if (isset($rec['_cache'])) {
$response->header('X-WikiProxy: '.$rec['_cache'],true,NULL);
wsfLogScriptComment($rec['_cache']);
}
$rec['_text_len']= strlen($rec['text']);
if (!@$response->is_http) {
foreach ($rec as $k => $v) {
if ($k=='text' || $k{0}=='_') continue;
$response->header("X-Wiki-$k: $v",true,NULL);
}
$response->write(''); #flush headers
}
else {
foreach ($rec as $k => $v) {
if ($k=='text') continue;
$response->write("$k: $v\r\n");
}
}
}
else {
$response->header('Content-Type: text/plain; charset=utf-8',true,NULL);
$response->header('Content-Length: '.strlen($rec['text']), true, NULL);
if (isset($rec['_cache'])) {
$response->header('X-WikiProxy: '.$rec['_cache'],true,NULL);
wsfLogScriptComment($rec['_cache']);
}
if (!@$response->is_http) {
$rec['_text_len']= strlen($rec['text']);
foreach ($rec as $k => $v) {
if ($k=='text' || $k{0}=='_') continue;
$response->header("X-Wiki-$k: $v",true,NULL);
}
}
$doout= true;
if ( $requestHeaders && isset($rec['rev_timestamp']) && isset($requestHeaders["If-Modified-Since"]) && !$force ) {
$since= wfTimestamp(TS_MW,$requestHeaders["If-Modified-Since"]);
#TODO: cheack earlier, don't load text if not neccessary!
if ($since>=$rec['rev_timestamp']) {
#print "$since >= {$rec['rev_timestamp']}";
$response->header("HTTP/1.1 304 Not modified",true,304);
$doout= false;
}
}
if (isset($rec['rev_timestamp'])) $response->header('Last-Modified: '.wfTimestamp(TS_RFC2822,$rec['rev_timestamp']),true,NULL);
if ($doout) {
$response->header('Content-Length: '.strlen($rec['text']),true,NULL);
#FIXME: does not seem to work...
/*if (strlen($rec['text'])>256) {
ini_set('zlib.output_compression','On',true,NULL);
}
else {
ini_set('zlib.output_compression',0);
$response->header('Content-Length: '.strlen($rec['text']),true,NULL);
}*/
if (@$response->is_http) $response->header("HTTP/1.1 200 OK",true,200);
$response->write($rec['text']);
}
}
#TODO: in daemon mode, keep it open!
$wiki->close();
}
function httpDie($code, $msg, $text) {
header("Content-Type: text/plain",true,$code);
header("HTTP/1.0 $code $msg",true,$code);
header("Status: $code $msg",true,$code);
print "\n***************************************\n";
print "\nERROR: $code $msg\n";
print "\n$text\n";
print "\n***************************************\n";
die();
}
function checkAccess() {
global $wgRequest, $wsgContentAccessIPWhitelist, $wsgContentAccessTokens;
if ($wsgContentAccessIPWhitelist === NULL || $wsgContentAccessIPWhitelist === true) {
#print "*** WHITELIST ALL ***\n";
return true;
}
else if ($wsgContentAccessIPWhitelist === false) {
#print "*** WHITELIST NONE ***\n";
}
else if (is_array($wsgContentAccessIPWhitelist)) {
if (isset($_SERVER['REMOTE_ADDR']) && in_array($_SERVER['REMOTE_ADDR'],$wsgContentAccessIPWhitelist)) {
#print "*** WHITELIST ARRAY (IP MATCH {$_SERVER['REMOTE_ADDR']}) ***\n";
return true;
}
if (isset($_SERVER['REMOTE_HOST']) && in_array($_SERVER['REMOTE_HOST'],$wsgContentAccessIPWhitelist)) {
#print "*** WHITELIST ARRAY (HOST MATCH: {$_SERVER['REMOTE_HOST']}) ***\n";
return true;
}
#print "*** WHITELIST ARRAY (NO MATCH) ***\n";
}
if ($wsgContentAccessTokens === NULL || $wsgContentAccessTokens === true) {
#print "*** TOKENS ALL ***\n";
}
else if ($wsgContentAccessTokens === false) {
#print "*** TOKENS NONE ***\n";
httpDie(403, 'Forbidden', 'Access denied: You have requested this page from an external address.');
}
else if (is_array($wsgContentAccessTokens)) {
$tok= $wgRequest->getVal('token');
if (!$tok) {
#print "*** TOKENS (MISSING) ***\n";
if (!$wsgContentAccessIPWhitelist) httpDie(403,'Forbidden','Access Denied');
else httpDie(403, 'Forbidden',
'You have requested this page from an external address.
An access token is required for accessing this page from the outside.'
);
}
if (!in_array($tok, $wsgContentAccessTokens)) {
#print "*** TOKENS (NO MATCH) ***\n";
httpDie(403,'Forbidden', 'Access denied: bad token!');
}
#print "*** TOKENS (MATCH) ***\n";
}
return true;
}
if (defined('PROXY_WEB_MODE')) {
$wsgLogLevel= -100;
$wsgWikiProxy= NULL; #NOTE: force proxy off, or we may be calling this script recursively!
$wiki = $wgRequest->getVal('wiki');
$title = $wgRequest->getVal('title');
$ns = $wgRequest->getVal('ns');
$rev = $wgRequest->getVal('rev');
$meta = $wgRequest->getVal('meta');
$force = $wgRequest->getVal('force');
if (is_null($wiki) || is_null($title)) $go= false;
else $go= true;
if ($go) {
if (!$meta && defined('PROXY_WEB_MODE')) checkAccess();
require_once("WikiAccess.php");
class HttpResponse {
function HttpResponse() {
$this->is_http= true;
}
function header($h, $override=true, $code=NULL) {
header($h, $override, $code);
}
function write($data) {
if ($data==='' || $data===NULL || $data===false) return;
print $data;
}
function flush() {
flush();
}
}
$requestHeaders= NULL;
if (function_exists('apache_request_headers')) {
$requestHeaders = apache_request_headers();
}
$response= new HttpResponse();
serve($wiki, $title, $ns, $rev, $meta, $force, $response);
}
else {
header('Content-Type: text/html; charset=utf-8');
?>
<html>
<head>
<title>Wiki Proxy</title>
</head>
<body>
<h1>Wiki Proxy</h1>
<form method="get" action="<?= $_SERVER['PHP_SELF']?>">
<p>Wiki: <input type='text' size='12' name='wiki' value='<?= escapeHtml($wiki) ?>'/></p>
<p>Title: <input type='text' size='64' name='title' value='<?= escapeHtml($title) ?>'/></p>
<p>Revision: <input type='text' size='6' name='rev' value='<?= escapeHtml($rev) ?>'/></p>
<p><input type='submit' name='go' value='Fetch'/> <input type='submit' name='meta' value='Meta'/></p>
<? if (@$wsgContentAccessTokens): ?>
<p>Access token: <input type='text' size='24' name='token' value='<?= $rev ?>'/> <small>(required for external access)</small></p>
<?endif?>
</form>
</body>
</html>
<?
}
}
if (defined('PROXY_FIFO_MODE')) {
require_once("WikiAccess.php");
require_once("FifoServer.php");
if (isset($options['ll'])) $wsgLogLevel= (int)$options['ll'];
else if (isset($options['vv'])) $wsgLogLevel= LL_DEBUG;
else if (isset($options['v'])) $wsgLogLevel= LL_VERBOSE;
class FifoProxy extends FifoServer {
function FifoProxy( $fifo ) {
FifoServer::FifoServer( $fifo );
}
function handleRequest( $req, &$response ) {
$wiki = @$req['wiki'];
$title = @$req['title'];
$ns = @$req['ns'];
$rev = @$req['rev'];
$meta = @$req['meta'];
$force = @$req['force'];
if ($title===NULL) $title = @$req['']; //path
serve($wiki, $title, $ns, $rev, $meta, $force, $response);
}
}
$serverFifo= @$args[0];
if (!$serverFifo) $serverFifo= '/var/lib/WikiProxy.fifo';
$server= new FifoProxy( $serverFifo );
$server->runServer();
}
if (defined('PROXY_TCP_MODE')) {
require_once("WikiAccess.php");
require_once("TcpServer.php");
if (isset($options['ll'])) $wsgLogLevel= (int)$options['ll'];
else if (isset($options['vv'])) $wsgLogLevel= LL_DEBUG;
else if (isset($options['v'])) $wsgLogLevel= LL_VERBOSE;
class TcpProxy extends TcpServer {
function TcpProxy( $port, $bind = '127.0.0.1' ) {
TcpServer::TcpServer( $port, $bind );
}
function handleRequest( $req, &$response ) {
$wiki = @$req['wiki'];
$title = @$req['title'];
$ns = @$req['ns'];
$rev = @$req['rev'];
$meta = @$req['meta'];
$force = @$req['force'];
if ($title===NULL && isset($req['']) && strlen($req[''])>1) {
$title = substr($req[''], 1);
}
serve($wiki, $title, $ns, $rev, $meta, $force, $response);
}
}
$port= (int)@$args[0];
if (!$port) $port= '4223';
$bind= '127.0.0.1';
if (isset($options['bind'])) $bind= $options['bind'];
$server= new TcpProxy( $port, $bind );
$server->runServer();
}
if (defined('PROXY_CONSOLE_MODE')) {
$wsgLogLevel= -100;
if (sizeof($args)<2) $go= false;
else {
$wiki = $args[0];
$title = $args[1];
$ns = @$options['namespace'];
$rev = @$options['rev'];
$meta = isset($options['meta']);
$force = isset($options['force']);
if (is_null($wiki) || is_null($title)) $go= false;
else $go= true;
}
if ($go) {
require_once("WikiAccess.php");
class CliResponse {
function CliResponse() {
$this->is_http= false;
}
function header($h, $override=true, $code=NULL) {
print "\t**** $h\n";
}
function write($data) {
if ($data==='' || $data===NULL || $data===false) return;
print $data;
}
function flush() {
flush();
}
}
$response= new CliResponse();
$requestHeaders= NULL;
if (function_exists('apache_request_headers')) {
$requestHeaders = apache_request_headers();
}
serve($wiki, $title, $ns, $rev, $meta, $force, $response);
}
else {
print "USAGE: WikiProxy [options] <wiki> <title>\n";
exit(1);
}
}
?>WikiProxy.php
application/x-php, 13746 bytes (load raw)

