Gabriel Ivăncescu : mshtml: Parse X-UA-Compatible correctly.

Alexandre Julliard julliard at winehq.org
Fri Jul 15 14:45:54 CDT 2022


Module: wine
Branch: master
Commit: efdfd328067225134bf7263928fa0a4fd58e1a40
URL:    https://gitlab.winehq.org/wine/wine/-/commit/efdfd328067225134bf7263928fa0a4fd58e1a40

Author: Gabriel Ivăncescu <gabrielopcode at gmail.com>
Date:   Thu Jul 14 21:18:07 2022 +0300

mshtml: Parse X-UA-Compatible correctly.

There can be multiple compat modes defined, separated by commas, but also
surrounded by whitespace. The highest mode in the list is picked as the
document mode, with 'edge' being the highest mode available.

It stops as soon as an invalid mode is found in the list and returns whatever
highest mode was found until then.

Signed-off-by: Gabriel Ivăncescu <gabrielopcode at gmail.com>

---

 dlls/mshtml/main.c           |  2 +-
 dlls/mshtml/mshtml_private.h |  3 ++-
 dlls/mshtml/mutation.c       | 37 +++++++++++++++++++++++++------------
 dlls/mshtml/tests/dom.c      | 37 ++++++++++++++++++++++++++++---------
 4 files changed, 56 insertions(+), 23 deletions(-)

diff --git a/dlls/mshtml/main.c b/dlls/mshtml/main.c
index bbaed1f1967..1a64bdb9b7d 100644
--- a/dlls/mshtml/main.c
+++ b/dlls/mshtml/main.c
@@ -154,7 +154,7 @@ static BOOL read_compat_mode(HKEY key, compat_mode_t *r)
     if(status != ERROR_SUCCESS || type != REG_SZ)
         return FALSE;
 
-    return parse_compat_version(version, r);
+    return parse_compat_version(version, r) != NULL;
 }
 
 static BOOL WINAPI load_compat_settings(INIT_ONCE *once, void *param, void **context)
diff --git a/dlls/mshtml/mshtml_private.h b/dlls/mshtml/mshtml_private.h
index d8b4ddef249..2e30210db2e 100644
--- a/dlls/mshtml/mshtml_private.h
+++ b/dlls/mshtml/mshtml_private.h
@@ -297,6 +297,7 @@ PRIVATE_TID_LIST
 } tid_t;
 
 typedef enum {
+    COMPAT_MODE_INVALID = -1,
     COMPAT_MODE_QUIRKS,
     COMPAT_MODE_IE5,
     COMPAT_MODE_IE7,
@@ -1253,7 +1254,7 @@ HRESULT set_task_timer(HTMLInnerWindow*,LONG,enum timer_type,IDispatch*,LONG*) D
 HRESULT clear_task_timer(HTMLInnerWindow*,DWORD) DECLSPEC_HIDDEN;
 HRESULT clear_animation_timer(HTMLInnerWindow*,DWORD) DECLSPEC_HIDDEN;
 
-BOOL parse_compat_version(const WCHAR*,compat_mode_t*) DECLSPEC_HIDDEN;
+const WCHAR *parse_compat_version(const WCHAR*,compat_mode_t*) DECLSPEC_HIDDEN;
 
 const char *debugstr_mshtml_guid(const GUID*) DECLSPEC_HIDDEN;
 
diff --git a/dlls/mshtml/mutation.c b/dlls/mshtml/mutation.c
index 79918278b3d..02b511e309e 100644
--- a/dlls/mshtml/mutation.c
+++ b/dlls/mshtml/mutation.c
@@ -412,15 +412,20 @@ static void set_document_mode(HTMLDocumentNode *doc, compat_mode_t document_mode
         lock_document_mode(doc);
 }
 
-BOOL parse_compat_version(const WCHAR *version_string, compat_mode_t *r)
+static BOOL is_ua_compatible_delimiter(WCHAR c)
+{
+    return !c || c == ';' || c == ',' || iswspace(c);
+}
+
+const WCHAR *parse_compat_version(const WCHAR *version_string, compat_mode_t *r)
 {
     DWORD version = 0;
     const WCHAR *p;
 
     for(p = version_string; '0' <= *p && *p <= '9'; p++)
         version = version * 10 + *p-'0';
-    if((*p && *p != ';') || p == version_string)
-        return FALSE;
+    if(!is_ua_compatible_delimiter(*p) || p == version_string)
+        return NULL;
 
     switch(version){
     case 5:
@@ -442,13 +447,14 @@ BOOL parse_compat_version(const WCHAR *version_string, compat_mode_t *r)
     default:
         *r = version < 5 ? COMPAT_MODE_QUIRKS : COMPAT_MODE_IE11;
     }
-    return TRUE;
+    return p;
 }
 
 static BOOL parse_ua_compatible(const WCHAR *p, compat_mode_t *r)
 {
     static const WCHAR ie_eqW[] = {'I','E','='};
     static const WCHAR edgeW[] = {'e','d','g','e'};
+    compat_mode_t mode = COMPAT_MODE_INVALID;
 
     TRACE("%s\n", debugstr_w(p));
 
@@ -456,15 +462,22 @@ static BOOL parse_ua_compatible(const WCHAR *p, compat_mode_t *r)
         return FALSE;
     p += 3;
 
-    if(!wcsnicmp(p, edgeW, ARRAY_SIZE(edgeW))) {
-        p += ARRAY_SIZE(edgeW);
-        if(*p && *p != ';')
-            return FALSE;
-        *r = COMPAT_MODE_IE11;
-        return TRUE;
-    }
+    do {
+        while(iswspace(*p)) p++;
+        if(!wcsnicmp(p, edgeW, ARRAY_SIZE(edgeW))) {
+            p += ARRAY_SIZE(edgeW);
+            if(is_ua_compatible_delimiter(*p))
+                mode = COMPAT_MODE_IE11;
+            break;
+        }else if(!(p = parse_compat_version(p, r)))
+            break;
+        if(mode < *r)
+            mode = *r;
+        while(iswspace(*p)) p++;
+    } while(*p++ == ',');
 
-    return parse_compat_version(p, r);
+    *r = mode;
+    return mode != COMPAT_MODE_INVALID;
 }
 
 void process_document_response_headers(HTMLDocumentNode *doc, IBinding *binding)
diff --git a/dlls/mshtml/tests/dom.c b/dlls/mshtml/tests/dom.c
index cd4daa84e0a..d25c7ac0df8 100644
--- a/dlls/mshtml/tests/dom.c
+++ b/dlls/mshtml/tests/dom.c
@@ -11441,6 +11441,26 @@ static void test_document_mode(IHTMLDocument2 *doc2)
 
 static void test_quirks_mode(void)
 {
+    static const struct {
+        const char *str;
+        unsigned expected_mode;
+    } tests[] = {
+        { "9",          9 },
+        { " \t9 ",      9 },
+        { " 5 , 8 , 7", 8 },
+        { " 8 , 7 , 5", 8 },
+        { " 5 , 5 , 7", 7 },
+        { " 5 , 9 , 7", 9 },
+        { " 5, 7,9",    9 },
+        { " 5, 7;9",    7 },
+        { " 5, edge,8", 11 },
+        { " 5, foo,8",  5 },
+        { " 5, 8,foo",  8 },
+        { " 5, ,,7",    5 },
+        { " 5, , ,7",   5 },
+    };
+    unsigned i;
+
     run_domtest("<html></html>", check_quirks_mode);
     run_domtest("<!DOCTYPE html>\n<html></html>", check_strict_mode);
     run_domtest("<!-- comment --><!DOCTYPE html>\n<html></html>", check_quirks_mode);
@@ -11455,15 +11475,14 @@ static void test_quirks_mode(void)
     if(!is_ie9plus)
         return;
 
-    expected_document_mode = 9;
-    run_domtest("<!DOCTYPE html>\n"
-                "<html>"
-                " <head>"
-                "  <meta http-equiv=\"x-ua-compatible\" content=\"IE=9\" />"
-                " </head>"
-                " <body>"
-                " </body>"
-                "</html>", test_document_mode);
+    for(i = 0; i < ARRAY_SIZE(tests); i++) {
+        char buf[128];
+        expected_document_mode = tests[i].expected_mode;
+        sprintf(buf, "<!DOCTYPE html>\n<html><head>"
+                     " <meta http-equiv=\"x-ua-compatible\" content=\"IE=%s\" />"
+                     "</head><body></body></html>", tests[i].str);
+        run_domtest(buf, test_document_mode);
+    }
 
     expected_document_mode = 8;
     run_domtest("<!DOCTYPE html>\n"




More information about the wine-cvs mailing list