Author: lindner
Date: Tue Mar 18 17:29:25 2008
New Revision: 638660
URL: http://svn.apache.org/viewvc?rev=638660&view=rev
Log:
Apply patch from Chris Chabot for SHINDIG-128
- Re-factored config.php and context class to be a bit more logical and
readable.
- Added lazy loading to said context class which has some performance benefits.
- A modest start at adding JavaDoc documentation to the code
Modified:
incubator/shindig/trunk/php/gadgets/config.php
incubator/shindig/trunk/php/gadgets/index.php
incubator/shindig/trunk/php/gadgets/src/BasicRemoteContent.php
incubator/shindig/trunk/php/gadgets/src/CacheMemcache.php
incubator/shindig/trunk/php/gadgets/src/Gadget.php
incubator/shindig/trunk/php/gadgets/src/GadgetContext.php
incubator/shindig/trunk/php/gadgets/src/GadgetServer.php
incubator/shindig/trunk/php/gadgets/src/GadgetSpecParser.php
incubator/shindig/trunk/php/gadgets/src/RemoteContent.php
incubator/shindig/trunk/php/gadgets/src/http/FilesServlet.php
incubator/shindig/trunk/php/gadgets/src/http/GadgetRenderingServlet.php
incubator/shindig/trunk/php/gadgets/src/http/HttpServlet.php
incubator/shindig/trunk/php/gadgets/src/http/JsServlet.php
incubator/shindig/trunk/php/gadgets/src/http/ProxyHandler.php
incubator/shindig/trunk/php/gadgets/src/http/ProxyServlet.php
Modified: incubator/shindig/trunk/php/gadgets/config.php
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/gadgets/config.php?rev=638660&r1=638659&r2=638660&view=diff
==============================================================================
--- incubator/shindig/trunk/php/gadgets/config.php (original)
+++ incubator/shindig/trunk/php/gadgets/config.php Tue Mar 18 17:29:25 2008
@@ -19,6 +19,11 @@
'syndicator_config' =>
realpath(dirname(__FILE__)).'/../../config/syndicator.js',
'javascript_path' => realpath(dirname(__FILE__)).'/../../javascript/',
+ // If you want to use the yuicompressor
(http://developer.yahoo.com/yui/compressor/) to minify your javascript
+ // set this to the yuicompressor-?.jar's file path
+ //NOTE: not used yet, will be in the next patch
+ 'compressor_path' =>
realpath(dirname(__FILE__)).'/bin/yuicompressor-2.3.5.jar',
+
// Configurable classes to use, this way we provide extensibility for
what
// backends the gadget server uses for its logic functionality.
'blacklist_class' => 'BasicGadgetBlacklist',
@@ -46,10 +51,5 @@
'cache_root'=> '/tmp/shindig',
// In some cases we need to know the site root (for features
forinstance)
- 'base_path'=> realpath(dirname(__FILE__)),
-
- // We combine global and per request state in the config since it saves
a good bit of code
- // and global classes & variables, these are the HttpProcessingOptions
- 'ignoreCache' => (isset($_GET['nocache']) && intval($_GET['nocache'])
== 1) || (isset($_GET['bpc']) && intval($_GET['bpc']) == 1),
- 'focedJsLibs' => isset($_GET['libs']) ? trim($_GET['libs']) : null
+ 'base_path'=> realpath(dirname(__FILE__))
);
Modified: incubator/shindig/trunk/php/gadgets/index.php
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/gadgets/index.php?rev=638660&r1=638659&r2=638660&view=diff
==============================================================================
--- incubator/shindig/trunk/php/gadgets/index.php (original)
+++ incubator/shindig/trunk/php/gadgets/index.php Tue Mar 18 17:29:25 2008
@@ -38,7 +38,7 @@
function __autoload($className)
{
- require_once 'src/' . $className . '.php';
+ require 'src/' . $className . '.php';
}
$servletMap = array($config['web_prefix'] . '/files' => 'FilesServlet',
$config['web_prefix'] . '/js' => 'JsServlet', $config['web_prefix'] . '/proxy'
=> 'ProxyServlet', $config['web_prefix'] . '/ifr' => 'GadgetRenderingServlet',
$config['web_prefix'] . '/rpc' => 'RpcServlet');
Modified: incubator/shindig/trunk/php/gadgets/src/BasicRemoteContent.php
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/gadgets/src/BasicRemoteContent.php?rev=638660&r1=638659&r2=638660&view=diff
==============================================================================
--- incubator/shindig/trunk/php/gadgets/src/BasicRemoteContent.php (original)
+++ incubator/shindig/trunk/php/gadgets/src/BasicRemoteContent.php Tue Mar 18
17:29:25 2008
@@ -20,7 +20,7 @@
class BasicRemoteContent extends RemoteContent {
- public function fetch($request)
+ public function fetch($request, $context)
{
global $config;
$cache = new $config['data_cache']();
@@ -29,7 +29,7 @@
throw new RemoteContentException("Invalid request type
in remoteContent");
}
// determine which requests we can load from cache, and which
we have to actually fetch
- if (! $config['ignoreCache'] && ($cachedRequest =
$cache->get($request->toHash())) !== false) {
+ if (! $context->getIgnoreCache() && ($cachedRequest =
$cache->get($request->toHash())) !== false) {
$ret = $cachedRequest;
} else {
$ret = $remoteContentFetcher->fetchRequest($request);
Modified: incubator/shindig/trunk/php/gadgets/src/CacheMemcache.php
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/gadgets/src/CacheMemcache.php?rev=638660&r1=638659&r2=638660&view=diff
==============================================================================
--- incubator/shindig/trunk/php/gadgets/src/CacheMemcache.php (original)
+++ incubator/shindig/trunk/php/gadgets/src/CacheMemcache.php Tue Mar 18
17:29:25 2008
@@ -23,7 +23,6 @@
* usefull in a multi-server envirionment then the file based caching,
* (in a single server setup file based caching is actually faster)
*/
-
class CacheMemcache extends Cache {
private $connection = false;
Modified: incubator/shindig/trunk/php/gadgets/src/Gadget.php
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/gadgets/src/Gadget.php?rev=638660&r1=638659&r2=638660&view=diff
==============================================================================
--- incubator/shindig/trunk/php/gadgets/src/Gadget.php (original)
+++ incubator/shindig/trunk/php/gadgets/src/Gadget.php Tue Mar 18 17:29:25 2008
@@ -32,7 +32,7 @@
private $userPrefValues;
private $messageBundle = array();
// As in UserPref, no enums so fake it
- public $contentTypes = array('HTML', 'URL');
+ public $contentTypes = array('HTML', 'URL');
public $id;
public $author;
public $authorEmail;
@@ -49,86 +49,88 @@
public $title;
public $titleUrl = null;
public $userPrefs = array();
-
- public function __construct($id = false, $prefs = false)
+
+ public function __construct($id = false, $context)
{
- if ($id) $this->id = $id;
- if ($prefs) $this->userPrefValues = $prefs;
+ if ($id)
+ $this->id = $id;
+ if ($context->getUserPrefs())
+ $this->setPrefs($context->getUserPrefs());
$this->substitutions = new Substitutions();
$this->jsLibraries = array();
}
-
+
public function setId($id)
{
$this->id = $id;
}
-
+
public function setPrefs($prefs)
{
$this->userPrefValues = $prefs;
}
-
+
public function getAuthor()
{
return $this->substitutions->substitute($this->author);
}
-
+
public function getAuthorEmail()
{
return $this->substitutions->substitute($this->authorEmail);
}
-
+
public function getContentData($view = false)
{
if ($this->contentType != 'HTML') {
throw new SpecParserException("getContentData()
requires contentType HTML");
}
- if (empty($view) || !$view) {
+ if (empty($view) || ! $view) {
$view = DEFAULT_VIEW;
}
return
$this->substitutions->substitute(isset($this->contentData[$view]) ?
trim($this->contentData[$view]) : '');
}
-
+
public function getContentHref()
{
return $this->substitutions->substitute($this->getContentType()
== 'URL' ? $this->contentHref : null);
}
-
+
public function getMessageBundle()
{
return $this->messageBundle;
}
-
+
public function getDescription()
{
return $this->substitutions->substitute($this->description);
}
-
+
public function getDirectoryTitle()
{
return $this->substitutions->substitute($this->directoryTitle);
}
-
+
public function getId()
{
return $this->id;
}
-
+
public function getJsLibraries()
{
return $this->jsLibraries;
}
-
+
public function addJsLibrary($library)
{
$this->jsLibraries[] = $library;
}
-
+
public function getLocaleSpecs()
{
return $this->localeSpecs;
}
-
+
public function getFeatureParams($gadget, $feature)
{
//FIXME not working atm
@@ -140,65 +142,65 @@
return $spec->getParams();
}
}
-
+
public function getPreloads()
{
$ret = array();
- foreach ( $this->preloads as $preload ) {
+ foreach ($this->preloads as $preload) {
$ret[] = $this->substitutions->substitute($preload);
}
return $ret;
}
-
+
public function getRequires()
{
return $this->requires;
}
-
+
public function getScreenshot()
{
return $this->substitutions->substitute($this->screenshot);
}
-
+
public function getSubstitutions()
{
return $this->substitutions;
}
-
+
public function getThumbnail()
{
return $this->substitutions->substitute($this->thumbnail);
}
-
+
public function getTitle()
{
return $this->substitutions->substitute($this->title);
}
-
+
public function getTitleURI()
{
$ret = null;
- if (!empty($this->titleURI)) {
+ if (! empty($this->titleURI)) {
$ret =
$this->substitutions->substitute($this->titleURI);
}
return $ret;
}
-
+
public function getUserPrefs()
{
return $this->userPrefs;
}
-
+
public function getUserPrefValues()
{
return $this->userPrefValues;
}
-
+
public function setMessageBundle($messageBundle)
{
$this->messageBundle = $messageBundle;
}
-
+
/* gadget Spec functions */
public function addContent($view, $data)
{
@@ -210,7 +212,7 @@
}
$this->contentData[$view] .= $data;
}
-
+
public function getContentType()
{
return $this->contentType;
@@ -221,17 +223,17 @@
public $url;
public $locale;
public $rightToLeft;
-
+
public function getURI()
{
return $this->url;
}
-
+
public function getLocale()
{
return $this->locale;
}
-
+
public function isRightToLeft()
{
return $this->rightToLeft;
@@ -242,17 +244,17 @@
public $name;
public $params = array();
public $optional;
-
+
public function getName()
{
return $this->name;
}
-
+
public function getParams()
{
return $this->params;
}
-
+
public function isOptional()
{
return $this->optional;
@@ -268,32 +270,32 @@
public $required;
public $enumValues;
public $contentType;
-
+
public function getName()
{
return $this->name;
}
-
+
public function getDisplayName()
{
return $this->displayName;
}
-
+
public function getDefaultValue()
{
return $this->defaultValue;
}
-
+
public function isRequired()
{
return $this->required;
}
-
+
public function getDataType()
{
return $this->dataType;
}
-
+
public function getEnumValues()
{
return $this->enumValues;
Modified: incubator/shindig/trunk/php/gadgets/src/GadgetContext.php
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/gadgets/src/GadgetContext.php?rev=638660&r1=638659&r2=638660&view=diff
==============================================================================
--- incubator/shindig/trunk/php/gadgets/src/GadgetContext.php (original)
+++ incubator/shindig/trunk/php/gadgets/src/GadgetContext.php Tue Mar 18
17:29:25 2008
@@ -18,40 +18,300 @@
*
*/
+define('DEFAULT_VIEW', 'default');
+
/*
- * the httpFetcher (RemoteContentFetcher) is our cache too, so we skip the
- * messageBundleCache vars and params.
+ * GadgetContext contains all contextual variables and classes that are
relevant for this request,
+ * such as url, httpFetcher, feature registry, etc.
+ * Server wide variables are stored in config.php in the global $config array
*/
-
class GadgetContext {
- private $httpFetcher;
- private $locale;
- private $renderingContext;
- private $registry;
-
- public function __construct(RemoteContent $httpFetcher, Locale $locale,
$renderingContext, GadgetFeatureRegistry $registry)
+ private $httpFetcher = null;
+ private $locale = null;
+ private $renderingContext = null;
+ private $registry = null;
+ private $userPrefs = null;
+ private $gadgetId = null;
+ private $view = null;
+ private $moduleId = null;
+ private $url = null;
+ private $cache = null;
+ private $blacklist = null;
+ private $ignoreCache = null;
+ private $forcedJsLibs = null;
+
+ public function __construct($renderingContext)
+ {
+ // Rendering context is set by the calling event handler
(either GADGET or CONTAINER)
+ $this->setRenderingContext($renderingContext);
+
+ // Request variables
+ $this->setIgnoreCache($this->getIgnoreCacheParam());
+ $this->setForcedJsLibs($this->getFocedJsLibsParam());
+ $this->setUrl($this->getUrlParam());
+ $this->setModuleId($this->getModuleIdParam());
+ $this->setView($this->getViewParam());
+ //NOTE All classes are inititialized when called (aka lazy
loading) because we don't
+ //need all of them in every situation
+ }
+
+ private function getIgnoreCacheParam()
+ {
+ // Support both the old Orkut style &bpc and new standard style
&nocache= params
+ return (isset($_GET['nocache']) && intval($_GET['nocache']) ==
1) || (isset($_GET['bpc']) && intval($_GET['bpc']) == 1);
+ }
+
+ private function getFocedJsLibsParam()
+ {
+ return isset($_GET['libs']) ? trim($_GET['libs']) : null;
+ }
+
+ private function getUrlParam()
+ {
+ if (!empty($_GET['url'])) {
+ return $_GET['url'];
+ } elseif (!empty($_POST['url'])) {
+ return $_POST['url'];
+ }
+ return null;
+ }
+
+ private function getModuleIdParam()
+ {
+ return isset($_GET['mid']) && is_numeric($_GET['mid']) ?
intval($_GET['mid']) : 0;
+ }
+
+ private function getViewParam()
+ {
+ return ! empty($_GET['view']) ? $_GET['view'] : DEFAULT_VIEW;
+ }
+
+ private function instanceBlacklist()
+ {
+ global $config;
+ if (! empty($config['blacklist_class'])) {
+ return new $config['blacklist_class']();
+ } else {
+ return null;
+ }
+ }
+
+ private function instanceUserPrefs()
+ {
+ global $config;
+ $prefs = array();
+ foreach ($_GET as $key => $val) {
+ if (substr($key, 0,
strlen($config['userpref_param_prefix'])) == $config['userpref_param_prefix']) {
+ $name = substr($key,
strlen($config['userpref_param_prefix']));
+ $prefs[$name] = $val;
+ }
+ }
+ return new UserPrefs($prefs);
+ }
+
+ private function instanceGadgetId($url, $moduleId)
+ {
+ return new GadgetId($url, $moduleId);
+ }
+
+ private function instanceHttpFetcher()
+ {
+ global $config;
+ return new $config['remote_content']();
+ }
+
+ private function instanceCache()
+ {
+ global $config;
+ return new $config['data_cache']();
+ }
+
+ private function instanceRegistry()
+ {
+ global $config;
+ // Profiling showed 40% of the processing time was spend in the
feature registry
+ // So by caching this and making it a one time initialization,
we almost double the performance
+ if (! ($registry =
$this->getCache()->get(sha1($config['features_path'])))) {
+ $registry = new
GadgetFeatureRegistry($config['features_path']);
+ $this->getCache()->set(sha1($config['features_path']),
$registry);
+ }
+ return $registry;
+ }
+
+ private function instanceLocale()
+ {
+ $language = 'all';
+ $country = 'all';
+ if (! empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
+ $acceptLanguage = explode(';',
$_SERVER['HTTP_ACCEPT_LANGUAGE']);
+ $acceptLanguage = $acceptLanguage[0];
+ if (strpos($acceptLanguage, '-') !== false) {
+ $lang = explode('-', $acceptLanguage);
+ $language = $lang[0];
+ $country = $lang[1];
+ if (strpos($country, ',') !== false) {
+ $country = explode(',', $country);
+ $country = $country[0];
+ }
+ } else {
+ $language = $acceptLanguage;
+ }
+
+ }
+ return new Locale($language, $country);
+ }
+
+ public function getCache()
+ {
+ if ($this->cache == null) {
+ $this->setCache($this->instanceCache());
+ }
+ return $this->cache;
+ }
+
+ public function getGadgetId()
+ {
+ if ($this->gadgetId == null) {
+
$this->setGadgetId($this->instanceGadgetId($this->getUrl(),
$this->getModuleId()));
+ }
+ return $this->gadgetId;
+ }
+
+ public function getModuleId()
+ {
+ return $this->moduleId;
+ }
+
+ public function getRegistry()
+ {
+ if ($this->registry == null) {
+ $this->setRegistry($this->instanceRegistry());
+ }
+ return $this->registry;
+ }
+
+ public function getUrl()
+ {
+ return $this->url;
+ }
+
+ public function getUserPrefs()
+ {
+ if ($this->userPrefs == null) {
+ $this->setUserPrefs($this->instanceUserPrefs());
+ }
+ return $this->userPrefs;
+ }
+
+ public function getView()
+ {
+ return $this->view;
+ }
+
+ public function setBlacklist($blacklist)
+ {
+ $this->blacklist = $blacklist;
+ }
+
+ public function setCache($cache)
+ {
+ $this->cache = $cache;
+ }
+
+ public function setGadgetId($gadgetId)
+ {
+ $this->gadgetId = $gadgetId;
+ }
+
+ public function setHttpFetcher($httpFetcher)
{
$this->httpFetcher = $httpFetcher;
+ }
+
+ public function setLocale($locale)
+ {
$this->locale = $locale;
- $this->renderingContext = $renderingContext;
+ }
+
+ public function setModuleId($moduleId)
+ {
+ $this->moduleId = $moduleId;
+ }
+
+ public function setRegistry($registry)
+ {
$this->registry = $registry;
}
-
+
+ public function setRenderingContext($renderingContext)
+ {
+ $this->renderingContext = $renderingContext;
+ }
+
+ public function setUrl($url)
+ {
+ $this->url = $url;
+ }
+
+ public function setUserPrefs($userPrefs)
+ {
+ $this->userPrefs = $userPrefs;
+ }
+
+ public function setView($view)
+ {
+ $this->view = $view;
+ }
+
+ public function setIgnoreCache($ignoreCache)
+ {
+ $this->ignoreCache = $ignoreCache;
+ }
+
+ public function setForcedJsLibs($forcedJsLibs)
+ {
+ $this->forcedJsLibs = $forcedJsLibs;
+ }
+
+ public function getIgnoreCache()
+ {
+ return $this->ignoreCache;
+ }
+
+ public function getForcedJsLibs()
+ {
+ return $this->forcedJsLibs;
+ }
+
+ public function getBlacklist()
+ {
+ if ($this->blacklist == null) {
+ $this->setBlacklist($this->instanceBlacklist());
+ }
+ return $this->blacklist;
+ }
+
public function getRenderingContext()
{
return $this->renderingContext;
}
-
+
public function getHttpFetcher()
{
+ if ($this->httpFetcher == null) {
+ $this->setHttpFetcher($this->instanceHttpFetcher());
+ }
return $this->httpFetcher;
}
-
+
public function getLocale()
{
+ if ($this->locale == null) {
+ $this->setLocale($this->instanceLocale());
+ }
return $this->locale;
}
-
+
public function getFeatureRegistry()
{
return $this->registry;
Modified: incubator/shindig/trunk/php/gadgets/src/GadgetServer.php
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/gadgets/src/GadgetServer.php?rev=638660&r1=638659&r2=638660&view=diff
==============================================================================
--- incubator/shindig/trunk/php/gadgets/src/GadgetServer.php (original)
+++ incubator/shindig/trunk/php/gadgets/src/GadgetServer.php Tue Mar 18
17:29:25 2008
@@ -24,65 +24,48 @@
*/
class GadgetServer {
- private $registry;
- private $blacklist;
- private $gc;
- private $gadgetId;
- private $userPrefs;
- private $renderingContext;
- private $locale;
- private $httpFetcher;
-
- public function processGadget($gadgetId, $userPrefs, $locale, $rctx,
$httpFetcher, $registry)
- {
- global $config;
- $this->gadgetId = $gadgetId;
- $this->userPrefs = $userPrefs;
- $this->renderingContext = $rctx;
- $this->locale = $locale;
- $this->registry = $registry;
- $this->httpFetcher = $httpFetcher;
- $this->gc = new GadgetContext($httpFetcher, $locale, $rctx,
$registry);
- $this->blacklist = new $config['blacklist_class']();
- $gadget = $this->specLoad();
- $this->featuresLoad($gadget);
+
+ public function processGadget($context)
+ {
+ $gadget = $this->specLoad($context);
+ $this->featuresLoad($gadget, $context);
return $gadget;
}
-
- private function specLoad()
+
+ private function specLoad($context)
{
- if ($this->blacklist != null &&
$this->blacklist->isBlacklisted($this->gadgetId->getURI())) {
+ if ($context->getBlacklist() != null &&
$context->getBlacklist()->isBlacklisted($context->getUrl())) {
throw new GadgetException("Gadget is blacklisted");
}
- $request = new RemoteContentRequest($this->gadgetId->getURI());
- $xml = $this->httpFetcher->fetch($request);
+ $request = new RemoteContentRequest($context->geturl());
+ $xml = $context->getHttpFetcher()->fetch($request, $context);
if ($xml->getHttpCode() != '200') {
throw new GadgetException("Failed to retrieve gadget
content");
}
$specParser = new GadgetSpecParser();
- $gadget = $specParser->parse($xml->getResponseContent(),
$this->gadgetId, $this->userPrefs);
+ $gadget = $specParser->parse($xml->getResponseContent(),
$context);
return $gadget;
}
-
+
private function getBundle($localeSpec, $context)
{
if ($localeSpec != null) {
$uri = $localeSpec->getURI();
if ($uri != null) {
$fetcher = $context->getHttpFetcher();
- $response = $fetcher->fetch(new
RemoteContentRequest($uri));
+ $response = $fetcher->fetch(new
RemoteContentRequest($uri), $context);
$parser = new MessageBundleParser();
$bundle =
$parser->parse($response->getResponseContent());
- return $bundle;
+ return $bundle;
}
}
return null;
}
-
+
private function localeSpec($gadget, $locale)
{
$localeSpecs = $gadget->getLocaleSpecs();
- foreach ( $localeSpecs as $locSpec ) {
+ foreach ($localeSpecs as $locSpec) {
//fix me
if ($locSpec->getLocale()->equals($locale)) {
return $locSpec;
@@ -90,10 +73,10 @@
}
return null;
}
-
- private function getLocaleSpec($gadget)
+
+ private function getLocaleSpec($gadget, $context)
{
- $locale = $this->gc->getLocale();
+ $locale = $context->getLocale();
// en-US
$localeSpec = $this->localeSpec($gadget, $locale);
if ($localeSpec == null) {
@@ -106,15 +89,15 @@
}
return $localeSpec;
}
-
- private function featuresLoad($gadget)
+
+ private function featuresLoad($gadget, $context)
{
//NOTE i've been a bit liberal here with folding code into this
function, while it did get a bit long, the many include()'s are slowing us down
// Should really clean this up a bit in the future though
- $localeSpec = $this->getLocaleSpec($gadget);
+ $localeSpec = $this->getLocaleSpec($gadget, $context);
// get the message bundle for this gadget
- $bundle = $this->getBundle($localeSpec, $this->gc);
+ $bundle = $this->getBundle($localeSpec, $context);
//FIXME this is a half-assed solution between following the
refactoring and maintaining some of the old code, fixing this up later
$gadget->setMessageBundle($bundle);
@@ -142,7 +125,7 @@
// userPref's
$upValues = $gadget->getUserPrefValues();
- foreach ( $gadget->getUserPrefs() as $pref ) {
+ foreach ($gadget->getUserPrefs() as $pref) {
$name = $pref->getName();
$value = $upValues->getPref($name);
if ($value == null) {
@@ -158,7 +141,7 @@
$requires = $gadget->getRequires();
$needed = array();
$optionalNames = array();
- foreach ( $requires as $key => $entry ) {
+ foreach ($requires as $key => $entry) {
$needed[] = $key;
if ($entry->isOptional()) {
$optionalNames[] = $key;
@@ -168,8 +151,8 @@
$resultsMissing = array();
$missingOptional = array();
$missingRequired = array();
- $this->registry->getIncludedFeatures($needed, $resultsFound,
$resultsMissing);
- foreach ( $resultsMissing as $missingResult ) {
+ $context->getRegistry()->getIncludedFeatures($needed,
$resultsFound, $resultsMissing);
+ foreach ($resultsMissing as $missingResult) {
if (in_array($missingResult, $optionalNames)) {
$missingOptional[$missingResult] =
$missingResult;
} else {
@@ -181,18 +164,18 @@
}
// create features
$features = array();
- foreach ( $resultsFound as $entry ) {
- $features[$entry] =
$this->registry->getEntry($entry)->getFeature()->create();
+ foreach ($resultsFound as $entry) {
+ $features[$entry] =
$context->getRegistry()->getEntry($entry)->getFeature()->create();
}
// prepare them
- foreach ( $features as $key => $feature ) {
- $params = $gadget->getFeatureParams($gadget,
$this->registry->getEntry($key));
- $feature->prepare($gadget, $this->gc, $params);
+ foreach ($features as $key => $feature) {
+ $params = $gadget->getFeatureParams($gadget,
$context->getRegistry()->getEntry($key));
+ $feature->prepare($gadget, $context, $params);
}
// and process them
- foreach ( $features as $key => $feature ) {
- $params = $gadget->getFeatureParams($gadget,
$this->registry->getEntry($key));
- $feature->process($gadget, $this->gc, $params);
+ foreach ($features as $key => $feature) {
+ $params = $gadget->getFeatureParams($gadget,
$context->getRegistry()->getEntry($key));
+ $feature->process($gadget, $context, $params);
}
}
}
Modified: incubator/shindig/trunk/php/gadgets/src/GadgetSpecParser.php
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/gadgets/src/GadgetSpecParser.php?rev=638660&r1=638659&r2=638660&view=diff
==============================================================================
--- incubator/shindig/trunk/php/gadgets/src/GadgetSpecParser.php (original)
+++ incubator/shindig/trunk/php/gadgets/src/GadgetSpecParser.php Tue Mar 18
17:29:25 2008
@@ -18,12 +18,12 @@
*
*/
-class SpecParserException extends Exception {
-}
+class SpecParserException extends Exception {}
class GadgetSpecParser {
+
//public function parse(GadgetId $id, String $xml)
- public function parse($xml, $id, $prefs)
+ public function parse($xml, $context)
{
if (empty($xml)) {
throw new SpecParserException("Empty XML document");
@@ -35,28 +35,28 @@
if (count($doc->ModulePrefs) != 1) {
throw new SpecParserException("Missing or duplicated
<ModulePrefs>");
}
- $gadget = new Gadget($id, $prefs);
+ $gadget = new Gadget($context->getGadgetId(), $context);
// process ModulePref attributes
- $this->processModulePrefs($id, $gadget, $doc->ModulePrefs);
+ $this->processModulePrefs($gadget, $doc->ModulePrefs);
// process UserPrefs, if any
- foreach ( $doc->UserPref as $pref ) {
+ foreach ($doc->UserPref as $pref) {
$this->processUserPref($gadget, $pref);
}
- foreach ( $doc->Content as $content ) {
+ foreach ($doc->Content as $content) {
$this->processContent($gadget, $content);
}
//FIXME : should we add an else { throw new
SpecParserException("Missing <Content> block"); } here ? Java version doesn't
but it seems like we should ?
- foreach ( $doc->ModulePrefs->Require as $feature ) {
+ foreach ($doc->ModulePrefs->Require as $feature) {
$this->processFeature($gadget, $feature, true);
}
- foreach ( $doc->ModulePrefs->Optional as $feature ) {
+ foreach ($doc->ModulePrefs->Optional as $feature) {
$this->processFeature($gadget, $feature, false);
}
//TODO java version has a todo here for parsing icons
return $gadget;
}
-
- private function processModulePrefs($id, &$gadget, $ModulePrefs)
+
+ private function processModulePrefs(&$gadget, $ModulePrefs)
{
$attributes = $ModulePrefs->attributes();
if (empty($attributes['title'])) {
@@ -72,12 +72,11 @@
$gadget->screenshot = isset($attributes['screenshot']) ?
trim($attributes['screenshot']) : '';
$gadget->thumbnail = isset($attributes['thumbnail']) ?
trim($attributes['thumbnail']) : '';
$gadget->titleUrl = isset($attributes['title_url']) ?
trim($attributes['title_url']) : '';
- foreach ( $ModulePrefs->Locale as $locale ) {
+ foreach ($ModulePrefs->Locale as $locale) {
$gadget->localeSpecs[] = $this->processLocale($locale);
}
-
}
-
+
private function processLocale($locale)
{
$attributes = $locale->attributes();
@@ -93,7 +92,7 @@
$locale->locale = new Locale($languageAttr, $countryAttr);
return $locale;
}
-
+
private function processUserPref(&$gadget, $pref)
{
$attributes = $pref->attributes();
@@ -107,7 +106,7 @@
$preference->dataType = isset($attributes['datatype']) &&
in_array(strtoupper($attributes['datatype']), $preference->DataTypes) ?
strtoupper($attributes['datatype']) : 'STRING';
$preference->defaultValue = isset($attributes['default_value'])
? trim($attributes['default_value']) : '';
if (isset($pref->EnumValue)) {
- foreach ( $pref->EnumValue as $enum ) {
+ foreach ($pref->EnumValue as $enum) {
$attr = $enum->attributes();
// java based shindig doesn't throw an
exception here, but it -is- invalid and should trigger a parse error
if (empty($attr['value'])) {
@@ -120,7 +119,7 @@
}
$gadget->userPrefs[] = $preference;
}
-
+
private function processContent(&$gadget, $content)
{
$attributes = $content->attributes();
@@ -137,15 +136,15 @@
$gadget->contentHref = $url;
} else {
$gadget->contentType = 'HTML';
- $html = (string)$content; // no trim here since empty
lines can have structural meaning, so typecast to string instead
+ $html = (string) $content; // no trim here since empty
lines can have structural meaning, so typecast to string instead
$view = isset($attributes['view']) ?
trim($attributes['view']) : '';
$views = explode(',', $view);
- foreach ( $views as $view ) {
+ foreach ($views as $view) {
$gadget->addContent($view, $html);
}
}
}
-
+
private function processFeature(&$gadget, $feature, $required)
{
$featureSpec = new FeatureSpec();
@@ -155,7 +154,7 @@
}
$featureSpec->name = trim($attributes['feature']);
$featureSpec->optional = ! $required;
- foreach ( $feature->Param as $param ) {
+ foreach ($feature->Param as $param) {
$attr = $param->attributes();
if (empty($attr['name'])) {
throw new SpecParserException("Missing name
attribute in <Param>.");
Modified: incubator/shindig/trunk/php/gadgets/src/RemoteContent.php
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/gadgets/src/RemoteContent.php?rev=638660&r1=638659&r2=638660&view=diff
==============================================================================
--- incubator/shindig/trunk/php/gadgets/src/RemoteContent.php (original)
+++ incubator/shindig/trunk/php/gadgets/src/RemoteContent.php Tue Mar 18
17:29:25 2008
@@ -30,5 +30,5 @@
}
abstract class RemoteContent {
- abstract public function fetch($request);
+ abstract public function fetch($request, $context);
}
Modified: incubator/shindig/trunk/php/gadgets/src/http/FilesServlet.php
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/gadgets/src/http/FilesServlet.php?rev=638660&r1=638659&r2=638660&view=diff
==============================================================================
--- incubator/shindig/trunk/php/gadgets/src/http/FilesServlet.php (original)
+++ incubator/shindig/trunk/php/gadgets/src/http/FilesServlet.php Tue Mar 18
17:29:25 2008
@@ -18,8 +18,21 @@
*
*/
+/**
+ * This class serves files from the shindig_root/javascript directory, it was
created
+ * so that the shindig examples and javascript files would work out of the box
with
+ * the php version too
+ */
class FilesServlet extends HttpServlet {
+ /**
+ * Handles the get file request, if the file exists and is in the
correct
+ * location it's echo'd to the browser (with a basic content type
guessing
+ * based on the file extention, ie .js becomes text/javascript).
+ * If the file location falls outside of the shindig/javascript root a
+ * 400 Bad Request is returned, and if the file is inside of the root
+ * but doesn't exist a 404 error is returned
+ */
public function doGet()
{
global $config;
Modified:
incubator/shindig/trunk/php/gadgets/src/http/GadgetRenderingServlet.php
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/gadgets/src/http/GadgetRenderingServlet.php?rev=638660&r1=638659&r2=638660&view=diff
==============================================================================
--- incubator/shindig/trunk/php/gadgets/src/http/GadgetRenderingServlet.php
(original)
+++ incubator/shindig/trunk/php/gadgets/src/http/GadgetRenderingServlet.php Tue
Mar 18 17:29:25 2008
@@ -20,41 +20,43 @@
include ('src/Gadget.php');
-define('DEFAULT_VIEW', 'default');
-
+/**
+ * This class deals with the gadget rendering requests (in default config this
+ * would be /gadgets/ifr?url=<some gadget's url>). It uses the gadget server
and
+ * gadget context to render the xml to a valid html file, and outputs it.
+ *
+ */
class GadgetRenderingServlet extends HttpServlet {
-
+
+ /**
+ * Creates the gadget using the GadgetServer class and calls
outputGadget
+ *
+ */
public function doGet()
{
- global $config;
try {
if (empty($_GET['url'])) {
throw new GadgetException("Missing required
parameter: url");
}
- $url = trim($_GET['url']);
- $moduleId = isset($_GET['mid']) &&
is_numeric($_GET['mid']) ? intval($_GET['mid']) : 0;
- $httpFetcher = new $config['remote_content']();
- $view = ! empty($_GET['view']) ? $_GET['view'] :
DEFAULT_VIEW;
- $gadgetId = new GadgetId($url, $moduleId);
- $prefs = $this->getPrefsFromRequest();
- $locale = $this->getLocaleFromRequest();
- $cache = new $config['data_cache']();
- // Profiling showed 40% of the processing time was
spend in the feature registry
- // So by caching this and making it a one time
initialization, we almost double the performance
- if (! ($registry =
$cache->get(sha1($config['features_path'])))) {
- $registry = new
GadgetFeatureRegistry($config['features_path']);
- $cache->set(sha1($config['features_path']),
$registry);
- }
- // skipping the contentFilters bit, since there's no
way to include caja yet
- // hopefully a rpc service or command line version will
be available at some point
+ // GadgetContext builds up all the contextual variables
(based on the url or post)
+ // plus instances all required classes (feature
registry, fetcher, blacklist, etc)
+ $context = new GadgetContext('GADGET');
+ // Unfortunatly we can't do caja content filtering
here, hoping we'll have a RPC service
+ // or command line caja to use for this at some point
$gadgetServer = new GadgetServer();
- $gadget = $gadgetServer->processGadget($gadgetId,
$prefs, $locale, 'GADGET', $httpFetcher, $registry);
- $this->outputGadget($gadget, $view);
- } catch ( Exception $e ) {
+ $gadget = $gadgetServer->processGadget($context);
+ $this->outputGadget($gadget, $context);
+ } catch (Exception $e) {
$this->outputError($e);
}
}
-
+
+ /**
+ * If an error occured (Exception) this function echo's the Exception's
message
+ * and if the config['debug'] is true, shows the debug backtrace in a
div
+ *
+ * @param Exception $e the exception to show
+ */
private function outputError($e)
{
global $config;
@@ -69,33 +71,50 @@
}
echo "</body></html>";
}
-
+
+ /**
+ * Takes the gadget to output, and depending on its content type calls
either outputHtml-
+ * or outputUrlGadget
+ *
+ * @param Gadget $gadget gadget to render
+ * @param string $view the view to render (only valid with a html
content type)
+ */
private function outputGadget($gadget, $view)
{
- switch ( $gadget->getContentType()) {
- case 'HTML' :
+ switch ($gadget->getContentType()) {
+ case 'HTML':
$this->outputHtmlGadget($gadget, $view);
break;
- case 'URL' :
+ case 'URL':
$this->outputUrlGadget($gadget);
break;
}
}
-
- private function outputHtmlGadget($gadget, $view)
+
+ /**
+ * Outputs a html content type gadget.
+ * It creates a html page, with the javascripts from the features
inline into the page, plus
+ * calls to 'gadgets.config.init' with the syndicator configuration
(config/syndicator.js) and
+ * 'gadgets.Prefs.setMessages_' with all the substitutions. For
external javascripts it adds
+ * a <script> tag.
+ *
+ * @param Gadget $gadget
+ * @param GadgetContext $context
+ */
+ private function outputHtmlGadget($gadget, $context)
{
global $config;
$this->setContentType("text/html; charset=UTF-8");
$output = '';
- $output .= "<html><head>";
+ $output .= "<html>\n<head>\n";
// TODO: This is so wrong. (todo copied from java shindig, but
i would agree with it :))
- $output .= "<style
type=\"text/css\">body,td,div,span,p{font-family:arial,sans-serif;} a
{color:#0000cc;}a:visited {color:#551a8b;}a:active {color:#ff0000;}body{margin:
0px;padding: 0px;background-color:white;}</style>";
- $output .= "</head><body>";
+ $output .= "<style
type=\"text/css\">body,td,div,span,p{font-family:arial,sans-serif;} a
{color:#0000cc;}a:visited {color:#551a8b;}a:active {color:#ff0000;}body{margin:
0px;padding: 0px;background-color:white;}</style>\n";
+ $output .= "</head>\n<body>\n";
$externJs = "";
$inlineJs = "";
$externFmt = "<script src=\"%s\"></script>";
- $forcedLibs = $config['focedJsLibs'];
- foreach ( $gadget->getJsLibraries() as $library ) {
+ $forcedLibs = $context->getForcedJsLibs();
+ foreach ($gadget->getJsLibraries() as $library) {
$type = $library->getType();
if ($type == 'URL') {
// TODO: This case needs to be handled more
gracefully by the js
@@ -112,13 +131,12 @@
}
}
// Forced libs first.
- //FIXME this doesnt make any sense to me yet, should make it
actually do something :-)
if (! empty($forcedLibs)) {
$libs = explode(':', $forcedLibs);
$output .= sprintf($externFmt, $this->getJsUrl($libs));
}
if (strlen($inlineJs) > 0) {
- $output .= "<script><!--\n" . $inlineJs .
"\n-->\n</script>";
+ $output .= "<script><!--\n" . $inlineJs .
"\n-->\n</script>\n";
}
if (strlen($externJs) > 0) {
$output .= $externJs;
@@ -130,28 +148,35 @@
// remove both /* */ and // style comments, they crash the
json_decode function
$contents = preg_replace('/\/\/.*$/m', '',
preg_replace('@/\\*(?:.|[\\n\\r])*?\\*/@', '',
file_get_contents($config['syndicator_config'])));
$syndData = json_decode($contents, true);
-
+ // build the messages to include in the
gadgets.Prefs.setMessages_() javascript call
$msgs = '';
if ($gadget->getMessageBundle()) {
$bundle = $gadget->getMessageBundle();
$msgs = json_encode($bundle->getMessages());
}
- $output .= "\n<script>\ngadgets.config.init(" .
json_encode($syndData['gadgets.features']) .
");\ngadgets.Prefs.setMessages_(".$msgs.");\n</script>\n";
+ // Add the gadget.config.init and gadgets.Prefs.setMessages_
calls to the document
+ $output .= "\n<script>\ngadgets.config.init(" .
json_encode($syndData['gadgets.features']) . ");\ngadgets.Prefs.setMessages_("
. $msgs . ");\n</script>\n";
$gadgetExceptions = array();
- $content = $gadget->getContentData($view);
+ $content = $gadget->getContentData($context->getView());
if (empty($content)) {
// unknown view
- $gadgetExceptions[] = "View: '" . $view . "' invalid
for gadget: " . $gadget->getId()->getKey();
+ $gadgetExceptions[] = "View: '" . $context->getView() .
"' invalid for gadget: " . $gadget->getId()->getKey();
}
if (count($gadgetExceptions)) {
throw new GadgetException(print_r($gadgetExceptions,
true));
}
$output .= $content . "\n";
- $output .= "<script>gadgets.util.runOnLoadHandlers();</script>";
- $output .= "</body></html>";
+ $output .=
"<script>gadgets.util.runOnLoadHandlers();</script>\n";
+ $output .= "</body>\n</html>";
echo $output;
}
-
+
+ /**
+ * Output's a URL content type gadget, it adds
libs=<list:of:js:libraries>.js and user preferences
+ * to the href url, and redirects the browser to it
+ *
+ * @param Gadget $gadget
+ */
private function outputUrlGadget($gadget)
{
global $config;
@@ -165,7 +190,7 @@
$forcedLibs = $config['focedJsLibs'];
if ($forcedLibs == null) {
$reqs = $gadget->getRequires();
- foreach ( $reqs as $key => $val ) {
+ foreach ($reqs as $key => $val) {
$libs[] = $key;
}
} else {
@@ -181,7 +206,15 @@
header('Location: ' . $redirURI);
die();
}
-
+
+ /**
+ * Returns the requested libs (from getjsUrl) with the libs_param_name
prepended
+ * ie: in libs=core:caja:etc.js format
+ *
+ * @param string $libs the libraries
+ * @param Gadget $gadget
+ * @return string the libs=... string to append to the redirection url
+ */
private function appendLibsToQuery($libs, $gadget)
{
global $config;
@@ -191,12 +224,19 @@
$ret .= $this->getJsUrl($libs, $gadget);
return $ret;
}
-
+
+ /**
+ * Returns the user preferences in &up_<name>=<val> format
+ *
+ * @param array $libs array of features this gadget requires
+ * @param Gadget $gadget
+ * @return string the up_<name>=<val> string to use in the redirection
url
+ */
private function getPrefsQueryString($prefVals)
{
global $config;
$ret = '';
- foreach ( $prefVals->getPrefs() as $key => $val ) {
+ foreach ($prefVals->getPrefs() as $key => $val) {
$ret .= '&';
$ret .= $config['userpref_param_prefix'];
$ret .= urlencode($key);
@@ -205,16 +245,23 @@
}
return $ret;
}
-
+
+ /**
+ * generates the library string (core:caja:etc.js) including a checksum
of all the
+ * javascript content (?v=<sha1 of js) for cache busting
+ *
+ * @param string $libs
+ * @param Gadget $gadget
+ * @return string the list of libraries in core:caja:etc.js?v=checksum>
format
+ */
private function getJsUrl($libs, $gadget)
{
- global $config;
$buf = '';
if (! is_array($libs) || ! count($libs)) {
$buf = 'core';
} else {
$firstDone = false;
- foreach ( $libs as $lib ) {
+ foreach ($libs as $lib) {
if ($firstDone) {
$buf .= ':';
} else {
@@ -226,7 +273,7 @@
// Build a version string from the sha1() checksum of all
included javascript
// to ensure the client always has the right version
$inlineJs = '';
- foreach ( $gadget->getJsLibraries() as $library ) {
+ foreach ($gadget->getJsLibraries() as $library) {
$type = $library->getType();
if ($type != 'URL') {
$inlineJs .= $library->getContent() . "\n";
@@ -235,44 +282,4 @@
$buf .= ".js?v=" . sha1($inlineJs);
return $buf;
}
-
- // since we don't have a java style request.locale. we create our own
- // this parses formats like 'en', 'en-us', 'en-us;en-gb' etc
- //TODO should really verify that this really works with all locale
strings and that it doesn't trip over priority weight fields
- private function getLocaleFromRequest()
- {
- $language = 'all';
- $country = 'all';
- if (! empty($_SERVER['HTTP_ACCEPT_LANGUAGE'])) {
- $acceptLanguage = explode(';',
$_SERVER['HTTP_ACCEPT_LANGUAGE']);
- $acceptLanguage = $acceptLanguage[0];
- if (strpos($acceptLanguage, '-') !== false) {
- $lang = explode('-', $acceptLanguage);
- $language = $lang[0];
- $country = $lang[1];
- if (strpos($country, ',') !== false) {
- $country = explode(',', $country);
- $country = $country[0];
- }
- } else {
- $language = $acceptLanguage;
- }
-
- }
- return new Locale($language, $country);
- }
-
- private function getPrefsFromRequest()
- {
- global $config;
- $prefs = array();
- foreach ( $_GET as $key => $val ) {
- if (substr($key, 0,
strlen($config['userpref_param_prefix'])) == $config['userpref_param_prefix']) {
- $name = substr($key,
strlen($config['userpref_param_prefix']));
- $prefs[$name] = $val;
- }
- }
- return new UserPrefs($prefs);
- }
-
-}
\ No newline at end of file
+}
Modified: incubator/shindig/trunk/php/gadgets/src/http/HttpServlet.php
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/gadgets/src/http/HttpServlet.php?rev=638660&r1=638659&r2=638660&view=diff
==============================================================================
--- incubator/shindig/trunk/php/gadgets/src/http/HttpServlet.php (original)
+++ incubator/shindig/trunk/php/gadgets/src/http/HttpServlet.php Tue Mar 18
17:29:25 2008
@@ -23,10 +23,6 @@
* Mixed with some essentials to make propper http header handling
* happen in php.
*/
-
-class ServletException extends Exception {
-}
-
class HttpServlet {
private $lastModified = false;
private $contentType = 'text/html';
@@ -34,12 +30,22 @@
public $noHeaders = false;
private $noCache = false;
+ /**
+ * Enables output buffering so we can do correct header handling in the
destructor
+ *
+ */
public function __construct()
{
// to do our header magic, we need output buffering on
ob_start();
}
+ /**
+ * Enter description here...
+ * If noHeaders is false, it adds all the correct http/1.1 headers to
the request
+ * and deals with modified/expires/e-tags/etc. This makes the server
behave more like
+ * a real http server.
+ */
public function __destruct()
{
global $config;
@@ -92,40 +98,65 @@
}
}
+ /**
+ * Sets the content type of this request (forinstance: text/html or
text/javascript, etc)
+ *
+ * @param string $type content type header to use
+ */
public function setContentType($type)
{
$this->contentType = $type;
}
+ /**
+ * Returns the current content type
+ *
+ * @return string content type string
+ */
public function getContentType()
{
return $this->contentType;
}
+ /**
+ * returns the current last modified time stamp
+ *
+ * @return int timestamp
+ */
public function getLastModified()
{
return $this->lastModified;
}
+ /**
+ * Sets the last modified timestamp. It automaticly checks if this
timestamp
+ * is larger then its current timestamp, and if not ignores the call
+ *
+ * @param int $modified timestamp
+ */
public function setLastModified($modified)
{
$this->lastModified = max($this->lastModified, $modified);
}
+ /**
+ * Sets the noCache boolean. If its set to true, no-caching headers
will be send
+ * (pragma no cache, expiration in the past)
+ *
+ * @param boolean $cache send no-cache headers?
+ */
public function setNoCache($cache = false)
{
$this->noCache = $cache;
}
+ /**
+ * returns the noCache boolean
+ *
+ * @return boolean
+ */
public function getNoCache()
{
return $this->noCache;
}
-
- public function error($msg)
- {
- @ob_end_clean();
- header("HTTP/1.0 400 Bad Request", true);
- echo "<html><body><h1>400 - $msg</h1></body></html>";
- }
-}
\ No newline at end of file
+}
Modified: incubator/shindig/trunk/php/gadgets/src/http/JsServlet.php
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/gadgets/src/http/JsServlet.php?rev=638660&r1=638659&r2=638660&view=diff
==============================================================================
--- incubator/shindig/trunk/php/gadgets/src/http/JsServlet.php (original)
+++ incubator/shindig/trunk/php/gadgets/src/http/JsServlet.php Tue Mar 18
17:29:25 2008
@@ -18,8 +18,12 @@
*
*/
+/**
+ * This event handler deals with the /js/core:caja:etc.js request which
content type=url gadgets can use
+ * to retrieve our features javascript code
+ */
class JsServlet extends HttpServlet {
-
+
public function doGet()
{
global $config;
Modified: incubator/shindig/trunk/php/gadgets/src/http/ProxyHandler.php
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/gadgets/src/http/ProxyHandler.php?rev=638660&r1=638659&r2=638660&view=diff
==============================================================================
--- incubator/shindig/trunk/php/gadgets/src/http/ProxyHandler.php (original)
+++ incubator/shindig/trunk/php/gadgets/src/http/ProxyHandler.php Tue Mar 18
17:29:25 2008
@@ -24,14 +24,28 @@
// according to features/core/io.js, this is high on the list of things to
scrap
define('UNPARSEABLE_CRUFT', "throw 1; < don't be evil' >");
+/**
+ * The ProxyHandler class does the actual proxy'ing work. it deals both with
+ * GET and POST based input, and peforms a request based on the input, headers
and
+ * httpmethod params. It also deals with request signing and verification thru
the
+ * authz and st (security token) params.
+ *
+ */
class ProxyHandler {
- private $fetcher;
-
- public function __construct($fetcher)
+ private $context;
+
+ public function __construct($context)
{
- $this->fetcher = $fetcher;
+ $this->context = $context;
}
-
+
+ /**
+ * Fetches content and returns it in JSON format
+ *
+ * @param string $url the url to fetch
+ * @param GadgetSigner $signer the request signer to use
+ * @param string $method the http method to use (get or post) in making
the request
+ */
public function fetchJson($url, $signer, $method)
{
$token = $this->extractAndValidateToken($signer);
@@ -40,7 +54,7 @@
// Fetch the content and convert it into JSON.
// TODO: Fetcher needs to handle variety of HTTP methods.
$result = $this->fetchContent($signedUrl, $method);
- $status = (int)$result->getHttpCode();
+ $status = (int) $result->getHttpCode();
//header("HTTP/1.1 $status", true);
if ($status == 200) {
$output = '';
@@ -57,7 +71,15 @@
}
die();
}
-
+
+ /**
+ * Fetches the content and returns it as-is using the headers as
returned
+ * by the remote host.
+ *
+ * @param string $url the url to retrieve
+ * @param GadgetSigner $signer the GadgetSigner to use
+ * @param string $method either get or post
+ */
public function fetch($url, $signer, $method)
{
$token = $this->extractAndValidateToken($signer);
@@ -66,13 +88,14 @@
//TODO: Fetcher needs to handle variety of HTTP methods.
$result = $this->fetchContent($signedUrl, $method);
// TODO: Fetcher needs to handle variety of HTTP methods.
- $status = (int)$result->getHttpCode();
+ $status = (int) $result->getHttpCode();
if ($status == 200) {
$headers = explode("\n", $result->getResponseHeaders());
- foreach ( $headers as $header ) {
+ foreach ($headers as $header) {
if (strpos($header, ':')) {
$key = trim(substr($header, 0,
strpos($header, ':')));
$val = trim(substr($header,
strpos($header, ':') + 1));
+ // filter out headers that would
otherwise mess up our output
if (strcasecmp($key,
"Transfer-Encoding") != 0 && strcasecmp($key, "Cache-Control") != 0 &&
strcasecmp($key, "Expires") != 0 && strcasecmp($key, "Content-Length") != 0) {
header("$key: $val");
}
@@ -90,7 +113,14 @@
// make sure the HttpServlet destructor doesn't override ours
die();
}
-
+
+ /**
+ * Both fetch and fetchJson call this function to retrieve the actual
content
+ *
+ * @param string $signedUrl the signed url to fetch
+ * @param string $method either get or post
+ * @return the filled in request (RemoteContentRequest)
+ */
private function fetchContent($signedUrl, $method)
{
//TODO get actual character encoding from the request
@@ -98,8 +128,9 @@
// Extract the request headers from the $_SERVER super-global
(this -does- unfortunatly mean that any header that php doesn't understand
won't be proxied thru though)
// if this turns out to be a problem we could add support for
HTTP_RAW_HEADERS, but this depends on a php.ini setting, so i'd rather prevent
that from being required
$headers = '';
+ $context = new GadgetContext('GADGET');
$requestHeaders = $this->request_headers();
- foreach ( $requestHeaders as $key => $val ) {
+ foreach ($requestHeaders as $key => $val) {
if ($key != 'Keep-alive' && $key != 'Connection' &&
$key != 'Host' && $key != 'Accept' && $key != 'Accept-Encoding') {
// propper curl header format according to
http://www.php.net/manual/en/function.curl-setopt.php#80099
$headers .= "$key: $val\n";
@@ -114,7 +145,7 @@
if ($data) {
$data = urldecode($data);
$entries = explode('&', $data);
- foreach ( $entries as $entry ) {
+ foreach ($entries as $entry) {
$parts = explode('=', $entry);
// Process only if its a valid
value=something pair
if (count($parts) == 2) {
@@ -129,27 +160,47 @@
// even if postData is an empty string, it will still
post (since RemoteContentRquest checks if its false)
// so the request to POST is still honored
$request = new RemoteContentRequest($signedUrl,
$headers, $postData);
- $request = $this->fetcher->fetch($request);
+ $request =
$this->context->getHttpFetcher()->fetch($request, $context);
} else {
$request = new RemoteContentRequest($signedUrl,
$headers);
- $request = $this->fetcher->fetch($request);
+ $request =
$this->context->getHttpFetcher()->fetch($request, $context);
}
return $request;
}
-
+
+ /**
+ * Sets the caching headers (overwriting anything the remote host set)
to force
+ * the browser not to cache this.
+ *
+ */
private function setCachingHeaders()
{
// TODO: Re-implement caching behavior if appropriate.
header("Cache-Control: private; max-age=0", true);
header("Expires: " . gmdate("D, d M Y H:i:s", time() - 3000) .
" GMT", true);
}
-
+
+ /**
+ * Empty function, should make something practical here some day.
+ * it's function should be to validate the given url if its in
+ * correct http(s):port://location/url format
+ *
+ * @param string $url
+ * @return string the 'validated' url
+ */
private function validateUrl($url)
{
//TODO should really make a PHP version of the URI class and
validate in all the locations the java version does
return $url;
}
-
+
+ /**
+ * Extracts the 'st' token from the GET or POST params and calls the
+ * signer to validate the token
+ *
+ * @param GadgetSigner $signer the signer to use (configured in
config.php)
+ * @return string the token to use in the signed url
+ */
private function extractAndValidateToken($signer)
{
if ($signer == null) {
@@ -161,7 +212,14 @@
}
return $signer->createToken($token);
}
-
+
+ /**
+ * Signs a url with the GadgetToken
+ *
+ * @param string $originalUrl
+ * @param GadgetToken $token
+ * @return unknown
+ */
private function signUrl($originalUrl, $token)
{
$authz = isset($_GET['authz']) ? $_GET['authz'] : false;
@@ -177,8 +235,8 @@
}
return $token->signUrl($originalUrl, $method);
}
-
- function request_headers()
+
+ private function request_headers()
{
// Try to use apache's request headers if available
if (function_exists("apache_request_headers")) {
@@ -188,7 +246,7 @@
}
// if that failed, try to create them from the _SERVER
superglobal
$headers = array();
- foreach ( array_keys($_SERVER) as $skey ) {
+ foreach (array_keys($_SERVER) as $skey) {
if (substr($skey, 0, 5) == "HTTP_") {
$headername = str_replace(" ", "-",
ucwords(strtolower(str_replace("_", " ", substr($skey, 0, 5)))));
$headers[$headername] = $_SERVER[$skey];
Modified: incubator/shindig/trunk/php/gadgets/src/http/ProxyServlet.php
URL:
http://svn.apache.org/viewvc/incubator/shindig/trunk/php/gadgets/src/http/ProxyServlet.php?rev=638660&r1=638659&r2=638660&view=diff
==============================================================================
--- incubator/shindig/trunk/php/gadgets/src/http/ProxyServlet.php (original)
+++ incubator/shindig/trunk/php/gadgets/src/http/ProxyServlet.php Tue Mar 18
17:29:25 2008
@@ -22,36 +22,36 @@
include_once ("src/http/ProxyHandler.php");
class ProxyServlet extends HttpServlet {
-
+
public function doGet()
{
global $config;
- $this->noHeaders = true;
+ $this->noHeaders = true;
+ $context = new GadgetContext('GADGET');
// those should be doable in one statement, but php seems to
still evauluate the second ? and : pair,
// so throws an error about undefined index on post, even
though it found it in get ... odd bug
$url = isset($_GET['url']) ? $_GET['url'] : false;
- if (!$url) {
+ if (! $url) {
$url = isset($_POST['url']) ? $_POST['url'] : false;
}
$url = urldecode($url);
$method = isset($_GET['httpMethod']) ? $_GET['httpMethod'] :
false;
- if (!$method) {
- $method = isset($_POST['httpMethod']) ?
$_POST['httpMethod'] : 'GET';
+ if (! $method) {
+ $method = isset($_POST['httpMethod']) ?
$_POST['httpMethod'] : 'GET';
}
- if (!$url) {
+ if (! $url) {
header("HTTP/1.0 400 Bad Request", true);
echo "<html><body><h1>400 - Missing url
parameter</h1></body></html>";
}
$gadgetSigner = new $config['gadget_signer']();
- $httpFetcher = new $config['remote_content']();
- $proxyHandler = new ProxyHandler($httpFetcher);
+ $proxyHandler = new ProxyHandler($context);
if (! empty($_GET['output']) && $_GET['output'] == 'js') {
$proxyHandler->fetchJson($url, $gadgetSigner, $method);
} else {
$proxyHandler->fetch($url, $gadgetSigner, $method);
}
}
-
+
public function doPost()
{
$this->doGet();