summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEvan Prodromou <evan@prodromou.name>2008-06-13 10:49:13 -0400
committerEvan Prodromou <evan@prodromou.name>2008-06-13 10:49:13 -0400
commita86477aad3bab8ad519626c56e3e253faea50518 (patch)
tree893cc9bc7c1b6e6a69e30b1087d9fd6b6d1d07d7
parentad7aa68a9917c9b53c8974f9002699a8efab54ee (diff)
add content negotiation for media type
darcs-hash:20080613144913-84dde-3e970b4e6f19ea1e0db09d7ab133a6c148be7a75.gz
-rw-r--r--doc/roadmap12
-rw-r--r--lib/util.php94
2 files changed, 99 insertions, 7 deletions
diff --git a/doc/roadmap b/doc/roadmap
index a3e725833..4caeb4e61 100644
--- a/doc/roadmap
+++ b/doc/roadmap
@@ -91,8 +91,8 @@ First public release (theoretically). Added distributed subscriptions,
+ log of consumers who ask for access
+ receive remote notice
+ send remote notice
-- receive remote profile update
-- send remote profile update
++ receive remote profile update
++ send remote profile update
+ subscribe form for not-logged-in users on showstream
+ pretty URLs
+ doc action
@@ -138,8 +138,8 @@ First public release (theoretically). Added distributed subscriptions,
- graphic refresh on remotesubscribe
+ graphic refresh on shownotice
+ graphic refresh on showstream
-- graphic refresh on subscribed
-- graphic refresh on subscriptions
++ graphic refresh on subscribed
++ graphic refresh on subscriptions
+ graphic refresh on userauthorization
- update default theme to use new, more semantic, HTML
- subscribe/unsubscribe on subscriptions page
@@ -147,10 +147,12 @@ First public release (theoretically). Added distributed subscriptions,
+ correct use of views menu in settings
+ correct use of views menu in streams
- INSTALL file
+- content negotiation for content type
Release 0.4
-----------
+- jQuery for as much as possible
- microid for profile page
- format times per user
- timezone preferences in Profile settings
@@ -164,8 +166,6 @@ Release 0.4
- email confirmation for registration
- email options
- change cookie handling for anon users to be more cache-friendly
-- jQuery for as much as possible
-- content negotiation for content type
- content negotiation for encoding
- If-Modified-Since support
- Vary
diff --git a/lib/util.php b/lib/util.php
index d6c1a9f8b..e1e508176 100644
--- a/lib/util.php
+++ b/lib/util.php
@@ -123,10 +123,24 @@ function common_end_xml() {
$xw->flush();
}
+define('PAGE_TYPE_PREFS', 'application/xhtml+xml,text/html;q=0.7,application/xml;q=0.3,text/xml;q=0.2');
+
function common_show_header($pagetitle, $callable=NULL, $data=NULL, $headercall=NULL) {
global $config, $xw;
- header('Content-Type: application/xhtml+xml');
+ $httpaccept = isset($_SERVER['HTTP_ACCEPT']) ? $_SERVER['HTTP_ACCEPT'] : NULL;
+
+ # XXX: allow content negotiation for RDF, RSS, or XRDS
+
+ $type = common_negotiate_type(common_accept_to_prefs($httpaccept),
+ common_accept_to_prefs(PAGE_TYPE_PREFS));
+
+ if (!$type) {
+ common_client_error(_t('This page is not available in a media type you accept'), 406);
+ exit(0);
+ }
+
+ header('Content-Type: '.$type);
common_start_xml('html',
'-//W3C//DTD XHTML 1.0 Strict//EN',
@@ -736,3 +750,81 @@ function common_pagination($have_before, $have_after, $page, $action, $args=NULL
common_element_end('div');
}
}
+
+/* Following functions are copied from MediaWiki GlobalFunctions.php
+ * and written by Evan Prodromou. */
+
+function common_accept_to_prefs($accept, $def = '*/*') {
+ # No arg means accept anything (per HTTP spec)
+ if(!$accept) {
+ return array($def => 1);
+ }
+
+ $prefs = array();
+
+ $parts = explode(',', $accept);
+
+ foreach($parts as $part) {
+ # FIXME: doesn't deal with params like 'text/html; level=1'
+ @list($value, $qpart) = explode(';', $part);
+ $match = array();
+ if(!isset($qpart)) {
+ $prefs[$value] = 1;
+ } elseif(preg_match('/q\s*=\s*(\d*\.\d+)/', $qpart, $match)) {
+ $prefs[$value] = $match[1];
+ }
+ }
+
+ return $prefs;
+}
+
+function common_mime_type_match($type, $avail) {
+ if(array_key_exists($type, $avail)) {
+ return $type;
+ } else {
+ $parts = explode('/', $type);
+ if(array_key_exists($parts[0] . '/*', $avail)) {
+ return $parts[0] . '/*';
+ } elseif(array_key_exists('*/*', $avail)) {
+ return '*/*';
+ } else {
+ return NULL;
+ }
+ }
+}
+
+function common_negotiate_type($cprefs, $sprefs) {
+ $combine = array();
+
+ foreach(array_keys($sprefs) as $type) {
+ $parts = explode('/', $type);
+ if($parts[1] != '*') {
+ $ckey = common_mime_type_match($type, $cprefs);
+ if($ckey) {
+ $combine[$type] = $sprefs[$type] * $cprefs[$ckey];
+ }
+ }
+ }
+
+ foreach(array_keys($cprefs) as $type) {
+ $parts = explode('/', $type);
+ if($parts[1] != '*' && !array_key_exists($type, $sprefs)) {
+ $skey = common_mime_type_match($type, $sprefs);
+ if($skey) {
+ $combine[$type] = $sprefs[$skey] * $cprefs[$type];
+ }
+ }
+ }
+
+ $bestq = 0;
+ $besttype = NULL;
+
+ foreach(array_keys($combine) as $type) {
+ if($combine[$type] > $bestq) {
+ $besttype = $type;
+ $bestq = $combine[$type];
+ }
+ }
+
+ return $besttype;
+}