Skip to content

Commit

Permalink
mshtml: Parse X-UA-Compatible correctly.
Browse files Browse the repository at this point in the history
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@gmail.com>
  • Loading branch information
g-insn authored and julliard committed Jul 15, 2022
1 parent 3301a8e commit efdfd32
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 23 deletions.
2 changes: 1 addition & 1 deletion dlls/mshtml/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion dlls/mshtml/mshtml_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,7 @@ PRIVATE_TID_LIST
} tid_t;

typedef enum {
COMPAT_MODE_INVALID = -1,
COMPAT_MODE_QUIRKS,
COMPAT_MODE_IE5,
COMPAT_MODE_IE7,
Expand Down Expand Up @@ -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;

Expand Down
37 changes: 25 additions & 12 deletions dlls/mshtml/mutation.c
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand All @@ -442,29 +447,37 @@ 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));

if(wcsnicmp(ie_eqW, p, ARRAY_SIZE(ie_eqW)))
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)
Expand Down
37 changes: 28 additions & 9 deletions dlls/mshtml/tests/dom.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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"
Expand Down

0 comments on commit efdfd32

Please sign in to comment.