summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--feed.php1
-rw-r--r--inc/httputils.php198
-rw-r--r--inc/pageutils.php92
-rw-r--r--lib/exe/css.php1
-rw-r--r--lib/exe/fetch.php56
-rw-r--r--lib/exe/js.php1
6 files changed, 203 insertions, 146 deletions
diff --git a/feed.php b/feed.php
index 7150a8e1e..dd790fec5 100644
--- a/feed.php
+++ b/feed.php
@@ -14,6 +14,7 @@
require_once(DOKU_INC.'inc/feedcreator.class.php');
require_once(DOKU_INC.'inc/auth.php');
require_once(DOKU_INC.'inc/pageutils.php');
+ require_once(DOKU_INC.'inc/httputils.php');
//close session
session_write_close();
diff --git a/inc/httputils.php b/inc/httputils.php
new file mode 100644
index 000000000..271b8272f
--- /dev/null
+++ b/inc/httputils.php
@@ -0,0 +1,198 @@
+<?php
+/**
+ * Utilities for handling HTTP related tasks
+ *
+ * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+
+define('HTTP_MULTIPART_BOUNDARY','D0KuW1K1B0uNDARY');
+define('HTTP_HEADER_LF',"\r\n");
+define('HTTP_CHUNK_SIZE',16*1024);
+
+/**
+ * Checks and sets HTTP headers for conditional HTTP requests
+ *
+ * @author Simon Willison <swillison@gmail.com>
+ * @link http://simon.incutio.com/archive/2003/04/23/conditionalGet
+ * @param timestamp $timestamp lastmodified time of the cache file
+ * @returns void or exits with previously header() commands executed
+ */
+function http_conditionalRequest($timestamp){
+ // A PHP implementation of conditional get, see
+ // http://fishbowl.pastiche.org/archives/001132.html
+ $last_modified = substr(gmdate('r', $timestamp), 0, -5).'GMT';
+ $etag = '"'.md5($last_modified).'"';
+ // Send the headers
+ header("Last-Modified: $last_modified");
+ header("ETag: $etag");
+ // See if the client has provided the required headers
+ if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])){
+ $if_modified_since = stripslashes($_SERVER['HTTP_IF_MODIFIED_SINCE']);
+ }else{
+ $if_modified_since = false;
+ }
+
+ if (isset($_SERVER['HTTP_IF_NONE_MATCH'])){
+ $if_none_match = stripslashes($_SERVER['HTTP_IF_NONE_MATCH']);
+ }else{
+ $if_none_match = false;
+ }
+
+ if (!$if_modified_since && !$if_none_match){
+ return;
+ }
+
+ // At least one of the headers is there - check them
+ if ($if_none_match && $if_none_match != $etag) {
+ return; // etag is there but doesn't match
+ }
+
+ if ($if_modified_since && $if_modified_since != $last_modified) {
+ return; // if-modified-since is there but doesn't match
+ }
+
+ // Nothing has changed since their last request - serve a 304 and exit
+ header('HTTP/1.0 304 Not Modified');
+
+ // don't produce output, even if compression is on
+ ob_end_clean();
+ exit;
+}
+
+/**
+ * Let the webserver send the given file vi x-sendfile method
+ *
+ * @author Chris Smith <chris.eureka@jalakai.co.uk>
+ * @returns void or exits with previously header() commands executed
+ */
+function http_sendfile($file) {
+ global $conf;
+
+ //use x-sendfile header to pass the delivery to compatible webservers
+ if($conf['xsendfile'] == 1){
+ header("X-LIGHTTPD-send-file: $file");
+ ob_end_clean();
+ exit;
+ }elseif($conf['xsendfile'] == 2){
+ header("X-Sendfile: $file");
+ ob_end_clean();
+ exit;
+ }elseif($conf['xsendfile'] == 3){
+ header("X-Accel-Redirect: $file");
+ ob_end_clean();
+ exit;
+ }
+
+ return false;
+}
+
+/**
+ * Send file contents supporting rangeRequests
+ *
+ * This function exits the running script
+ *
+ * @param ressource $fh - file handle for an already open file
+ * @param int $size - size of the whole file
+ * @param int $mime - MIME type of the file
+ *
+ * @author Andreas Gohr <andi@splitbrain.org>
+ */
+function http_rangeRequest($fh,$size,$mime){
+ $ranges = array();
+ $isrange = false;
+
+ header('Accept-Ranges: bytes');
+
+ if(!isset($_SERVER['HTTP_RANGE'])){
+ // no range requested - send the whole file
+ $ranges[] = array(0,$size,$size);
+ }else{
+ $t = explode('=', $_SERVER['HTTP_RANGE']);
+ if (!$t[0]=='bytes') {
+ // we only understand byte ranges - send the whole file
+ $ranges[] = array(0,$size,$size);
+ }else{
+ $isrange = true;
+ // handle multiple ranges
+ $r = explode(',',$t[1]);
+ foreach($r as $x){
+ $p = explode('-', $x);
+ $start = (int)$p[0];
+ $end = (int)$p[1];
+ if (!$end) $end = $size - 1;
+ if ($start > $end || $start > $size || $end > $size){
+ header('HTTP/1.1 416 Requested Range Not Satisfiable');
+ print 'Bad Range Request!';
+ exit;
+ }
+ $len = $end - $start + 1;
+ $ranges[] = array($start,$end,$len);
+ }
+ }
+ }
+ $parts = count($ranges);
+
+ // now send the type and length headers
+ if(!$isrange){
+ header("Content-Type: $mime",true);
+ }else{
+ header('HTTP/1.1 206 Partial Content');
+ if($parts == 1){
+ header("Content-Type: $mime",true);
+ }else{
+ header('Content-Type: multipart/byteranges; boundary='.HTTP_MULTIPART_BOUNDARY,true);
+ }
+ }
+
+ // send all ranges
+ for($i=0; $i<$parts; $i++){
+ list($start,$end,$len) = $ranges[$i];
+
+ // multipart or normal headers
+ if($parts > 1){
+ echo HTTP_HEADER_LF.'--'.HTTP_MULTIPART_BOUNDARY.HTTP_HEADER_LF;
+ echo "Content-Type: $mime".HTTP_HEADER_LF;
+ echo "Content-Range: bytes $start-$end/$size".HTTP_HEADER_LF;
+ }else{
+ header("Content-Length: $len");
+ if($isrange){
+ header("Content-Range: bytes $start-$end/$size");
+ }
+ }
+
+ // send file content
+ fseek($fh,$start); //seek to start of range
+ $chunk = ($len > HTTP_CHUNK_SIZE) ? HTTP_CHUNK_SIZE : $len;
+ while (!feof($fh) && $chunk > 0) {
+ @set_time_limit(30); // large files can take a lot of time
+ print fread($fh, $chunk);
+ flush();
+ $len -= $chunk;
+ $chunk = ($len > HTTP_CHUNK_SIZE) ? HTTP_CHUNK_SIZE : $len;
+ }
+ }
+ if($parts > 1){
+ echo HTTP_HEADER_LF.'--'.HTTP_MULTIPART_BOUNDARY.'--'.HTTP_HEADER_LF;
+ }
+
+ // everything should be done here, exit
+ exit;
+}
+
+/**
+ * Check for a gzipped version and create if necessary
+ *
+ * return true if there exists a gzip version of the uncompressed file
+ * (samepath/samefilename.sameext.gz) created after the uncompressed file
+ *
+ * @author Chris Smith <chris.eureka@jalakai.co.uk>
+ */
+function http_gzip_valid($uncompressed_file) {
+ $gzip = $uncompressed_file.'.gz';
+ if (filemtime($gzip) < filemtime($uncompressed_file)) { // filemtime returns false (0) if file doesn't exist
+ return copy($uncompressed_file, 'compress.zlib://'.$gzip);
+ }
+
+ return true;
+}
diff --git a/inc/pageutils.php b/inc/pageutils.php
index 105cfa18e..872191d12 100644
--- a/inc/pageutils.php
+++ b/inc/pageutils.php
@@ -528,97 +528,5 @@ function isVisiblePage($id){
return !isHiddenPage($id);
}
-/**
- * Checks and sets HTTP headers for conditional HTTP requests
- *
- * @author Simon Willison <swillison@gmail.com>
- * @link http://simon.incutio.com/archive/2003/04/23/conditionalGet
- * @param timestamp $timestamp lastmodified time of the cache file
- * @returns void or exits with previously header() commands executed
- */
-function http_conditionalRequest($timestamp){
- // A PHP implementation of conditional get, see
- // http://fishbowl.pastiche.org/archives/001132.html
- $last_modified = substr(gmdate('r', $timestamp), 0, -5).'GMT';
- $etag = '"'.md5($last_modified).'"';
- // Send the headers
- header("Last-Modified: $last_modified");
- header("ETag: $etag");
- // See if the client has provided the required headers
- if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])){
- $if_modified_since = stripslashes($_SERVER['HTTP_IF_MODIFIED_SINCE']);
- }else{
- $if_modified_since = false;
- }
-
- if (isset($_SERVER['HTTP_IF_NONE_MATCH'])){
- $if_none_match = stripslashes($_SERVER['HTTP_IF_NONE_MATCH']);
- }else{
- $if_none_match = false;
- }
-
- if (!$if_modified_since && !$if_none_match){
- return;
- }
-
- // At least one of the headers is there - check them
- if ($if_none_match && $if_none_match != $etag) {
- return; // etag is there but doesn't match
- }
-
- if ($if_modified_since && $if_modified_since != $last_modified) {
- return; // if-modified-since is there but doesn't match
- }
-
- // Nothing has changed since their last request - serve a 304 and exit
- header('HTTP/1.0 304 Not Modified');
-
- // don't produce output, even if compression is on
- ob_end_clean();
- exit;
-}
-/**
- * Let the webserver send the given file vi x-sendfile method
- *
- * @author Chris Smith <chris.eureka@jalakai.co.uk>
- * @returns void or exits with previously header() commands executed
- */
-function http_sendfile($file) {
- global $conf;
-
- //use x-sendfile header to pass the delivery to compatible webservers
- if($conf['xsendfile'] == 1){
- header("X-LIGHTTPD-send-file: $file");
- ob_end_clean();
- exit;
- }elseif($conf['xsendfile'] == 2){
- header("X-Sendfile: $file");
- ob_end_clean();
- exit;
- }elseif($conf['xsendfile'] == 3){
- header("X-Accel-Redirect: $file");
- ob_end_clean();
- exit;
- }
-
- return false;
-}
-
-/**
- * Check for a gzipped version and create if necessary
- *
- * return true if there exists a gzip version of the uncompressed file
- * (samepath/samefilename.sameext.gz) created after the uncompressed file
- *
- * @author Chris Smith <chris.eureka@jalakai.co.uk>
- */
-function http_gzip_valid($uncompressed_file) {
- $gzip = $uncompressed_file.'.gz';
- if (filemtime($gzip) < filemtime($uncompressed_file)) { // filemtime returns false (0) if file doesn't exist
- return copy($uncompressed_file, 'compress.zlib://'.$gzip);
- }
-
- return true;
-}
//Setup VIM: ex: et ts=2 enc=utf-8 :
diff --git a/lib/exe/css.php b/lib/exe/css.php
index 7fa56f4cc..2517db38d 100644
--- a/lib/exe/css.php
+++ b/lib/exe/css.php
@@ -11,6 +11,7 @@ if(!defined('NOSESSION')) define('NOSESSION',true); // we do not use a session o
if(!defined('DOKU_DISABLE_GZIP_OUTPUT')) define('DOKU_DISABLE_GZIP_OUTPUT',1); // we gzip ourself here
require_once(DOKU_INC.'inc/init.php');
require_once(DOKU_INC.'inc/pageutils.php');
+require_once(DOKU_INC.'inc/httputils.php');
require_once(DOKU_INC.'inc/io.php');
require_once(DOKU_INC.'inc/confutils.php');
diff --git a/lib/exe/fetch.php b/lib/exe/fetch.php
index ddfff4b4e..728b0b448 100644
--- a/lib/exe/fetch.php
+++ b/lib/exe/fetch.php
@@ -12,12 +12,12 @@
require_once(DOKU_INC.'inc/common.php');
require_once(DOKU_INC.'inc/media.php');
require_once(DOKU_INC.'inc/pageutils.php');
+ require_once(DOKU_INC.'inc/httputils.php');
require_once(DOKU_INC.'inc/confutils.php');
require_once(DOKU_INC.'inc/auth.php');
//close sesseion
session_write_close();
- if(!defined('CHUNK_SIZE')) define('CHUNK_SIZE',16*1024);
$mimetypes = getMimeTypes();
@@ -139,24 +139,10 @@ function sendFile($file,$mime,$dl,$cache){
//use x-sendfile header to pass the delivery to compatible webservers
if (http_sendfile($file)) exit;
- //support download continueing
- header('Accept-Ranges: bytes');
- list($start,$len) = http_rangeRequest(filesize($file));
-
// send file contents
$fp = @fopen($file,"rb");
if($fp){
- fseek($fp,$start); //seek to start of range
-
- $chunk = ($len > CHUNK_SIZE) ? CHUNK_SIZE : $len;
- while (!feof($fp) && $chunk > 0) {
- @set_time_limit(30); // large files can take a lot of time
- print fread($fp, $chunk);
- flush();
- $len -= $chunk;
- $chunk = ($len > CHUNK_SIZE) ? CHUNK_SIZE : $len;
- }
- fclose($fp);
+ http_rangeRequest($fp,filesize($file),$mime);
}else{
header("HTTP/1.0 500 Internal Server Error");
print "Could not read $file - bad permissions?";
@@ -164,44 +150,6 @@ function sendFile($file,$mime,$dl,$cache){
}
/**
- * Checks and sets headers to handle range requets
- *
- * @author Andreas Gohr <andi@splitbrain.org>
- * @returns array The start byte and the amount of bytes to send
- */
-function http_rangeRequest($size){
- if(!isset($_SERVER['HTTP_RANGE'])){
- // no range requested - send the whole file
- header("Content-Length: $size");
- return array(0,$size);
- }
-
- $t = explode('=', $_SERVER['HTTP_RANGE']);
- if (!$t[0]=='bytes') {
- // we only understand byte ranges - send the whole file
- header("Content-Length: $size");
- return array(0,$size);
- }
-
- $r = explode('-', $t[1]);
- $start = (int)$r[0];
- $end = (int)$r[1];
- if (!$end) $end = $size - 1;
- if ($start > $end || $start > $size || $end > $size){
- header('HTTP/1.1 416 Requested Range Not Satisfiable');
- print 'Bad Range Request!';
- exit;
- }
-
- $tot = $end - $start + 1;
- header('HTTP/1.1 206 Partial Content');
- header("Content-Range: bytes {$start}-{$end}/{$size}");
- header("Content-Length: $tot");
-
- return array($start,$tot);
-}
-
-/**
* Returns the wanted cachetime in seconds
*
* Resolves named constants
diff --git a/lib/exe/js.php b/lib/exe/js.php
index 7746edcd9..7ba777928 100644
--- a/lib/exe/js.php
+++ b/lib/exe/js.php
@@ -12,6 +12,7 @@ if(!defined('NL')) define('NL',"\n");
if(!defined('DOKU_DISABLE_GZIP_OUTPUT')) define('DOKU_DISABLE_GZIP_OUTPUT',1); // we gzip ourself here
require_once(DOKU_INC.'inc/init.php');
require_once(DOKU_INC.'inc/pageutils.php');
+require_once(DOKU_INC.'inc/httputils.php');
require_once(DOKU_INC.'inc/io.php');
require_once(DOKU_INC.'inc/JSON.php');