Difference between revisions of "Server.pl"

From Organic Design wiki
m
 
(3 intermediate revisions by the same user not shown)
Line 1: Line 1:
# Server.pl is a component of wikid.pl - MediaWiki Wiki-Daemon Extension{{perl}}{{#security:*|dev}}{{#security:view|*}}
+
{{legacy}}
# - See http://www.mediawiki.org/wiki/Extension:WikiDaemon for installation and usage details
+
<source lang="perl">
# - Licenced under LGPL (http://www.gnu.org/copyleft/lesser.html)
 
# - Author: http://www.organicdesign.co.nz/nad
 
# - Source: http://www.organicdesign.co.nz/server.pl
 
 
# UNDER CONSTRUCTION - this code is being restructured for WikiD II - started 2007-04-26
 
 
 
 
use IO::Socket;
 
use IO::Socket;
 
use IO::Select;
 
use IO::Select;
 
use MIME::Base64;
 
use MIME::Base64;
  
sub serverInitialise {
+
sub server {
  
 
%::streams = ();
 
%::streams = ();
$::port = shift or 1729;
+
$::port = shift or 80;
 
$0 = "$::daemon: $::peer (http$::port)";
 
$0 = "$::daemon: $::peer (http$::port)";
 
my $subname = $::subname;
 
my $subname = $::subname;
Line 30: Line 24:
 
$::select = new IO::Select $::server;
 
$::select = new IO::Select $::server;
 
logAdd "Listening on port $::port";
 
logAdd "Listening on port $::port";
 +
 +
# HTML interface environment
 +
$::template = readFile 'peer.html';
 +
$::template =~ s/<!-- daemon -->/$::title ($::daemon)/g;
 +
$::template =~ s/<!-- peer -->/$::peer/g;
 +
$::deny = readFile "$::peer.401";
 +
my $views = '';
 +
$views .= "*[[$_]]\n" for ( 'Update', 'Filter', 'Events', 'Edit' );
 +
$::template =~ s/<!-- views -->/ wikiParse($views) /e;
 +
my $nav = "*[[$peer|Gir Home]]\n*[http://www.organicdesign.co.nz/User:$peer User:$peer]\n";
 +
$nav .= "*[[$_]]\n" for (
 +
"env/cmd|Environment Info",
 +
"peerlog/cmd|Peer Log",
 +
"syslog/cmd|Syslog",
 +
"restart/cmd|Restart $::peer",
 +
"stop/cmd|Stop $::peer",
 +
"reboot/cmd|Restart this server",
 +
"fileSync/cmd|Manual fileSync",
 +
"wikiSync/cmd|Manual wikiSync",
 +
"swfCompile/cmd|Manual swfCompile",
 +
"serverBackup/cmd|Backup server now",
 +
"wikiBackup/cmd|Backup wiki now",
 +
"peerBackup/cmd|Backup peer now",
 +
"scpBackups/cmd|SCP Backup now",
 +
"Yi|Hexagrams"
 +
);
 +
$::template =~ s/<!-- navigation -->/ wikiParse($nav) /e;
  
 
# Simple HTTP server loop
 
# Simple HTTP server loop
Line 70: Line 91:
  
 
# Process an incoming HTTP message
 
# Process an incoming HTTP message
sub serverProcessMessage {
+
sub processMessage {
 
my ( $stream, $msg ) = @_;
 
my ( $stream, $msg ) = @_;
 
my $handle = $::streams{$stream}{handle};
 
my $handle = $::streams{$stream}{handle};
Line 93: Line 114:
 
}
 
}
  
 +
# Process request from other peer or peer-related process
 +
# - doesn't return an HTTP response
 +
elsif ( $ct =~ /^peer\/(.*)/ ) {
 +
my $type = $1;
 +
logAdd "PEER command \"$title\" received from an instance of \"$type\"";
 +
 +
# peerd-child is doing initial connection, keep handle in global scope
 +
# - peerd could talk back here over this stream, but doesn't currently
 +
if ( $title eq 'connect' and $type eq 'peerd' ) {
 +
$::peerdHandle = $handle;
 +
}
 +
 +
# Forward any commands from XmlWiki to peerd unchanged
 +
elsif ( $type eq 'notify-peer.php' ) {
 +
print $::peerdHandle "$title/$type\x00" if defined $::peerdHandle;
 +
}
 +
 +
# SWF initiating connection, ask peerd to connect back on a new stream for a session
 +
elsif ( $title eq 'connect' and $type eq 'interface' ) {
 +
# Send stream-id of swf, so we know which one is wanted by the connection back from peerd
 +
print $::peerdHandle "connect-request/stream$stream\x00" if defined $::peerdHandle;
 +
# Remove the handle from this (server.pl) context, but don't close it
 +
# - also keep our local %stream info to give to session-handler
 +
$::select->remove( $handle );
 +
}
 +
 +
# peerd is connecting back from session request, so we can now spawn the session-handler
 +
elsif ( $title eq 'session' and $type =~ /^peerd\/stream([0-9]+)/ ) {
 +
# Spawn a new session-handler child and pass the peerd and peer.swf stream-handles
 +
spawn 'sessionHandler', $handle, $::streams{$1}{handle};
 +
# We can remove the interface from %streams now too
 +
delete $::streams{$1};
 +
}
 +
 +
# These peer requests don't want HTTP returned currently
 +
$respond = 0;
 +
}
 +
 +
# Process request for raw SWF
 +
elsif ( $ct eq 'application/x-shockwave-flash' ) {
 +
$headers .= "Content-Disposition: inline;filename=$::peer.swf\r\n";
 +
logAdd "SWF movie \"$title\" requested";
 +
$article = readFile $title;
 +
}
 +
 +
# Process request for SWF embedded in HTML
 +
elsif ( $ct eq 'swf' ) {
 +
my $width = 640;
 +
my $height = 480;
 +
my $file = "/$::peer.swf/application/x-shockwave-flash";
 +
$article = "<object classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"
 +
codebase=\"http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0\"
 +
width=\"$width\" height=\"$height\" id=\"$file\" align=\"\"
 +
type=\"application/x-shockwave-flash\" data=\"$file\">
 +
<param name=\"movie\" value=\"$file\">
 +
<param name=\"quality\" value=\"high\">
 +
<param name=\"bgcolor\" value=\"cccccc\">
 +
<embed src=\"$file\" quality=\"high\" bgcolor=\"cccccc\"
 +
width=\"$width\" height=\"$height\" align=\"\"
 +
name=\"$file\" type=\"application/x-shockwave-flash\"
 +
pluginspage=\"http://www.macromedia.com/go/getflashplayer\" />
 +
</object>";
 +
$ct = '';
 +
}
  
 
# If still non processed, treat request as local filename to return
 
# If still non processed, treat request as local filename to return
Line 120: Line 205:
 
}
 
}
 
}
 
}
 +
</source>
 +
[[Category:PERL]]

Latest revision as of 13:31, 2 August 2017

Legacy.svg Legacy: This article describes a concept that has been superseded in the course of ongoing development on the Organic Design wiki. Please do not develop this any further or base work on this concept, now this page is for historic record only.
use IO::Socket;
use IO::Select;
use MIME::Base64;

sub server {

	%::streams = ();
	$::port = shift or 80;
	$0 = "$::daemon: $::peer (http$::port)";
	my $subname = $::subname;

	# Initialise server listening on our port
	do { unless ( $::server = new IO::Socket::INET
			Listen => 1,
			LocalPort => $::port,
			Proto => 'tcp',
			ReuseAddr => 1 ) {
				logAdd "Failed to bind to Port$::port, waiting 10 seconds...";
				sleep(10);
				}
		} until ( $::server );
	$::select = new IO::Select $::server;
	logAdd "Listening on port $::port";

	# HTML interface environment
	$::template = readFile 'peer.html';
	$::template =~ s/<!-- daemon -->/$::title ($::daemon)/g;
	$::template =~ s/<!-- peer -->/$::peer/g;
	$::deny = readFile "$::peer.401";
	my $views = '';
	$views .= "*[[$_]]\n" for ( 'Update', 'Filter', 'Events', 'Edit' );
	$::template =~ s/<!-- views -->/ wikiParse($views) /e;
	my $nav = "*[[$peer|Gir Home]]\n*[http://www.organicdesign.co.nz/User:$peer User:$peer]\n";
	$nav .= "*[[$_]]\n" for (
		"env/cmd|Environment Info",
		"peerlog/cmd|Peer Log",
		"syslog/cmd|Syslog",
		"restart/cmd|Restart $::peer",
		"stop/cmd|Stop $::peer",
		"reboot/cmd|Restart this server",
		"fileSync/cmd|Manual fileSync",
		"wikiSync/cmd|Manual wikiSync",
		"swfCompile/cmd|Manual swfCompile",
		"serverBackup/cmd|Backup server now",
		"wikiBackup/cmd|Backup wiki now",
		"peerBackup/cmd|Backup peer now",
		"scpBackups/cmd|SCP Backup now",
		"Yi|Hexagrams"
		);
	$::template =~ s/<!-- navigation -->/ wikiParse($nav) /e;

	# Simple HTTP server loop
	while(1) {
		for my $handle ( $::select->can_read(1) ) {
			my $stream = fileno $handle;
			$::subname = "$subname/stream$stream";

			# Handle is the server, set up a new stream
			if ( $handle == $::server ) {
				my $newhandle = $::server->accept;
				$stream = fileno $newhandle;
				$::select->add( $newhandle );
				$::streams{$stream}{buffer} = '';
				$::streams{$stream}{handle} = $newhandle;
				logAdd "New connection: Stream$stream", 'main/new';
				}

			# Handle is an existing stream with data to read
			# NOTE: we should disconnect after certain size limit
			# - Process (and remove) all complete messages from this peer's buffer
			elsif ( sysread $handle, my $input, 10000 ) {
				$::streams{$stream}{buffer} .= $input;
				if ( $::streams{$stream}{buffer} =~ s/^(.*\r?\n\r?\n\x00?)//s ) {
					processMessage( $stream, $_ ) for split /\r?\n\r?\n\x00?/, $1;
					}
				}

			# Handle is an existing stream with no more data to read
			else {
				$::select->remove( $handle );
				delete $::streams{$stream};
				$handle->close();
				logAdd "Stream$stream disconnected.";
				}

			}
		}
	}

# Process an incoming HTTP message
sub processMessage {
	my ( $stream, $msg ) = @_;
	my $handle = $::streams{$stream}{handle};
	my $headers = '';
	my $http = '200 OK';
	my $respond = 1;
	my $date = strftime "%a, %d %b %Y %H:%M:%S %Z", localtime;
	my $article = $::deny;

	# Extract info from the HTTP GET request
	my ( $title, $ct, $ver ) =
		$msg =~ /GET\s+\/+(.*?)(\/(.+))?\s+(HTTP\/[0-9.]+)/ ? ( $1, $3, $4 ) : ( $peer, '', 'HTTP/1.1' );

	# If request authenticates service it, else return 401
	if ( $ct =~ /^cmd/ ? ( $msg =~ /Authorization: Basic (\w+)/ and decode_base64($1) eq "$::peer:$::pwd1" ) : 1 ) {

		# Process a command
		if ( $ct =~ /^cmd(.*)/ ) {
			logAdd "Executing $title command.";
			$article = '<pre>'.command($title).'</pre>';
			$ct = '' if $1 ne '/raw';
			}

		# Process request from other peer or peer-related process
		# - doesn't return an HTTP response
		elsif ( $ct =~ /^peer\/(.*)/ ) {
			my $type = $1;
			logAdd "PEER command \"$title\" received from an instance of \"$type\"";

			# peerd-child is doing initial connection, keep handle in global scope
			# - peerd could talk back here over this stream, but doesn't currently
			if ( $title eq 'connect' and $type eq 'peerd' ) {
				$::peerdHandle = $handle;
				}

			# Forward any commands from XmlWiki to peerd unchanged
			elsif ( $type eq 'notify-peer.php' ) {
				print $::peerdHandle "$title/$type\x00" if defined $::peerdHandle;
				}

			# SWF initiating connection, ask peerd to connect back on a new stream for a session
			elsif ( $title eq 'connect' and $type eq 'interface' ) {
				# Send stream-id of swf, so we know which one is wanted by the connection back from peerd
				print $::peerdHandle "connect-request/stream$stream\x00" if defined $::peerdHandle;
				# Remove the handle from this (server.pl) context, but don't close it
				# - also keep our local %stream info to give to session-handler
				$::select->remove( $handle );
				}

			# peerd is connecting back from session request, so we can now spawn the session-handler
			elsif ( $title eq 'session' and $type =~ /^peerd\/stream([0-9]+)/ ) {
				# Spawn a new session-handler child and pass the peerd and peer.swf stream-handles
				spawn 'sessionHandler', $handle, $::streams{$1}{handle};
				# We can remove the interface from %streams now too
				delete $::streams{$1};
				}

			# These peer requests don't want HTTP returned currently
			$respond = 0;
			}

		# Process request for raw SWF
		elsif ( $ct eq 'application/x-shockwave-flash' ) {
			$headers .= "Content-Disposition: inline;filename=$::peer.swf\r\n";
			logAdd "SWF movie \"$title\" requested";
			$article = readFile $title;
			}

		# Process request for SWF embedded in HTML
		elsif ( $ct eq 'swf' ) {
			my $width = 640;
			my $height = 480;
			my $file = "/$::peer.swf/application/x-shockwave-flash";
			$article = "<object classid=\"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\"
	codebase=\"http://download.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,0,0\"
	width=\"$width\" height=\"$height\" id=\"$file\" align=\"\"
	type=\"application/x-shockwave-flash\" data=\"$file\">
	<param name=\"movie\" value=\"$file\">
	<param name=\"quality\" value=\"high\">
	<param name=\"bgcolor\" value=\"cccccc\">
	<embed src=\"$file\" quality=\"high\" bgcolor=\"cccccc\"
		width=\"$width\" height=\"$height\" align=\"\"
		name=\"$file\" type=\"application/x-shockwave-flash\"
		pluginspage=\"http://www.macromedia.com/go/getflashplayer\" />
	</object>";
			$ct = '';
			}

		# If still non processed, treat request as local filename to return
		else {
			logAdd "$title($ct) requested";
			$article = readFile $title;
			}

		# Render article
		unless ( $ct ) {
			$ct = 'text/html';
			my $tmp = $::template;
			$tmp =~ s/<!-- title -->/$title/g;
			$tmp =~ s/<!-- content -->/ wikiParse $article /e;
			$article = $tmp;
			}
		}
	else { $http = "401 Authorization Required\r\nWWW-Authenticate: Basic realm=\"private\"" }

	# Send response back to requestor
	if ( $respond ) {
		$headers = "$ver $http\r\nDate: $date\r\nServer: $::daemon\r\n$headers";
		$headers .= "Content-Type: $ct\r\n";
		$headers .= "Connection: close\r\n";
		$headers .= "Content-Length: ".(length $article)."\r\n";
		print $handle "$headers\r\n$article";
		}
	}