Page 2 of 2 FirstFirst 12
Results 11 to 13 of 13

Thread: parse error

  1. #11
    Join Date
    Dec 2004
    Location
    UK
    Posts
    2,358
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Default

    Quote Originally Posted by Twey View Post
    Except that IE sends Accept: */*,
    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.

    so by the laws of content negotiation
    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:

    one should send it XHTML.
    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.

    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'], $listItemsPREG_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();
    }
    ?>
    Last edited by mwinter; 05-06-2007 at 07:28 PM. Reason: Grammar and minor code change

  2. #12
    Join Date
    Jun 2006
    Location
    Acton Ontario Canada.
    Posts
    677
    Thanks
    0
    Thanked 1 Time in 1 Post

    Default

    That'll help tons, i had never considered content negotiation (never knew it existed...) but now that i know i'll be able improve my coding further.
    Thanks Mwinter, Twey, Your insights are always helpfull in creating a better internet.
    - Ryan "Boxxertrumps" Trumpa
    Come back once it validates: HTML, CSS, JS.

  3. #13
    Join Date
    Dec 2004
    Location
    UK
    Posts
    2,358
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Default

    Quote Originally Posted by boxxertrumps View Post
    That'll help tons, i had never considered content negotiation (never knew it existed...)
    You were using it already: the User-Agent header is a possible dimension (all request headers are, actually), but it's not one I would advise using. Like using feature detection in client-side scripting, the Accept header indicates what the user agent is capable of processing - at least in principle.

    One thing that I didn't get to demonstrate in the code below is the necessity of the Vary header. When negotiating a response, the Vary response header should contain a list of request headers that determined the variant returned to the client. If the Vary header isn't sent, a cache might retrieve an XHTML response for one client and send it later to another which needed a HTML document.

    Section 12 of RFC 2616 [ftp] describes content negotiation in more detail, as does various parts of sections 3 and 14.

    Mike

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •