Make concurrent reads on HttpHeaders thread-safe - #68115

Merged
MihaZupan merged 1 commit into
dotnet:mainfrom
MihaZupan:httpheaders-thread-safe-reads
May 6, 2022
Merged

Make concurrent reads on HttpHeaders thread-safe#68115
MihaZupan merged 1 commit into
dotnet:mainfrom
MihaZupan:httpheaders-thread-safe-reads

Conversation

@MihaZupan

@MihaZupanMihaZupan commented Apr 16, 2022

Copy link
Copy Markdown
Member

Fixes#61798
Lowers the impact of bugs like #66989 and #65379.

Adds no overhead if headers are both added & enumerated without validation.

Simpler to review when hiding whitespace changes.

@MihaZupanMihaZupan added this to the 7.0.0 milestone Apr 16, 2022
@MihaZupanMihaZupan self-assigned this Apr 16, 2022
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #61798

Adds no overhead if headers are both added & enumerated without validation.

Author:MihaZupan
Assignees:MihaZupan
Labels:

area-System.Net.Http

Milestone:7.0.0

@MihaZupan
MihaZupan requested a review from a teamApril 16, 2022 18:47
@MihaZupan

Copy link
Copy Markdown
MemberAuthor

@dotnet/ncl PTAL

The change boils down to adding a lock when:

  • The values in HeaderStoreItemInfo are being parsed (so its fields are being modified)
  • The values are read from HeaderStoreItemInfo (non-validated reads / copying to a new header collection).

Since a value entry can transition from being a string to a HeaderStoreItemInfo, and we're not locking at those sites, it is expected that a single raw value may end up being parsed multiple times.
Such parsing is idempotent, so this is transparent to the user.

The code also has to be careful when reading the value of a given entry.
For example, the following logic would be problematic:

if(entries[i].ValueisHeaderStoreItemInfo){// ...}else{DoSomething((string)entries[i].Value);// Wrong! The value may now be HeaderStoreItemInfo}

and it should instead be something like

objectvalue=entries[i].Value;if(valueisHeaderStoreItemInfo){// ...}else{DoSomething((string)value);}

I've looked through our current code to make sure this is the case, but it's possible future changes may accidentally break this. I've added a test that should catch most such mistakes, but there may be cases that aren't covered.

@CarnaViireCarnaViire left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but maybe someone else could also take a look 🙂

@CarnaViire

Copy link
Copy Markdown
Member

Does this change fully address #61798 ? I see the issue mentioning invalid values too, but this change only adds locks?

@MihaZupan

Copy link
Copy Markdown
MemberAuthor

Does this change fully address #61798 ?

Yes. I split off the invalid values part into #67199, as that was a prerequisite for this change.

@MihaZupan
MihaZupan merged commit b00a64d into dotnet:mainMay 6, 2022
@juharris

Copy link
Copy Markdown

Will this change be in an upcoming version 6 update? If so, any idea when?

@MihaZupan

Copy link
Copy Markdown
MemberAuthor

It will be in preview 5 of .NET 7.

If you mean whether it will be backported to 6.0, there are currently no plans for that.

@ghostghost locked as resolved and limited conversation to collaborators Jun 9, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

HttpHeaders thread safety and behavior of invalid values

5 participants

@MihaZupan@CarnaViire@juharris@stephentoub@ManickaP
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Make concurrent reads on HttpHeaders thread-safe - #68115

Merged
MihaZupan merged 1 commit into
dotnet:mainfrom
MihaZupan:httpheaders-thread-safe-reads
May 6, 2022
Merged

Make concurrent reads on HttpHeaders thread-safe#68115
MihaZupan merged 1 commit into
dotnet:mainfrom
MihaZupan:httpheaders-thread-safe-reads

Conversation

@MihaZupan

@MihaZupanMihaZupan commented Apr 16, 2022

Copy link
Copy Markdown
Member

Fixes#61798
Lowers the impact of bugs like #66989 and #65379.

Adds no overhead if headers are both added & enumerated without validation.

Simpler to review when hiding whitespace changes.

@MihaZupanMihaZupan added this to the 7.0.0 milestone Apr 16, 2022
@MihaZupanMihaZupan self-assigned this Apr 16, 2022
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #61798

Adds no overhead if headers are both added & enumerated without validation.

Author:MihaZupan
Assignees:MihaZupan
Labels:

area-System.Net.Http

Milestone:7.0.0

@MihaZupan
MihaZupan requested a review from a teamApril 16, 2022 18:47
@MihaZupan

Copy link
Copy Markdown
MemberAuthor

@dotnet/ncl PTAL

The change boils down to adding a lock when:

  • The values in HeaderStoreItemInfo are being parsed (so its fields are being modified)
  • The values are read from HeaderStoreItemInfo (non-validated reads / copying to a new header collection).

Since a value entry can transition from being a string to a HeaderStoreItemInfo, and we're not locking at those sites, it is expected that a single raw value may end up being parsed multiple times.
Such parsing is idempotent, so this is transparent to the user.

The code also has to be careful when reading the value of a given entry.
For example, the following logic would be problematic:

if(entries[i].ValueisHeaderStoreItemInfo){// ...}else{DoSomething((string)entries[i].Value);// Wrong! The value may now be HeaderStoreItemInfo}

and it should instead be something like

objectvalue=entries[i].Value;if(valueisHeaderStoreItemInfo){// ...}else{DoSomething((string)value);}

I've looked through our current code to make sure this is the case, but it's possible future changes may accidentally break this. I've added a test that should catch most such mistakes, but there may be cases that aren't covered.

@CarnaViireCarnaViire left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but maybe someone else could also take a look 🙂

@CarnaViire

Copy link
Copy Markdown
Member

Does this change fully address #61798 ? I see the issue mentioning invalid values too, but this change only adds locks?

@MihaZupan

Copy link
Copy Markdown
MemberAuthor

Does this change fully address #61798 ?

Yes. I split off the invalid values part into #67199, as that was a prerequisite for this change.

@MihaZupan
MihaZupan merged commit b00a64d into dotnet:mainMay 6, 2022
@juharris

Copy link
Copy Markdown

Will this change be in an upcoming version 6 update? If so, any idea when?

@MihaZupan

Copy link
Copy Markdown
MemberAuthor

It will be in preview 5 of .NET 7.

If you mean whether it will be backported to 6.0, there are currently no plans for that.

@ghostghost locked as resolved and limited conversation to collaborators Jun 9, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

HttpHeaders thread safety and behavior of invalid values

5 participants

@MihaZupan@CarnaViire@juharris@stephentoub@ManickaP
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Make concurrent reads on HttpHeaders thread-safe - #68115

Merged
MihaZupan merged 1 commit into
dotnet:mainfrom
MihaZupan:httpheaders-thread-safe-reads
May 6, 2022
Merged

Make concurrent reads on HttpHeaders thread-safe#68115
MihaZupan merged 1 commit into
dotnet:mainfrom
MihaZupan:httpheaders-thread-safe-reads

Conversation

@MihaZupan

@MihaZupanMihaZupan commented Apr 16, 2022

Copy link
Copy Markdown
Member

Fixes#61798
Lowers the impact of bugs like #66989 and #65379.

Adds no overhead if headers are both added & enumerated without validation.

Simpler to review when hiding whitespace changes.

@MihaZupanMihaZupan added this to the 7.0.0 milestone Apr 16, 2022
@MihaZupanMihaZupan self-assigned this Apr 16, 2022
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #61798

Adds no overhead if headers are both added & enumerated without validation.

Author:MihaZupan
Assignees:MihaZupan
Labels:

area-System.Net.Http

Milestone:7.0.0

@MihaZupan
MihaZupan requested a review from a teamApril 16, 2022 18:47
@MihaZupan

Copy link
Copy Markdown
MemberAuthor

@dotnet/ncl PTAL

The change boils down to adding a lock when:

  • The values in HeaderStoreItemInfo are being parsed (so its fields are being modified)
  • The values are read from HeaderStoreItemInfo (non-validated reads / copying to a new header collection).

Since a value entry can transition from being a string to a HeaderStoreItemInfo, and we're not locking at those sites, it is expected that a single raw value may end up being parsed multiple times.
Such parsing is idempotent, so this is transparent to the user.

The code also has to be careful when reading the value of a given entry.
For example, the following logic would be problematic:

if(entries[i].ValueisHeaderStoreItemInfo){// ...}else{DoSomething((string)entries[i].Value);// Wrong! The value may now be HeaderStoreItemInfo}

and it should instead be something like

objectvalue=entries[i].Value;if(valueisHeaderStoreItemInfo){// ...}else{DoSomething((string)value);}

I've looked through our current code to make sure this is the case, but it's possible future changes may accidentally break this. I've added a test that should catch most such mistakes, but there may be cases that aren't covered.

@CarnaViireCarnaViire left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but maybe someone else could also take a look 🙂

@CarnaViire

Copy link
Copy Markdown
Member

Does this change fully address #61798 ? I see the issue mentioning invalid values too, but this change only adds locks?

@MihaZupan

Copy link
Copy Markdown
MemberAuthor

Does this change fully address #61798 ?

Yes. I split off the invalid values part into #67199, as that was a prerequisite for this change.

@MihaZupan
MihaZupan merged commit b00a64d into dotnet:mainMay 6, 2022
@juharris

Copy link
Copy Markdown

Will this change be in an upcoming version 6 update? If so, any idea when?

@MihaZupan

Copy link
Copy Markdown
MemberAuthor

It will be in preview 5 of .NET 7.

If you mean whether it will be backported to 6.0, there are currently no plans for that.

@ghostghost locked as resolved and limited conversation to collaborators Jun 9, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

HttpHeaders thread safety and behavior of invalid values

5 participants

@MihaZupan@CarnaViire@juharris@stephentoub@ManickaP
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Make concurrent reads on HttpHeaders thread-safe - #68115

Merged
MihaZupan merged 1 commit into
dotnet:mainfrom
MihaZupan:httpheaders-thread-safe-reads
May 6, 2022
Merged

Make concurrent reads on HttpHeaders thread-safe#68115
MihaZupan merged 1 commit into
dotnet:mainfrom
MihaZupan:httpheaders-thread-safe-reads

Conversation

@MihaZupan

@MihaZupanMihaZupan commented Apr 16, 2022

Copy link
Copy Markdown
Member

Fixes#61798
Lowers the impact of bugs like #66989 and #65379.

Adds no overhead if headers are both added & enumerated without validation.

Simpler to review when hiding whitespace changes.

@MihaZupanMihaZupan added this to the 7.0.0 milestone Apr 16, 2022
@MihaZupanMihaZupan self-assigned this Apr 16, 2022
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #61798

Adds no overhead if headers are both added & enumerated without validation.

Author:MihaZupan
Assignees:MihaZupan
Labels:

area-System.Net.Http

Milestone:7.0.0

@MihaZupan
MihaZupan requested a review from a teamApril 16, 2022 18:47
@MihaZupan

Copy link
Copy Markdown
MemberAuthor

@dotnet/ncl PTAL

The change boils down to adding a lock when:

  • The values in HeaderStoreItemInfo are being parsed (so its fields are being modified)
  • The values are read from HeaderStoreItemInfo (non-validated reads / copying to a new header collection).

Since a value entry can transition from being a string to a HeaderStoreItemInfo, and we're not locking at those sites, it is expected that a single raw value may end up being parsed multiple times.
Such parsing is idempotent, so this is transparent to the user.

The code also has to be careful when reading the value of a given entry.
For example, the following logic would be problematic:

if(entries[i].ValueisHeaderStoreItemInfo){// ...}else{DoSomething((string)entries[i].Value);// Wrong! The value may now be HeaderStoreItemInfo}

and it should instead be something like

objectvalue=entries[i].Value;if(valueisHeaderStoreItemInfo){// ...}else{DoSomething((string)value);}

I've looked through our current code to make sure this is the case, but it's possible future changes may accidentally break this. I've added a test that should catch most such mistakes, but there may be cases that aren't covered.

@CarnaViireCarnaViire left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but maybe someone else could also take a look 🙂

@CarnaViire

Copy link
Copy Markdown
Member

Does this change fully address #61798 ? I see the issue mentioning invalid values too, but this change only adds locks?

@MihaZupan

Copy link
Copy Markdown
MemberAuthor

Does this change fully address #61798 ?

Yes. I split off the invalid values part into #67199, as that was a prerequisite for this change.

@MihaZupan
MihaZupan merged commit b00a64d into dotnet:mainMay 6, 2022
@juharris

Copy link
Copy Markdown

Will this change be in an upcoming version 6 update? If so, any idea when?

@MihaZupan

Copy link
Copy Markdown
MemberAuthor

It will be in preview 5 of .NET 7.

If you mean whether it will be backported to 6.0, there are currently no plans for that.

@ghostghost locked as resolved and limited conversation to collaborators Jun 9, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

HttpHeaders thread safety and behavior of invalid values

5 participants

@MihaZupan@CarnaViire@juharris@stephentoub@ManickaP
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Make concurrent reads on HttpHeaders thread-safe - #68115

Merged
MihaZupan merged 1 commit into
dotnet:mainfrom
MihaZupan:httpheaders-thread-safe-reads
May 6, 2022
Merged

Make concurrent reads on HttpHeaders thread-safe#68115
MihaZupan merged 1 commit into
dotnet:mainfrom
MihaZupan:httpheaders-thread-safe-reads

Conversation

@MihaZupan

@MihaZupanMihaZupan commented Apr 16, 2022

Copy link
Copy Markdown
Member

Fixes#61798
Lowers the impact of bugs like #66989 and #65379.

Adds no overhead if headers are both added & enumerated without validation.

Simpler to review when hiding whitespace changes.

@MihaZupanMihaZupan added this to the 7.0.0 milestone Apr 16, 2022
@MihaZupanMihaZupan self-assigned this Apr 16, 2022
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #61798

Adds no overhead if headers are both added & enumerated without validation.

Author:MihaZupan
Assignees:MihaZupan
Labels:

area-System.Net.Http

Milestone:7.0.0

@MihaZupan
MihaZupan requested a review from a teamApril 16, 2022 18:47
@MihaZupan

Copy link
Copy Markdown
MemberAuthor

@dotnet/ncl PTAL

The change boils down to adding a lock when:

  • The values in HeaderStoreItemInfo are being parsed (so its fields are being modified)
  • The values are read from HeaderStoreItemInfo (non-validated reads / copying to a new header collection).

Since a value entry can transition from being a string to a HeaderStoreItemInfo, and we're not locking at those sites, it is expected that a single raw value may end up being parsed multiple times.
Such parsing is idempotent, so this is transparent to the user.

The code also has to be careful when reading the value of a given entry.
For example, the following logic would be problematic:

if(entries[i].ValueisHeaderStoreItemInfo){// ...}else{DoSomething((string)entries[i].Value);// Wrong! The value may now be HeaderStoreItemInfo}

and it should instead be something like

objectvalue=entries[i].Value;if(valueisHeaderStoreItemInfo){// ...}else{DoSomething((string)value);}

I've looked through our current code to make sure this is the case, but it's possible future changes may accidentally break this. I've added a test that should catch most such mistakes, but there may be cases that aren't covered.

@CarnaViireCarnaViire left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but maybe someone else could also take a look 🙂

@CarnaViire

Copy link
Copy Markdown
Member

Does this change fully address #61798 ? I see the issue mentioning invalid values too, but this change only adds locks?

@MihaZupan

Copy link
Copy Markdown
MemberAuthor

Does this change fully address #61798 ?

Yes. I split off the invalid values part into #67199, as that was a prerequisite for this change.

@MihaZupan
MihaZupan merged commit b00a64d into dotnet:mainMay 6, 2022
@juharris

Copy link
Copy Markdown

Will this change be in an upcoming version 6 update? If so, any idea when?

@MihaZupan

Copy link
Copy Markdown
MemberAuthor

It will be in preview 5 of .NET 7.

If you mean whether it will be backported to 6.0, there are currently no plans for that.

@ghostghost locked as resolved and limited conversation to collaborators Jun 9, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

HttpHeaders thread safety and behavior of invalid values

5 participants

@MihaZupan@CarnaViire@juharris@stephentoub@ManickaP
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Make concurrent reads on HttpHeaders thread-safe - #68115

Merged
MihaZupan merged 1 commit into
dotnet:mainfrom
MihaZupan:httpheaders-thread-safe-reads
May 6, 2022
Merged

Make concurrent reads on HttpHeaders thread-safe#68115
MihaZupan merged 1 commit into
dotnet:mainfrom
MihaZupan:httpheaders-thread-safe-reads

Conversation

@MihaZupan

@MihaZupanMihaZupan commented Apr 16, 2022

Copy link
Copy Markdown
Member

Fixes#61798
Lowers the impact of bugs like #66989 and #65379.

Adds no overhead if headers are both added & enumerated without validation.

Simpler to review when hiding whitespace changes.

@MihaZupanMihaZupan added this to the 7.0.0 milestone Apr 16, 2022
@MihaZupanMihaZupan self-assigned this Apr 16, 2022
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #61798

Adds no overhead if headers are both added & enumerated without validation.

Author:MihaZupan
Assignees:MihaZupan
Labels:

area-System.Net.Http

Milestone:7.0.0

@MihaZupan
MihaZupan requested a review from a teamApril 16, 2022 18:47
@MihaZupan

Copy link
Copy Markdown
MemberAuthor

@dotnet/ncl PTAL

The change boils down to adding a lock when:

  • The values in HeaderStoreItemInfo are being parsed (so its fields are being modified)
  • The values are read from HeaderStoreItemInfo (non-validated reads / copying to a new header collection).

Since a value entry can transition from being a string to a HeaderStoreItemInfo, and we're not locking at those sites, it is expected that a single raw value may end up being parsed multiple times.
Such parsing is idempotent, so this is transparent to the user.

The code also has to be careful when reading the value of a given entry.
For example, the following logic would be problematic:

if(entries[i].ValueisHeaderStoreItemInfo){// ...}else{DoSomething((string)entries[i].Value);// Wrong! The value may now be HeaderStoreItemInfo}

and it should instead be something like

objectvalue=entries[i].Value;if(valueisHeaderStoreItemInfo){// ...}else{DoSomething((string)value);}

I've looked through our current code to make sure this is the case, but it's possible future changes may accidentally break this. I've added a test that should catch most such mistakes, but there may be cases that aren't covered.

@CarnaViireCarnaViire left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but maybe someone else could also take a look 🙂

@CarnaViire

Copy link
Copy Markdown
Member

Does this change fully address #61798 ? I see the issue mentioning invalid values too, but this change only adds locks?

@MihaZupan

Copy link
Copy Markdown
MemberAuthor

Does this change fully address #61798 ?

Yes. I split off the invalid values part into #67199, as that was a prerequisite for this change.

@MihaZupan
MihaZupan merged commit b00a64d into dotnet:mainMay 6, 2022
@juharris

Copy link
Copy Markdown

Will this change be in an upcoming version 6 update? If so, any idea when?

@MihaZupan

Copy link
Copy Markdown
MemberAuthor

It will be in preview 5 of .NET 7.

If you mean whether it will be backported to 6.0, there are currently no plans for that.

@ghostghost locked as resolved and limited conversation to collaborators Jun 9, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

HttpHeaders thread safety and behavior of invalid values

5 participants

@MihaZupan@CarnaViire@juharris@stephentoub@ManickaP
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Make concurrent reads on HttpHeaders thread-safe - #68115

Merged
MihaZupan merged 1 commit into
dotnet:mainfrom
MihaZupan:httpheaders-thread-safe-reads
May 6, 2022
Merged

Make concurrent reads on HttpHeaders thread-safe#68115
MihaZupan merged 1 commit into
dotnet:mainfrom
MihaZupan:httpheaders-thread-safe-reads

Conversation

@MihaZupan

@MihaZupanMihaZupan commented Apr 16, 2022

Copy link
Copy Markdown
Member

Fixes#61798
Lowers the impact of bugs like #66989 and #65379.

Adds no overhead if headers are both added & enumerated without validation.

Simpler to review when hiding whitespace changes.

@MihaZupanMihaZupan added this to the 7.0.0 milestone Apr 16, 2022
@MihaZupanMihaZupan self-assigned this Apr 16, 2022
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #61798

Adds no overhead if headers are both added & enumerated without validation.

Author:MihaZupan
Assignees:MihaZupan
Labels:

area-System.Net.Http

Milestone:7.0.0

@MihaZupan
MihaZupan requested a review from a teamApril 16, 2022 18:47
@MihaZupan

Copy link
Copy Markdown
MemberAuthor

@dotnet/ncl PTAL

The change boils down to adding a lock when:

  • The values in HeaderStoreItemInfo are being parsed (so its fields are being modified)
  • The values are read from HeaderStoreItemInfo (non-validated reads / copying to a new header collection).

Since a value entry can transition from being a string to a HeaderStoreItemInfo, and we're not locking at those sites, it is expected that a single raw value may end up being parsed multiple times.
Such parsing is idempotent, so this is transparent to the user.

The code also has to be careful when reading the value of a given entry.
For example, the following logic would be problematic:

if(entries[i].ValueisHeaderStoreItemInfo){// ...}else{DoSomething((string)entries[i].Value);// Wrong! The value may now be HeaderStoreItemInfo}

and it should instead be something like

objectvalue=entries[i].Value;if(valueisHeaderStoreItemInfo){// ...}else{DoSomething((string)value);}

I've looked through our current code to make sure this is the case, but it's possible future changes may accidentally break this. I've added a test that should catch most such mistakes, but there may be cases that aren't covered.

@CarnaViireCarnaViire left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but maybe someone else could also take a look 🙂

@CarnaViire

Copy link
Copy Markdown
Member

Does this change fully address #61798 ? I see the issue mentioning invalid values too, but this change only adds locks?

@MihaZupan

Copy link
Copy Markdown
MemberAuthor

Does this change fully address #61798 ?

Yes. I split off the invalid values part into #67199, as that was a prerequisite for this change.

@MihaZupan
MihaZupan merged commit b00a64d into dotnet:mainMay 6, 2022
@juharris

Copy link
Copy Markdown

Will this change be in an upcoming version 6 update? If so, any idea when?

@MihaZupan

Copy link
Copy Markdown
MemberAuthor

It will be in preview 5 of .NET 7.

If you mean whether it will be backported to 6.0, there are currently no plans for that.

@ghostghost locked as resolved and limited conversation to collaborators Jun 9, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

HttpHeaders thread safety and behavior of invalid values

5 participants

@MihaZupan@CarnaViire@juharris@stephentoub@ManickaP
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Make concurrent reads on HttpHeaders thread-safe - #68115

Merged
MihaZupan merged 1 commit into
dotnet:mainfrom
MihaZupan:httpheaders-thread-safe-reads
May 6, 2022
Merged

Make concurrent reads on HttpHeaders thread-safe#68115
MihaZupan merged 1 commit into
dotnet:mainfrom
MihaZupan:httpheaders-thread-safe-reads

Conversation

@MihaZupan

@MihaZupanMihaZupan commented Apr 16, 2022

Copy link
Copy Markdown
Member

Fixes#61798
Lowers the impact of bugs like #66989 and #65379.

Adds no overhead if headers are both added & enumerated without validation.

Simpler to review when hiding whitespace changes.

@MihaZupanMihaZupan added this to the 7.0.0 milestone Apr 16, 2022
@MihaZupanMihaZupan self-assigned this Apr 16, 2022
@ghost

Copy link
Copy Markdown

Tagging subscribers to this area: @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Issue Details

Fixes #61798

Adds no overhead if headers are both added & enumerated without validation.

Author:MihaZupan
Assignees:MihaZupan
Labels:

area-System.Net.Http

Milestone:7.0.0

@MihaZupan
MihaZupan requested a review from a teamApril 16, 2022 18:47
@MihaZupan

Copy link
Copy Markdown
MemberAuthor

@dotnet/ncl PTAL

The change boils down to adding a lock when:

  • The values in HeaderStoreItemInfo are being parsed (so its fields are being modified)
  • The values are read from HeaderStoreItemInfo (non-validated reads / copying to a new header collection).

Since a value entry can transition from being a string to a HeaderStoreItemInfo, and we're not locking at those sites, it is expected that a single raw value may end up being parsed multiple times.
Such parsing is idempotent, so this is transparent to the user.

The code also has to be careful when reading the value of a given entry.
For example, the following logic would be problematic:

if(entries[i].ValueisHeaderStoreItemInfo){// ...}else{DoSomething((string)entries[i].Value);// Wrong! The value may now be HeaderStoreItemInfo}

and it should instead be something like

objectvalue=entries[i].Value;if(valueisHeaderStoreItemInfo){// ...}else{DoSomething((string)value);}

I've looked through our current code to make sure this is the case, but it's possible future changes may accidentally break this. I've added a test that should catch most such mistakes, but there may be cases that aren't covered.

@CarnaViireCarnaViire left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but maybe someone else could also take a look 🙂

@CarnaViire

Copy link
Copy Markdown
Member

Does this change fully address #61798 ? I see the issue mentioning invalid values too, but this change only adds locks?

@MihaZupan

Copy link
Copy Markdown
MemberAuthor

Does this change fully address #61798 ?

Yes. I split off the invalid values part into #67199, as that was a prerequisite for this change.

@MihaZupan
MihaZupan merged commit b00a64d into dotnet:mainMay 6, 2022
@juharris

Copy link
Copy Markdown

Will this change be in an upcoming version 6 update? If so, any idea when?

@MihaZupan

Copy link
Copy Markdown
MemberAuthor

It will be in preview 5 of .NET 7.

If you mean whether it will be backported to 6.0, there are currently no plans for that.

@ghostghost locked as resolved and limited conversation to collaborators Jun 9, 2022
Sign up for freeto subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

HttpHeaders thread safety and behavior of invalid values

5 participants

@MihaZupan@CarnaViire@juharris@stephentoub@ManickaP