When reloading a resource, yes. With basic requests the value is longer, though equally ill-conceived. The former is behaviour that Microsoft should fix as soon as possible. The latter should be changed before Microsoft supports XHTML properly. Microsoft should also add image/png to the Accept header value now that it has adequate support for PNG images.
There are no requirements regarding content negotiation, only recommendations (which are violated, in another way, by Ryan's code). Even so, those recommendations don't lead to your conclusion:Quote:
so by the laws of content negotiation
If a media range matches two or more available variants, the server is free to send any of them. Typically, it is the variant preferred by the author, but that is a subjective choice.Quote:
one should send it XHTML.
The technique for dealing with IE, and any user agent with similar behaviour, is simple: only serve XHTML if the media type is matched exactly. The code attached and posted below demonstrates this approach. Please excuse the mismatch in filenames; the board won't allow the upload of .php files.
Mike
PHP Code:<?php
require_once('media-range.php');
require_once('media-type.php');
header('Content-Type: text/plain');
echo "{$_SERVER['HTTP_ACCEPT']}\r\n";
$acceptableRanges = getAcceptableMediaRanges();
$availableVariants = array(MediaType::createInstance('application/xhtml+xml'),
MediaType::createInstance('text/html'));
$variant = findBestVariant($acceptableRanges, $availableVariants);
echo 'Normal negotiation: ', is_null($variant) ? 'No acceptable variants!' : $variant, "\r\n";
$variant = findBestMarkupVariant($acceptableRanges, $availableVariants);
echo 'Modified negotiation: ', is_null($variant) ? 'No acceptable variants!' : $variant, "\r\n";
/* Returns the best variant, as a MediaType object, accepted by the client based on media type. If
* no variants are acceptable, null is returned.
*
* $acceptableMediaRanges: an array of MediaRange objects that the client finds acceptable. This
* array must be sorted in ascending order of precedence.
* $availableVariants: an array of MediaType objects that represent the variants that can be sent
* from the server to the client.
*/
function findBestVariant(array $acceptableMediaRanges, array $availableVariants) {
$bestVariant = null;
$bestScore = 0.0;
foreach ($availableVariants as $variant) {
$i = count($acceptableMediaRanges);
while ($i--) {
$mediaRange = $acceptableMediaRanges[$i];
if ($mediaRange->match($variant) && ($mediaRange->getQuality() > $bestScore)) {
$bestVariant = $variant;
$bestScore = $mediaRange->getQuality();
}
}
}
return $bestVariant;
}
/* Returns the best markup variant, as a MediaType object, accepted by the client based on media
* type. The function considers the relative lack of support for XHTML, only returning such a
* variant if the user agent accepts it specifically using a concrete media type. If no variants
* are acceptable, null is returned.
*
* $acceptableMediaRanges: an array of MediaRange objects that the client finds acceptable. This
* array must be sorted in ascending order of precedence.
* $availableVariants: an array of MediaType objects that represent the variants that can be sent
* from the server to the client.
*/
function findBestMarkupVariant(array $acceptableMediaRanges, array $availableVariants) {
$bestVariant = null;
$bestScore = 0.0;
foreach ($availableVariants as $variant) {
$i = count($acceptableMediaRanges);
while ($i--) {
$mediaRange = $acceptableMediaRanges[$i];
if ($mediaRange->match($variant) && ($mediaRange->getQuality() > $bestScore)
&& (($variant->getType() != 'application')
|| ($variant->getSubtype() != 'xhtml+xml')
|| !$mediaRange->isSubtypeRange())) {
$bestVariant = $variant;
$bestScore = $mediaRange->getQuality();
}
}
}
return $bestVariant;
}
/* Returns an array of MediaRange objects that represents the media types accepted by the client.
* The array is sorted by ascending precedence.
*/
function getAcceptableMediaRanges() {
if (isset($_SERVER['HTTP_ACCEPT'])) {
if (!preg_match_all('<\s*((?:[^,"]|"(?:\\\\.|[^"])*")+)\s*(?:,|$)>',
$_SERVER['HTTP_ACCEPT'], $listItems, PREG_SET_ORDER))
sendBadRequest();
try {
foreach ($listItems as $item)
$ranges[] = MediaRange::createInstance($item[1]);
} catch (InvalidArgumentException $iae) {
sendBadRequest();
}
usort($ranges, array('MediaRange', 'compare'));
}
/* If no Accept header is sent by the user agent, all media types are assumed to be acceptable.
* 14.1 Accept, RFC 2616.
*/
else $ranges[] = new MediaRange('*', '*');
return $ranges;
}
function sendBadRequest() {
header('HTTP/1.1 Bad Request', 400);
exit();
}
?>

