params = $params; } function get_archive_location() { $path_parts = array(); preg_match($this->params['pattern'], $this->params['vpath'], $path_parts); if (in_array($path_parts[1], array('boost-build', 'regression'))) { $this->params['version'] = null; $version_dir = $path_parts[1]; } else { $this->params['version'] = BoostVersion::from($path_parts[1]); $version_dir = is_numeric($path_parts[1][0]) ? "boost_{$path_parts[1]}" : $path_parts[1]; } $this->params['key'] = $path_parts[2]; $file = false; if ($this->params['fix_dir']) { $fix_path = "{$this->params['fix_dir']}/{$version_dir}/{$this->params['key']}"; if (is_file($fix_path) || (is_dir($fix_path) && is_file("{$fix_path}/index.html"))) { $this->params['zipfile'] = false; $file = $fix_path; } } if (!$file) { $file = ($this->params['zipfile'] ? '' : $this->params['archive_dir'] . '/'); if ($this->params['archive_subdir']) { $file = $file . $this->params['archive_file_prefix'] . $version_dir . '/' . $this->params['key']; } else { $file = $file . $this->params['archive_file_prefix'] . $this->params['key']; } } $this->params['file'] = $file; $this->params['archive'] = $this->params['zipfile'] ? str_replace('\\','/', $this->params['archive_dir'] . '/' . $version_dir . '.zip') : Null; } function display_from_archive($content_map = array()) { // Set default values $this->params = array_merge( array( 'pattern' => '@^[/]([^/]+)[/](.*)$@', 'vpath' => $_SERVER["PATH_INFO"], 'archive_subdir' => true, 'zipfile' => true, 'fix_dir' => false, 'archive_dir' => ARCHIVE_DIR, 'archive_file_prefix' => ARCHIVE_FILE_PREFIX, 'use_http_expire_date' => false, 'override_extractor' => null, 'title' => NULL, 'charset' => NULL, 'content' => NULL, 'error' => false, ), $this->params ); $this->get_archive_location(); // Only use a permanent redirect for releases (beta or full). $redirect_status_code = $this->params['version'] && $this->params['version']->is_numbered_release() ? 301 : 302; // Calculate expiry date if requested. $expires = null; if ($this->params['use_http_expire_date']) { if (!$this->params['version']) { $expires = "+1 week"; } else { $compare_version = BoostVersion::from($this->params['version'])-> compare(BoostVersion::current()); $expires = $compare_version === -1 ? "+1 year" : ($compare_version === 0 ? "+1 week" : "+1 day"); } } // Check file exists. if ($this->params['zipfile']) { $check_file = $this->params['archive']; if (!is_readable($check_file)) { error_page($this->params, 'Unable to find zipfile.'); return; } } else { $check_file = $this->params['file']; if (is_dir($check_file)) { if(substr($check_file, -1) != '/') { $redirect = resolve_url(basename($check_file).'/'); header("Location: $redirect", TRUE, $redirect_status_code); return; } $found_file = NULL; if (is_readable("$check_file/index.html")) $found_file = 'index.html'; else if (is_readable("$check_file/index.htm")) $found_file = 'index.htm'; if ($found_file) { $this->params['file'] = $check_file = $check_file.$found_file; $this->params['key'] = $this->params['key'].$found_file; } else { if (!http_headers('text/html', filemtime($check_file), $expires)) return; $display_dir = new BoostDisplayDir($this->params); return $display_dir->display($check_file); } } else if (!is_readable($check_file)) { error_page($this->params, 'Unable to find file.'); return; } } // Choose filter to use $info_map = array_merge($content_map, array( array('','@[.](txt|py|rst|jam|v2|bat|sh|xml|xsl|toyxml)$@i','text','text/plain'), array('','@[.](qbk|quickbook)$@i','qbk','text/plain'), array('','@[.](c|h|cpp|hpp)$@i','cpp','text/plain'), array('','@[.]png$@i','raw','image/png'), array('','@[.]gif$@i','raw','image/gif'), array('','@[.](jpg|jpeg|jpe)$@i','raw','image/jpeg'), array('','@[.]svg$@i','raw','image/svg+xml'), array('','@[.]css$@i','raw','text/css'), array('','@[.]js$@i','raw','application/x-javascript'), array('','@[.]pdf$@i','raw','application/pdf'), array('','@[.](html|htm)$@i','raw','text/html'), array('','@(/|^)(Jamroot|Jamfile|ChangeLog|configure)$@i','text','text/plain'), array('','@[.]dtd$@i','raw','application/xml-dtd'), )); $preprocess = null; $extractor = null; $type = null; foreach ($info_map as $i) { if (preg_match($i[1],$this->params['key'])) { if ($i[0]) { $version = BoostVersion::from($i[0]); if ($version->compare(BoostVersion::page()) > 0) { // This is after the current version. continue; } } $extractor = $i[2]; $type = $i[3]; $preprocess = isset($i[4]) ? $i[4] : NULL; break; } } if ($this->params['override_extractor']) $extractor = $this->params['override_extractor']; if (!$extractor) { if (strpos($_SERVER['HTTP_HOST'], 'www.boost.org') === false) { error_page($this->params, "No extractor found for filename."); } else { error_page($this->params); } return; } // Handle ETags and Last-Modified HTTP headers. // Output raw files. if($extractor == 'raw') { if (!http_headers($type, filemtime($check_file), $expires)) return; display_raw_file($this->params, $_SERVER['REQUEST_METHOD'], $type); } else { // Read file from hard drive or zipfile // Note: this sets $this->params['content'] with either the // content or an error message. if(!extract_file($this->params)) { error_page($this->params, $this->params['content']); return; } // Check if the file contains a redirect. if($type == 'text/html') { if($redirect = detect_redirect($this->params['content'])) { http_headers('text/html', null, "+1 day"); header("Location: $redirect", TRUE, $redirect_status_code); if($_SERVER['REQUEST_METHOD'] != 'HEAD') echo $this->params['content']; return; } } if (!http_headers('text/html', filemtime($check_file), $expires)) return; // Finally process the file and display it. if($_SERVER['REQUEST_METHOD'] != 'HEAD') { if ($preprocess) { $this->params['content'] = call_user_func($preprocess, $this->params['content']); } echo_filtered($extractor, $this->params); } } } } // HTTP header handling function http_headers($type, $last_modified, $expires = null) { header('Content-type: '.$type); switch($type) { case 'image/png': case 'image/gif': case 'image/jpeg': case 'text/css': case 'application/x-javascript': case 'application/pdf': case 'application/xml-dtd': header('Expires: '.date(DATE_RFC2822, strtotime("+1 year"))); header('Cache-Control: max-age=31556926'); // A year, give or take a day. break; default: if($expires) { header('Expires: '.date(DATE_RFC2822, strtotime($expires))); header('Cache-Control: max-age='.strtotime($expires, 0)); } break; } return conditional_get(max( strtotime(BOOST_DOCS_MODIFIED_DATE), // last manual documenation update filemtime(dirname(__FILE__).'/boost.php'), // last release (since the version number is updated) $last_modified // when the file was modified )); } function conditional_get($last_modified) { if(!$last_modified) return true; $last_modified_text = date(DATE_RFC2822, $last_modified); $etag = '"'.md5($last_modified).'"'; header("Last-Modified: $last_modified_text"); header("ETag: $etag"); $checked = false; if(isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { $checked = true; $if_modified_since = strtotime(stripslashes($_SERVER['HTTP_IF_MODIFIED_SINCE'])); if(!$if_modified_since || $if_modified_since < $last_modified) return true; } if(isset($_SERVER['HTTP_IF_NONE_MATCH'])) { $checked = true; if(stripslashes($_SERVER['HTTP_IF_NONE_MATCH'] != $etag)) return true; } if(!$checked) return true; header($_SERVER["SERVER_PROTOCOL"].' 304 Not Modified'); return false; } function display_raw_file($params, $method, $type) { ## header('Content-Disposition: attachment; filename="downloaded.pdf"'); if($params['zipfile']) { if ($method == 'HEAD') { $output = null; exec(unzip_command($params).' > /dev/null', $output, $exit_status); } else { $file_handle = popen(unzip_command($params), 'rb'); fpassthru($file_handle); $exit_status = pclose($file_handle); } // Don't display errors for a corrupt zip file, as we seemd to // be getting them for legitimate files. if($exit_status > 1) { unzip_error($params, $exit_status); if ($params['error']) { header("{$_SERVER["SERVER_PROTOCOL"]} {$params['error']}", true); } echo "Error extracting file: {$params['content']}"; } } else { if ($method != 'HEAD') { readfile($params['file']); } } } function extract_file(&$params) { if($params['zipfile']) { $file_handle = popen(unzip_command($params),'r'); $text = ''; while ($file_handle && !feof($file_handle)) { $text .= fread($file_handle,8*1024); } $exit_status = pclose($file_handle); if($exit_status == 0) { $params['content'] = $text; return true; } else { $params['content'] = null; if (strstr($_SERVER['HTTP_HOST'], 'beta')) { unzip_error($params, $exit_status); } return false; } } else { $params['content'] = file_get_contents($params['file']); return true; } } function unzip_command($params) { return UNZIP .' -p '.escapeshellarg($params['archive']) .' '.escapeshellarg($params['file']); } // // Filters // function echo_filtered($extractor, $params) { $name = "BoostFilter".underscore_to_camel_case($extractor); $extractor = new $name($params); $extractor->echo_filtered(); } function underscore_to_camel_case($name) { return str_replace(' ','', ucwords(str_replace('_', ' ', $name))); } /* File Not Found */ function error_page($params, $message = null) { if (!$params['error']) { $params['error'] = "404 Not Found"; } header("{$_SERVER["SERVER_PROTOCOL"]} {$params['error']}"); $head = <<
File "' . html_encode($params['file']) . '" not found.
'; if(!empty($params['zipfile'])) $content .= "Unzip error: "; $content .= html_encode($message); $content .= '
'; $filter = new BoostFilters($params); $filter->display_template(Array('head' => $head, 'content' => $content)); } /* * HTML processing functions */ function detect_redirect($content) { // Only check small files, since larger files are never redirects, and are // expensive to search. if(strlen($content) <= 2000 && preg_match( '@@i', $content, $redirect)) { return resolve_url($redirect[1]); } return false; } function latest_link($params) { if (!isset($params['version']) || $params['error']) { return; } $version = BoostVersion::from($params['version']); $current = BoostVersion::current(); switch ($current->compare($version)) { case 0: break; case 1: echo '