Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added support for GZIP-compression and If-Unmodified-Since-header

  • Loading branch information...
commit 7bb4dc4e0fb1cc02ee0cad917b06cfabf4c7da9c 1 parent 85a350d
Yussuf Khalil authored
View
2  conf/config.example.yml
@@ -1,5 +1,5 @@
main:
- sysvpath: /usr/local/Pancake/sysv/ # Path to System V-Files
+ tmppath: /usr/local/Pancake/tmp/ # Path for temporary files
logging:
system: /usr/local/Pancake/log/system.log # Path to System-Log
request: /usr/local/Pancake/log/requests.log # Path to Request-Log
View
2  conf/skeleton.yml
@@ -1,6 +1,6 @@
# DO NOT EDIT THIS SKELETON-CONFIGURATION
main:
- sysvpath: /usr/local/Pancake/sysv/
+ tmppath: /usr/local/Pancake/tmp/
logging:
system: /usr/local/Pancake/log/system.log
request: /usr/local/Pancake/log/requests.log
View
3  conf/vhosts/example.yml
@@ -8,6 +8,9 @@
# - 127.0.0.1
# phpworkers: 3 # Amount of PHP-Workers to run
# writelimit: 1048576 # Limits the maximum data to be sent to the client at a time - Low value = less RAM-usage, but slower - High value = faster, but more RAM-usage
+# gzipmin: 1048576 # Minimum static filesize to use GZIP-compression
+# gziplevel: 1 # Level of the GZIP-compression - Lower = bigger size, less CPU-usage
+# enablegzip: false # Enable and disable GZIP-compression - We recommend leaving it disabled, it's better to precompress big files - GZIP-compression may produce very heavy CPU-load
# allowdirectorylistings: true # Enable directory listings
# index: # List of files allowed as directory-indexes
# - index.htm
View
25 sys/HTTPRequest.class.php
@@ -27,6 +27,7 @@ class Pancake_HTTPRequest {
private $requestLine = null;
private $rangeFrom = 0;
private $rangeTo = 0;
+ private $acceptedCompressions = array();
private static $answerCodes = array(
100 => 'Continue',
101 => 'Switching Protocols',
@@ -208,6 +209,21 @@ public function init($requestHeader) {
valid:
+ // Check for If-Unmodified-Since
+ if($this->getRequestHeader('If-Unmodified-Since')) {
+ if(filemtime($this->vHost->getDocumentRoot().$this->requestFilePath) != strtotime($this->getRequestHeader('If-Unmodified-Since')))
+ throw new Pancake_InvalidHTTPRequestException('File was modified since requested time.', 412, $requestHeader);
+ }
+
+ // Check for accepted compressions
+ if($this->getRequestHeader('Accept-Encoding')) {
+ $accepted = explode(',', $this->getRequestHeader('Accept-Encoding'));
+ foreach($accepted as $format) {
+ $format = strtolower(trim($format));
+ $this->acceptedCompressions[$format] = true;
+ }
+ }
+
// Check for Range-header
if($this->getRequestHeader('Range')) {
preg_match('~([0-9]+)-([0-9]+)?~', $this->getRequestHeader('Range'), $range);
@@ -525,6 +541,15 @@ public function getRangeTo() {
}
/**
+ * Check if client accepts a specific compression format
+ *
+ * @param string $compression Name of the compression, e. g. gzip, deflate, etc.
+ */
+ public function acceptsCompression($compression) {
+ return $this->acceptedCompressions[strtolower($compression)] === true;
+ }
+
+ /**
* Get Message corresponding to an AnswerCode
*
* @param int $code Valid AnswerCode, for example 200 or 404
View
2  sys/IPC.class.php
@@ -22,7 +22,7 @@ class Pancake_IPC {
*/
static public function create() {
// Create temporary file
- $tempFile = tempnam(Pancake_Config::get('main.sysvpath'), 'IPC');
+ $tempFile = tempnam(Pancake_Config::get('main.tmppath'), 'IPC');
// Create resource
self::$IPC = msg_get_queue(ftok($tempFile, 'p'));
View
2  sys/functions.php
@@ -43,7 +43,7 @@ function Pancake_out($text, $type = SYSTEM, $log = true, $debugMode = false) {
if(PANCAKE_DAEMONIZED !== true)
echo $message;
if($log === true && !fwrite($fileStream[$type], $message))
- Pancake_out('Couldn\'t write to logfile', SYSTEM, false);
+ trigger_error('Couldn\'t write to logfile', E_USER_WARNING);
return $message;
}
View
2  sys/sharedMemory.class.php
@@ -22,7 +22,7 @@ class Pancake_SharedMemory {
*/
static public function create() {
// Create temporary file
- $tempFile = tempnam(Pancake_Config::get('main.sysvpath'), 'SHMEM');
+ $tempFile = tempnam(Pancake_Config::get('main.tmppath'), 'SHMEM');
// Get filetoken for temporary file and attach Shared Memory
self::$sharedMemory = shm_attach(ftok($tempFile, 'p'), 10000000);
View
56 sys/threads/single/requestWorker.thread.php
@@ -194,18 +194,47 @@ function stop() {
$body .= '</body>';
$body .= '</html>';
$request->setAnswerBody($body);
- } else {
- $request->setHeader('Content-Type', $fileInfo->file($request->getvHost()->getDocumentRoot().$request->getRequestFilePath()));
- $request->setHeader('Content-Length', filesize($request->getvHost()->getDocumentRoot().$request->getRequestFilePath()) - $request->getRangeFrom());
- $request->setHeader('Accept-Ranges', 'bytes');
- $requestFileHandle = fopen($request->getvHost()->getDocumentRoot().$request->getRequestFilePath(), 'r');
+ } else {
+ $request->setHeader('Content-Type', $fileInfo->file($request->getvHost()->getDocumentRoot().$request->getRequestFilePath()));
+ $request->setHeader('Accept-Ranges', 'bytes');
+
+ // Check if GZIP-compression should be used
+ if($request->acceptsCompression('gzip') && $request->getvHost()->allowGZIPCompression() === true && filesize($request->getvHost()->getDocumentRoot().$request->getRequestFilePath()) >= $request->getvHost()->getGZIPMimimum()) {
+ // Set encoding-header
+ $request->setHeader('Transfer-Encoding', 'gzip');
+ // Create temporary file
+ $gzipPath = tempnam(Pancake_Config::get('main.tmppath'), 'GZIP');
+ $gzipFileHandle = gzopen($gzipPath, 'w' . $request->getvHost()->getGZIPLevel());
+ // Load uncompressed requested file
+ $requestedFileHandle = fopen($request->getvHost()->getDocumentRoot().$request->getRequestFilePath(), 'r');
+ // Compress file
+ while(!feof($requestedFileHandle))
+ gzwrite($gzipFileHandle, fread($requestedFileHandle, $request->getvHost()->getWriteLimit()));
+ // Close GZIP-resource and open normal file-resource
+ gzclose($gzipFileHandle);
+ $requestFileHandle = fopen($gzipPath, 'r');
+ // Set Content-Length
+ $request->setHeader('Content-Length', filesize($gzipPath) - $request->getRangeFrom());
+ // Check if we should send the file in parts
+ if(filesize($gzipPath) - $request->getRangeFrom() > $request->getvHost()->getWriteLimit())
+ $sendParts = true;
+ } else {
+ $request->setHeader('Content-Length', filesize($request->getvHost()->getDocumentRoot().$request->getRequestFilePath()) - $request->getRangeFrom());
+ $requestFileHandle = fopen($request->getvHost()->getDocumentRoot().$request->getRequestFilePath(), 'r');
+ if(filesize($request->getvHost()->getDocumentRoot().$request->getRequestFilePath()) - $request->getRangeFrom() > $request->getvHost()->getWriteLimit())
+ $sendParts = true;
+ }
+
+ // Check if a specific range was requested
if($request->getRangeFrom()) {
$request->setAnswerCode(206);
fseek($requestFileHandle, $request->getRangeFrom());
- $request->setHeader('Content-Range', 'bytes ' . $request->getRangeFrom().'-'.(filesize($request->getvHost()->getDocumentRoot().$request->getRequestFilePath()) - 1).'/'.filesize($request->getvHost()->getDocumentRoot().$request->getRequestFilePath()));
+ if($gzipPath)
+ $request->setHeader('Content-Range', 'bytes ' . $request->getRangeFrom().'-'.(filesize($gzipPath) - 1).'/'.filesize($gzipPath));
+ else
+ $request->setHeader('Content-Range', 'bytes ' . $request->getRangeFrom().'-'.(filesize($request->getvHost()->getDocumentRoot().$request->getRequestFilePath()) - 1).'/'.filesize($request->getvHost()->getDocumentRoot().$request->getRequestFilePath()));
}
- if(filesize($request->getvHost()->getDocumentRoot().$request->getRequestFilePath()) - $request->getRangeFrom() > $request->getvHost()->getWriteLimit())
- $sendParts = true;
+
$data = fread($requestFileHandle, $request->getvHost()->getWriteLimit());
$request->setAnswerBody($data);
unset($data);
@@ -216,6 +245,9 @@ function stop() {
// Get answer and its size
$answer = $request->buildAnswer();
+ // Output request-information
+ Pancake_out('REQ '.$request->getAnswerCode().' '.$ip.': '.$request->getRequestLine().' on vHost '.(($request->getvHost()) ? $request->getvHost()->getName() : null).' (via '.$request->getRequestHeader('Host').') - '.$request->getRequestHeader('User-Agent'), REQUEST);
+
// Check if user wants keep-alive-connection
if($request->getAnswerHeader('Connection') == 'keep-alive')
socket_set_option($requestSocket, SOL_SOCKET, SO_KEEPALIVE, 1);
@@ -227,7 +259,7 @@ function stop() {
socket_write($requestSocket, $answer);
// Send parts
- if($sendParts === true) {
+ if($sendParts === true && $request->getRequestType() != 'HEAD') {
while(!feof($requestFileHandle)) {
$data = fread($requestFileHandle, $request->getvHost()->getWriteLimit());
if(!socket_write($requestSocket, $data))
@@ -241,9 +273,6 @@ function stop() {
if(strtolower($request->getAnswerHeader('Connection')) != 'keep-alive')
socket_shutdown($requestSocket);
- // Output request-information
- Pancake_out('REQ '.$request->getAnswerCode().' '.$ip.': '.$request->getRequestLine().' on vHost '.(($request->getvHost()) ? $request->getvHost()->getName() : null).' (via '.$request->getRequestHeader('Host').') - '.$request->getRequestHeader('User-Agent'), REQUEST);
-
next:
if($request && !in_array($requestSocket, $listenSocketsOrig, true) && strtolower($request->getAnswerHeader('Connection')) == 'keep-alive')
@@ -266,6 +295,9 @@ function stop() {
unset($_GET);
unset($add);
unset($sendParts);
+ if($gzipPath)
+ unlink($gzipPath);
+ unset($gzipPath);
if(is_resource($requestFileHandle))
fclose($requestFileHandle);
View
32 sys/vHost.class.php
@@ -24,6 +24,9 @@ class Pancake_vHost {
private $authFiles = array();
private $writeLimit = 0;
private $allowDirectoryListings = false;
+ private $gzipMinimum = 0;
+ private $gzipLevel = -1;
+ private $allowGZIP = false;
/**
* Loads a vHost
@@ -51,6 +54,9 @@ public function __construct($name) {
$this->indexFiles = $config['index'];
$this->writeLimit = (int) $config['writelimit'];
$this->allowDirectoryListings = (bool) $config['allowdirectorylistings'];
+ $this->gzipMinimum = (int) $config['gzipmin'];
+ $this->gzipLevel = (int) $config['gziplevel'];
+ $this->allowGZIP = (bool) $config['enablegzip'];
// Load files and directories that need authentication
if($config['auth']) {
@@ -201,6 +207,30 @@ public function getWriteLimit() {
*/
public function allowDirectoryListings() {
return $this->allowDirectoryListings;
- }
+ }
+
+ /**
+ * Returns the minimum filesize for using GZIP-compression
+ *
+ */
+ public function getGZIPMimimum() {
+ return $this->gzipMinimum;
+ }
+
+ /**
+ * Returns the level of GZIP-compression to use
+ *
+ */
+ public function getGZIPLevel() {
+ return $this->gzipLevel;
+ }
+
+ /**
+ * Returns whether GZIP-compression can be used or not
+ *
+ */
+ public function allowGZIPCompression() {
+ return $this->allowGZIP;
+ }
}
?>
View
0  sysv/placeholder → tmp/placeholder
File renamed without changes
Please sign in to comment.
Something went wrong with that request. Please try again.