Skip to content

The layout of a html page which has nested <a> inside tables was messed up #123

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
topcoderKai opened this issue Sep 1, 2017 · 11 comments

Comments

@topcoderKai
Copy link

topcoderKai commented Sep 1, 2017

There are nested <a> and <table> in the test case and the sanitizer generated additional elementes such as </table> and </a> and messed up the layout.
See the test case
tokenMessedup.html.zip

@mikesamuel
Copy link
Contributor

I'm not going to download and unzip attachments from people I don't know onto my local machine.

Please put testcases in the bug text using an HTML code section like

```html
Your HTML goes here
```

@lquinn
Copy link

lquinn commented Oct 30, 2017

<a href="http://foo.example.com/">
  <table><tr><td><a href="http://bar.example.com/">foobar</a></td></tr></table>
</a>

The sanitizer moves the inner "a" element outside the table, which breaks the layout.

This causes Netflix emails to display badly if they are run through the sanitizer.

@mikesamuel
Copy link
Contributor

Thanks. Getting the semantics of nested <a> elements right is tough.
This tool makes a best effort, but I'm probably not going to have time to sort out all the subtleties.

I suppose I could try and do less damaging recovery.

IIUC, the output you probably see is

<a href="foo.example.com">
<table></tr><td></td></tr></table></a><a href="http://bar.example.com/">foobar</a>

Would it be sufficient if I just closed the link on entering a table.

<a href="http://foo.example.com/"></a>
  <table><tr><td><a href="http://bar.example.com/">foobar</a></td></tr></table>

That would mean the tags are still properly nested, but it would make it impossible for tables that are one giant link, which I, personally, am OK with.

@lquinn
Copy link

lquinn commented Oct 30, 2017

I think what's missing is the notion of a "marker" in the list of active formatting elements.

https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-intr

At the start of a table cell, the parser should add a "marker" to the list of active formatting elements. When the parser then encounters an "a" element inside the table cell, there is no parse error because the parser is only looking for an existing "a" element between the end of the list and the last marker on the list.

https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inbody

@mikesamuel
Copy link
Contributor

I'm currently doing scope based reasoning in the element stack. I had assumed that the kind of reasoning that could be done with markers could be done with scopes. Is that wrong?

@lquinn
Copy link

lquinn commented Oct 31, 2017

I don't think it's wrong, but it requires extra care when checking if nested "a" elements are allowed. https://html.spec.whatwg.org/multipage/parsing.html#parsing-main-inbody says:

If the list of active formatting elements contains an a element between the end of the list and the last marker on the list (or the start of the list if there is no marker on the list), then this is a parse error; run the adoption agency algorithm for the token, then remove that element from the list of active formatting elements and the stack of open elements if the adoption agency algorithm didn't already remove it (it might not have if the element is not in table scope).

If there's a marker ahead of an "a" element in the list of active formatting elements, then we should allow that nesting of "a" elements.

@topcoderKai
Copy link
Author

The test case:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional //EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
 <head> 
  <meta charset="utf-8"> 
  <meta http-equiv="X-UA-Compatible" content="IE=edge"> 
  <meta name="viewport" content="width=device-width, initial-scale=1"> 
 </head> 
 <body bgcolor="#000000" style="font-family:Helvetica, Arial, sans;color:rgb(255, 255, 255);width:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;margin:0;padding:0;background-color:rgb(0, 0, 0);"> 
  <!--/* 100% Size Container --> 
  <table class="container" width="100%" cellpadding="0" cellspacing="0" border="0" style="background-color:rgb(0, 0, 0);"> 
   <tbody>
    <tr> 
     <td align="center"> 
      <!--/* Hero + Content --> 
      <table class="shell" width="450" cellpadding="0" cellspacing="0" border="0" style="background-color:rgb(255, 255, 255);"> 
       <!--/* Content --> 
       <tbody>
        <tr> 
         <td class="content-shell" style="background-color:rgb(255, 255, 255);"> 
          <table class="content" width="100%" cellpadding="0" cellspacing="0" border="0"> 
           <!--/* Hero --> 
           <tbody>
            <tr> 
             <td class="hero-shell"> <a href="https://www.netflix.com/title/80025172?trkid=13710079&amp;MSG_TITLE=80025172&amp;lnktrk=EMP&amp;g=3A8714C682E30D91AFE38B49701D669264526983&amp;lkid=TITLE_MDP" style="text-decoration:none !important;color:inherit;"> 
               <table cellpadding="0" cellspacing="0" border="0" width="100%" class="hero" style="min-height:703px;"> 
                <tbody>
                 <tr> 
                  <td class="hero-background" bgcolor="#000000" style="overflow:hidden;background-repeat: no-repeat;background:rgb(0, 0, 0) url(http://art-1.nflximg.net/93a79/c654d7836398c6067cd56bd53262f20d33f93a79.jpg) no-repeat center top;background-size:450px;background-repeat:no-repeat;" background="http://art-1.nflximg.net/93a79/c654d7836398c6067cd56bd53262f20d33f93a79.jpg"> 
                   <!--[if gte mso 9]>
<v:rect xmlns:v="urn:schemas-microsoft-com:vml" fill="true" stroke="false" style="width:450px;height:703px;">
<v:fill type="tile" src="http://art-1.nflximg.net/93a79/c654d7836398c6067cd56bd53262f20d33f93a79.jpg" color="#000000" />
<v:textbox inset="0,0,0,0">
<![endif]--> 
                   <div> 
                    <table class="hero-content" align="center" cellpadding="0" cellspacing="0" border="0" height="100%" width="100%" style="min-height:703px;"> 
                     <!--/* Logo --> 
                     <tbody>
                      <tr> 
                       <td class="logo" valign="top" align="center" style="padding:20px 0 0 0;"> <a href="https://www.netflix.com/browse?lnktrk=EMP&amp;g=3A8714C682E30D91AFE38B49701D669264526983&amp;lkid=URL_HOME_4" style="color:inherit;"> <img src="http://cdn.nflximg.com/us/email/logo/newDesign/logo_v2.png" alt="Netflix" width="100" height="27" style="-ms-interpolation-mode:bicubic;border:none;outline:none;border-collapse:collapse;display:block;border-style:none;"> </a> </td> 
                      </tr> 
                      <tr> 
                       <td class="label" valign="top" align="center" style="font-size:9px;color:#ffffff;text-transform:uppercase;padding:5px 0px 0px 0px;font-family: Helvetica, Georgia, Arial, sans-serif;-webkit-text-size-adjust: none;letter-spacing:1px;">A Netflix Original Series </td> 
                      </tr> 
                      <!-- Title Logo --> 
                      <!--[if !mso]><!--> 
                      <style type="text/css">
      table.title-logo-table, .title-logo {
        width: 100% !important;
      }
      .title-logo img {
    max-width: 535px !important;
        width: 100% !important;
      }
    </style> 
                      <!--<![endif]--> 
                      <tr> 
                       <td class="title-logo" width="450" align="center" valign="bottom" style="vertical-align:bottom;padding:400px 50px 0 50px;"> <img src="http://art-1.nflximg.net/32524/4075cad5d716b4bee2102ac43b0481bdb2332524.png" alt="Narcos" style="border-collapse:collapse;display:block;max-width: 535px !important;-ms-interpolation-mode:bicubic;border:none;outline:none;border-collapse:collapse;border-style:none;" width="350"> </td> 
                      </tr> 
                      <tr> 
                       <td class="flavor-text" style="text-decoration: none !important;font-size:18px;line-height:24px;color:rgb(255, 255, 255);font-family:Helvetica, Arial, sans;padding:20px 0 0 0;font-weight:bold;" align="center"><a href="#" style="text-decoration: none !important;color:rgb(255, 255, 255);color:inherit;">Season 3</a> <br><span class="date-text" style="text-decoration: none !important;font-size:20px;line-height:24px;color:rgb(255, 255, 255);font-family:Helvetica, Arial, sans;padding:5px 0 0 0;font-weight:bold;" align="center"><a href="#" style="text-decoration: none !important;color:rgb(255, 255, 255);color:inherit;color:rgb(255, 255, 255);">September 1st</a></span> </td> 
                      </tr> 
                      <!-- Button --> 
                      <tr> 
                       <td class="button-shell" align="center" style="padding:20px 44px 0 44px;"> <a class="button-link" href="https://www.netflix.com/watch/80201489?trkid=13710079&amp;MSG_TITLE=80201489&amp;lnktrk=EMP&amp;g=3A8714C682E30D91AFE38B49701D669264526983&amp;lkid=TRAILER_WATCH" style="text-decoration:none;color:inherit;"> 
                         <table class="button red" cellpadding="0" cellspacing="0" border="0" align="center"> 
                          <tbody>
                           <tr> 
                            <td align="center" style="color:rgb(255, 255, 255);font-size:14px;font-weight:bold;background-color:rgb(229, 9, 20);text-align:center;padding:12px 22px;border-radius:4px;max-width:250px;"> <a class="button-link" href="https://www.netflix.com/watch/80201489?trkid=13710079&amp;MSG_TITLE=80201489&amp;lnktrk=EMP&amp;g=3A8714C682E30D91AFE38B49701D669264526983&amp;lkid=TRAILER_WATCH_2" style="color:#ffffff;font-family: Helvetica, Arial, sans;font-size:14px;font-weight:bold;text-align:center;text-decoration:none;color:inherit;color:rgb(255, 255, 255);font-size:14px;font-weight:bold;text-align:center;text-decoration:none;font-family:Helvetica, Arial, sans;">PLAY TRAILER</a> </td> 
                           </tr> 
                          </tbody>
                         </table> </a> </td> 
                      </tr> 
                      <tr> 
                       <td class="filler" height="30"> &nbsp; </td> 
                      </tr> 
                     </tbody>
                    </table> 
                   </div> 
                   <!--[if gte mso 9]>
</v:textbox>
</v:rect>
<![endif]--> </td> 
                 </tr> 
                </tbody>
               </table> </a> </td> 
            </tr> 
           </tbody>
          </table> </td> 
        </tr> 
       </tbody>
      </table> 
      <table class="shell-footer" width="450" cellpadding="0" cellspacing="0" border="0" style="background-color:rgb(0, 0, 0);"> 
       <!--/* Content --> 
       <tbody>
        <tr> 
         <td class="content-shell-footer" style="background-color:rgb(0, 0, 0);"> 
          <table class="content" width="100%" cellpadding="0" cellspacing="0" border="0"> 
           <!-- View All Bar With Play --> 
           <tbody>
            <tr> 
             <td class="view-all-shell" align="center" valign="top"> 
              <table cellpadding="0" cellspacing="0" border="0" width="100%"> 
               <!-- View All Text --> 
               <tbody>
                <tr> 
                 <td align="center" valign="top"> 
                  <table cellpadding="0" cellspacing="0" border="0" width="100%"> 
                   <tbody>
                    <tr> 
                     <td align="left" valign="top"> 
                      <table cellpadding="0" cellspacing="0" border="0" width="100%"> 
                       <tbody>
                        <tr> 
                         <td align="center" valign="top" style="padding:10px 0px 0px 0px;"> 
                          <table cellpadding="0" cellspacing="0" border="0" align="center"> 
                           <tbody>
                            <tr> 
                             <td class="viewAlltxt" align="right" valign="middle" style="font-family: Helvetica, Arial, sans-serif;-webkit-text-size-adjust: none;color:#ffffff;font-size:18px;font-weight:lighter;padding-right:5px;"><a href="https://www.netflix.com/browse?lnktrk=EMP&amp;g=3A8714C682E30D91AFE38B49701D669264526983&amp;lkid=URL_HOME_2" target="_blank" style="text-decoration: none;color:#ffffff;line-height:100%;color:inherit;">View All TV Shows &amp; Movies</a></td> 
                             <td class="viewAllimg" align="left" valign="top" style="padding-top:-1px"> <a href="https://www.netflix.com/browse?lnktrk=EMP&amp;g=3A8714C682E30D91AFE38B49701D669264526983&amp;lkid=URL_HOME_3" target="_blank" style="text-decoration: none;color:#e50914;line-height:100%;color:inherit;"><img alt="" src="http://cdn.nflximg.com/us/email/adhoc/201405/oitnb/launch/201406_hpnav5_vall.png" width="27" height="47" border="0" style="-ms-interpolation-mode:bicubic;border:none;outline:none;border-collapse:collapse;border-style:none;"></a> </td> 
                            </tr> 
                           </tbody>
                          </table> </td> 
                        </tr> 
                       </tbody>
                      </table> </td> 
                    </tr> 
                   </tbody>
                  </table> </td> 
                </tr> 
                <!-- Horizontal Rule --> 
                <tr> 
                 <td> 
                  <table cellpadding="0" cellspacing="0" border="0" width="100%"> 
                   <tbody>
                    <tr> 
                     <td class="view-all-rule width100" align="center" valign="top"><img alt="" src="http://cdn.nflximg.com/us/email/adhoc/201405/oitnb/s2comingsoon/20140529_rule.png" width="450" height="1" border="0" style="display:block;color:;font-family: Helvetica, Arial, sans-serif;-webkit-text-size-adjust: none;padding:8px 0px 0px 0px;-ms-interpolation-mode:bicubic;border:none;outline:none;border-collapse:collapse;"></td> 
                    </tr> 
                   </tbody>
                  </table> </td> 
                </tr> 
               </tbody>
              </table> </td> 
            </tr> 
            <!-- /* Footer  --> 
            <tr> 
             <td class="footer questions" align="center" style="font-size:14px;line-height:18px;padding:22px 44px 0 44px;color:rgb(110, 110, 110);background-color:rgb(0, 0, 0);text-align:center;font-family:Helvetica, Arial, sans;color:rgb(110, 110, 110);background-color:rgb(0, 0, 0);border-color:rgb(0, 0, 0);font-family:Helvetica, Arial, sans-serif;-webkit-text-size-adjust:none;font-size:13px;color:rgb(110, 110, 110);text-decoration:none;font-weight:lighter;"> Questions? Call 1-888-811-9842 </td> 
            </tr> 
            <tr> 
             <td class="footer footer-copy" style="font-size:12px;line-height:18px;padding:10px 44px 0 44px;color:rgb(110, 110, 110);background-color:rgb(0, 0, 0);font-family:Helvetica, Arial, sans;color:rgb(110, 110, 110);background-color:rgb(0, 0, 0);border-color:rgb(0, 0, 0);"> This informational email has been sent to you as part of your Netflix membership. If you would like to stop receiving these emails, please <a href="https://www.netflix.com/ManageSubscriptions?id=BQE0AAEBEHKydrfMz0werF%2F3av4YgjOAgAb8QNqpt8xPQh3WWEZTvvZXoJo%2Btdo3IuNx68avq6a4eMfVF3cNPgPtWtYctlqcZ8zowXZeQg5xuEMKYoBFyyKAv4niTtBKXmue8x2QmWac%2FsaG9wvFVhh9IBSR%2FCm8KQHcrD0NZx7l4JYtEGhPpUlSxzxG4qPXbKpSpW7mzeL%2F&amp;mid=20792311&amp;lnktrk=EMP&amp;g=3A8714C682E30D91AFE38B49701D669264526983&amp;lkid=unsubscribe_link" style="color:#6e6e6e;color:rgb(110, 110, 110);color:inherit;" target="_blank">click here to unsubscribe</a>, or visit the <a href="https://www.netflix.com/EmailPreferences?lnktrk=EMP&amp;g=3A8714C682E30D91AFE38B49701D669264526983&amp;lkid=email_settings" style="color:#6e6e6e;color:rgb(110, 110, 110);color:inherit;" target="_blank">Communication Settings</a> page, uncheck the <span style="font-weight:bold;">Now on Netflix</span> box, and click "Update." Please do not reply to this email, as we are unable to respond from this email address. If you need help or would like to contact us, please visit our <a href="https://help.netflix.com/help?lnktrk=EMP&amp;g=3A8714C682E30D91AFE38B49701D669264526983&amp;lkid=hc_footer_link" style="color:#6e6e6e;color:rgb(110, 110, 110);color:inherit;" target="_blank">Help Center.</a> </td> 
            </tr> 
            <tr> 
             <td class="footer footer-copy" style="font-size:12px;line-height:18px;padding:10px 44px 0 44px;color:rgb(110, 110, 110);background-color:rgb(0, 0, 0);font-family:Helvetica, Arial, sans;color:rgb(110, 110, 110);background-color:rgb(0, 0, 0);border-color:rgb(0, 0, 0);"> This message was mailed to [<a href="#" style="text-decoration: none !important; color: #6e6e6e;color:rgb(110, 110, 110);color:inherit;">[email protected]</a>] by Netflix. </td> 
            </tr> 
            <tr> 
             <td class="footer footer-copyNp" style="font-family:Helvetica, Arial, sans;color:rgb(110, 110, 110);background-color:rgb(0, 0, 0);border-color:rgb(0, 0, 0);font-size:12px;line-height:18px;padding:0px 44px 0 44px;color:rgb(110, 110, 110);background-color:rgb(0, 0, 0);"> 
              <!--legal_content_footer--> SRC: <a href="https://help.netflix.com/help?lnktrk=EMP&amp;g=3A8714C682E30D91AFE38B49701D669264526983&amp;lkid=URL_HELP_2" style="color:#6e6e6e;text-decoration:none;color:rgb(110, 110, 110);color:inherit;">12186_en_CA</a> </td> 
            </tr> 
            <tr> 
             <td class="footer footer-copyNp" style="font-family:Helvetica, Arial, sans;color:rgb(110, 110, 110);background-color:rgb(0, 0, 0);border-color:rgb(0, 0, 0);font-size:12px;line-height:18px;padding:0px 44px 0 44px;color:rgb(110, 110, 110);background-color:rgb(0, 0, 0);"> Use of the Netflix service and website is subject to our <a style="color:#6e6e6e;text-decoration:underline;color:rgb(110, 110, 110);color:inherit;" href="https://www.netflix.com/TermsOfUse?lnktrk=EMP&amp;g=3A8714C682E30D91AFE38B49701D669264526983&amp;lkid=URL_TERMS">Terms of Use</a> and <a style="color:#6e6e6e;text-decoration:underline;color:rgb(110, 110, 110);color:inherit;" href="https://www.netflix.com/PrivacyPolicy?lnktrk=EMP&amp;g=3A8714C682E30D91AFE38B49701D669264526983&amp;lkid=URL_PRIVACY">Privacy Statement</a>. </td> 
            </tr> 
            <tr> 
             <td class="footer footer-copyNp" style="font-family:Helvetica, Arial, sans;color:rgb(110, 110, 110);background-color:rgb(0, 0, 0);border-color:rgb(0, 0, 0);font-size:12px;line-height:18px;padding:0px 44px 0 44px;color:rgb(110, 110, 110);background-color:rgb(0, 0, 0);"> <span class="iosnonlink"><a href="https://www.netflix.com/browse?lnktrk=EMP&amp;g=3A8714C682E30D91AFE38B49701D669264526983&amp;lkid=URL_HOME_5" style="color:#6e6e6e; text-decoration:none;color:rgb(110, 110, 110);color:inherit;">Netflix International B.V., care of Netflix [Inc.], 100 Winchester Circle, Los Gatos, CA 95032, U.S.A. </a><a href="https://help.netflix.com/help?lnktrk=EMP&amp;g=3A8714C682E30D91AFE38B49701D669264526983&amp;lkid=URL_HELP_3" style="color:#6e6e6e;color:rgb(110, 110, 110);color:inherit;">https://help.netflix.com/help</a></span> </td> 
            </tr> 
            <tr> 
             <td class="footer footer-spacer" height="44" style="font-family:Helvetica, Arial, sans;color:rgb(110, 110, 110);background-color:rgb(0, 0, 0);border-color:rgb(0, 0, 0);"> &nbsp;
              <!--legal_content_footer--> <img src="http://beacon.netflix.com/img/BAQgBEAEa0AJ2THSsgosiINnMMOKPnivWKSK-WmHHLwvtmTf2TDI_GuFdQ7rh6ZsD7KUYbtEoyrbWZRrh4iEyxxZCzrO8sWQOgn-XbxL_uHk3a1ntFlzHx1ZShyYfurnrE7hJImuNEKMBalbOW7I5uGHcnzAh0L1XzQrDt2vPArfk8iEy_YtQOVOteqRg85hjpWF6IFp_2dF2KKBBSZwnkphwd_hXO-TBUCAjNI22NGd_4GQzy0nvX6v8uVskrRl3oAIvuUGh3hqfhxxZQShjFp1N8jZtwDcDuDRnYdXbzFR4e-OulSmlWD-gBf5hEw-xrd7ECBO1KobhVTNnn5AeFN1mOrR2gLbnLY4RZvLOamjVpArokq2KJqbdlT4QeyQqleaF83KC9HKkh69M7r8EY-y80f3Dgw2Up94JppjjAff24kdRQrHq2HxKDoHequlW5MaxKA85vGU." style="display:block;-ms-interpolation-mode:bicubic;border:none;outline:none;border-collapse:collapse;" border="0"> </td> 
            </tr> 
           </tbody>
          </table> </td> 
        </tr> 
       </tbody>
      </table> </td> 
    </tr> 
   </tbody>
  </table> 
  <!-- Fix for Google Inbox --> 
  <table class="inbox-fix" cellpadding="0" cellspacing="0" border="0" width="450" height="1" align="center" style="width: 450px !important;"> 
   <tbody>
    <tr> 
     <td> <img src="http://cdn.nflximg.com/us/email/spacer.gif" width="150" height="1" style="border-collapse:collapse;display:block;-ms-interpolation-mode:bicubic;border:none;outline:none;border-collapse:collapse;"> </td> 
     <td> <img src="http://cdn.nflximg.com/us/email/spacer.gif" width="150" height="1" style="border-collapse:collapse;display:block;-ms-interpolation-mode:bicubic;border:none;outline:none;border-collapse:collapse;"> </td> 
     <td> <img src="http://cdn.nflximg.com/us/email/spacer.gif" width="150" height="1" style="border-collapse:collapse;display:block;-ms-interpolation-mode:bicubic;border:none;outline:none;border-collapse:collapse;"> </td> 
    </tr> 
   </tbody>
  </table>   
 </body>
</html>

@fr3akX
Copy link

fr3akX commented Jan 8, 2018

any update on this? Ebay email html's also affected.

@jmanico
Copy link
Member

jmanico commented Jan 8, 2018 via email

@topcoderKai
Copy link
Author

I posted the test case above, I hope I could simplify the test case more. Anyone have more simplified and better test case is appreciated.

@mikesamuel
Copy link
Contributor

Duplicate of #137

@mikesamuel mikesamuel marked this as a duplicate of #137 Jan 16, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants