This repository was archived by the owner on Jun 15, 2025. It is now read-only.

Latest commit

History

143 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Warning!

This repository is unmaintained anymore. Parser has multiple performance issues and bugs that must be fixed, so if you gonna use, please open an issue

SnowDrop

A LLHTTP-like HTTP requests parser. As there are no external HTTP parsers in golang (excluding wildcat, but it doesn't support stream-based parsing and last time it was contributed is 2014), so I decided to do it by my own as I need it for my web-server. The decision to do parser and external package follows the idea that it'll be more clear to divide web-server and http parser, but also to let other people use it in their projects if they need it.

Simple usage:

This parser is inspired by LLHTTP, as I said before. So, you need to implement a protocol, which is a usual struct, but needs to implement such a methods:

typeProtocolinterface {
OnMessageBegin() errorOnMethod([]byte) errorOnPath([]byte) errorOnProtocol([]byte) errorOnHeadersBegin() errorOnHeader([]byte, []byte) errorOnHeadersComplete() errorOnBody([]byte) errorOnMessageComplete() error
}

Example of implemented protocol you can find here

Also parser has settings structure:

typeSettingsstruct {
// hard limitsMaxPathLengthintMaxHeaderLineLengthintMaxBodyLengthintMaxChunkLengthint// soft limitsInitialPathBufferLengthintInitialHeadersBufferLengthintStartLineBuffer []byteHeadersBuffer []byte
}

This settings are passed to parser ALWAYS. It may be even not specified as parser will set unspecified values with default ones. If buffers aren't specified, they will be allocated automatically. All this stuff you can find in httpparser/settings.go

FAQ

Q: How does parser behave in case of chunked request?

A: OnBody() callback will be called each time when a piece of body was received. It may be even one single byte


Q: How does parser behave in case of extra-bytes are passed?

A: Parser is stream-based, so parser's lifetime equals to connection lifetime. This means that extra-bytes will be parsed as a beginning of the next request


Q: Can it parse requests that use not CRLF, but just LF?

A: Yes. Parser can parse even requests with mixed usage of CRLF and LF


Q: What's if it is not a GET request, but Content-Length is not specified?

A: Request's body will be marked as empty (QA below referrs to this question), if "Connection" header is not set to closed (in this case, request body will be parsed until empty bytes array will be passed as a food)


Q: How will parser behave in case of empty request body?

A: OnBody() will be never called, but OnMessageComplete() will


Q: What will happen if an error will occur?

A: Parser will die (the state of it will be set to "dead" forever), and all the attempts to feed it again will return ParserIsDead error


Q: What's if an error occurred in protocol callback?

A: Parser will die and return error from callback to server, BUT in case httpparser.Upgrade struct is returned from OnMessageComplete(), server won't die, but will just return the error to http server. Warning: in case httpparser.Upgrade will be returned from any other callback, this won't work and parser will die anyway


Q: What's if we have a simple request that doesn't even contains headers, for example, GET / HTTP/1.1\r\n\r\n?

A: There are 7 obligatory callbacks that are guarantateed to be called (if no errors occurred): OnMessageBegin, OnMethod, OnPath, OnProtocol, OnHeadersBegin, OnHeadersComplete, OnMessageComplete. So all them will be called during parsing ANY request except invalid ones

Example:

package main
import (
"github.com/floordiv/snowdrop-http/src/httpparser"
)
typeMyProtocolstruct {
// implement httpparser.Protocol here
}
funcmain() {
protocol:=MyProtocol{...}
parser:=httpparser.NewHTTPRequestParser(&protocol, httpparser.Settings{})
data:=...// http request taken from any source, with []byte typeiferr:=parser.Feed(data); err!=nil {
// parser isn't able to parse anymorelog.Fatal(err)
}
// that's it! Now everything has been processed with your protocol
}

Parser also can return errors:

  • ErrInvalidMethod
  • ErrInvalidPath
  • ErrProtocolNotSupported
  • ErrInvalidHeader
  • ErrBufferOverflow
  • ErrInvalidContentLength
  • ErrRequestSyntaxError
  • ErrBodyTooBig
  • ErrTooBigChunkSize
  • ErrInvalidChunkSize
  • ErrInvalidChunkSplitter
  • ErrConnectionClosed
  • ErrParserIsDead

Important: this is not a finite list of errors may be returned by parser. In case of errors returned from callbacks, parser will die and return error from callback

Also httpparser.Upgrade struct may be returned as an error. It can be constructed from httpparser.NewUpgrade(string) function

Details about errors you can find in httpparser/errors.go

About

HTTP zero-allocations parser for golang, inspired by llhttp

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, '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
This repository was archived by the owner on Jun 15, 2025. It is now read-only.

Latest commit

History

143 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Warning!

This repository is unmaintained anymore. Parser has multiple performance issues and bugs that must be fixed, so if you gonna use, please open an issue

SnowDrop

A LLHTTP-like HTTP requests parser. As there are no external HTTP parsers in golang (excluding wildcat, but it doesn't support stream-based parsing and last time it was contributed is 2014), so I decided to do it by my own as I need it for my web-server. The decision to do parser and external package follows the idea that it'll be more clear to divide web-server and http parser, but also to let other people use it in their projects if they need it.

Simple usage:

This parser is inspired by LLHTTP, as I said before. So, you need to implement a protocol, which is a usual struct, but needs to implement such a methods:

typeProtocolinterface {
OnMessageBegin() errorOnMethod([]byte) errorOnPath([]byte) errorOnProtocol([]byte) errorOnHeadersBegin() errorOnHeader([]byte, []byte) errorOnHeadersComplete() errorOnBody([]byte) errorOnMessageComplete() error
}

Example of implemented protocol you can find here

Also parser has settings structure:

typeSettingsstruct {
// hard limitsMaxPathLengthintMaxHeaderLineLengthintMaxBodyLengthintMaxChunkLengthint// soft limitsInitialPathBufferLengthintInitialHeadersBufferLengthintStartLineBuffer []byteHeadersBuffer []byte
}

This settings are passed to parser ALWAYS. It may be even not specified as parser will set unspecified values with default ones. If buffers aren't specified, they will be allocated automatically. All this stuff you can find in httpparser/settings.go

FAQ

Q: How does parser behave in case of chunked request?

A: OnBody() callback will be called each time when a piece of body was received. It may be even one single byte


Q: How does parser behave in case of extra-bytes are passed?

A: Parser is stream-based, so parser's lifetime equals to connection lifetime. This means that extra-bytes will be parsed as a beginning of the next request


Q: Can it parse requests that use not CRLF, but just LF?

A: Yes. Parser can parse even requests with mixed usage of CRLF and LF


Q: What's if it is not a GET request, but Content-Length is not specified?

A: Request's body will be marked as empty (QA below referrs to this question), if "Connection" header is not set to closed (in this case, request body will be parsed until empty bytes array will be passed as a food)


Q: How will parser behave in case of empty request body?

A: OnBody() will be never called, but OnMessageComplete() will


Q: What will happen if an error will occur?

A: Parser will die (the state of it will be set to "dead" forever), and all the attempts to feed it again will return ParserIsDead error


Q: What's if an error occurred in protocol callback?

A: Parser will die and return error from callback to server, BUT in case httpparser.Upgrade struct is returned from OnMessageComplete(), server won't die, but will just return the error to http server. Warning: in case httpparser.Upgrade will be returned from any other callback, this won't work and parser will die anyway


Q: What's if we have a simple request that doesn't even contains headers, for example, GET / HTTP/1.1\r\n\r\n?

A: There are 7 obligatory callbacks that are guarantateed to be called (if no errors occurred): OnMessageBegin, OnMethod, OnPath, OnProtocol, OnHeadersBegin, OnHeadersComplete, OnMessageComplete. So all them will be called during parsing ANY request except invalid ones

Example:

package main
import (
"github.com/floordiv/snowdrop-http/src/httpparser"
)
typeMyProtocolstruct {
// implement httpparser.Protocol here
}
funcmain() {
protocol:=MyProtocol{...}
parser:=httpparser.NewHTTPRequestParser(&protocol, httpparser.Settings{})
data:=...// http request taken from any source, with []byte typeiferr:=parser.Feed(data); err!=nil {
// parser isn't able to parse anymorelog.Fatal(err)
}
// that's it! Now everything has been processed with your protocol
}

Parser also can return errors:

  • ErrInvalidMethod
  • ErrInvalidPath
  • ErrProtocolNotSupported
  • ErrInvalidHeader
  • ErrBufferOverflow
  • ErrInvalidContentLength
  • ErrRequestSyntaxError
  • ErrBodyTooBig
  • ErrTooBigChunkSize
  • ErrInvalidChunkSize
  • ErrInvalidChunkSplitter
  • ErrConnectionClosed
  • ErrParserIsDead

Important: this is not a finite list of errors may be returned by parser. In case of errors returned from callbacks, parser will die and return error from callback

Also httpparser.Upgrade struct may be returned as an error. It can be constructed from httpparser.NewUpgrade(string) function

Details about errors you can find in httpparser/errors.go

About

HTTP zero-allocations parser for golang, inspired by llhttp

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, '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
This repository was archived by the owner on Jun 15, 2025. It is now read-only.

Latest commit

History

143 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Warning!

This repository is unmaintained anymore. Parser has multiple performance issues and bugs that must be fixed, so if you gonna use, please open an issue

SnowDrop

A LLHTTP-like HTTP requests parser. As there are no external HTTP parsers in golang (excluding wildcat, but it doesn't support stream-based parsing and last time it was contributed is 2014), so I decided to do it by my own as I need it for my web-server. The decision to do parser and external package follows the idea that it'll be more clear to divide web-server and http parser, but also to let other people use it in their projects if they need it.

Simple usage:

This parser is inspired by LLHTTP, as I said before. So, you need to implement a protocol, which is a usual struct, but needs to implement such a methods:

typeProtocolinterface {
OnMessageBegin() errorOnMethod([]byte) errorOnPath([]byte) errorOnProtocol([]byte) errorOnHeadersBegin() errorOnHeader([]byte, []byte) errorOnHeadersComplete() errorOnBody([]byte) errorOnMessageComplete() error
}

Example of implemented protocol you can find here

Also parser has settings structure:

typeSettingsstruct {
// hard limitsMaxPathLengthintMaxHeaderLineLengthintMaxBodyLengthintMaxChunkLengthint// soft limitsInitialPathBufferLengthintInitialHeadersBufferLengthintStartLineBuffer []byteHeadersBuffer []byte
}

This settings are passed to parser ALWAYS. It may be even not specified as parser will set unspecified values with default ones. If buffers aren't specified, they will be allocated automatically. All this stuff you can find in httpparser/settings.go

FAQ

Q: How does parser behave in case of chunked request?

A: OnBody() callback will be called each time when a piece of body was received. It may be even one single byte


Q: How does parser behave in case of extra-bytes are passed?

A: Parser is stream-based, so parser's lifetime equals to connection lifetime. This means that extra-bytes will be parsed as a beginning of the next request


Q: Can it parse requests that use not CRLF, but just LF?

A: Yes. Parser can parse even requests with mixed usage of CRLF and LF


Q: What's if it is not a GET request, but Content-Length is not specified?

A: Request's body will be marked as empty (QA below referrs to this question), if "Connection" header is not set to closed (in this case, request body will be parsed until empty bytes array will be passed as a food)


Q: How will parser behave in case of empty request body?

A: OnBody() will be never called, but OnMessageComplete() will


Q: What will happen if an error will occur?

A: Parser will die (the state of it will be set to "dead" forever), and all the attempts to feed it again will return ParserIsDead error


Q: What's if an error occurred in protocol callback?

A: Parser will die and return error from callback to server, BUT in case httpparser.Upgrade struct is returned from OnMessageComplete(), server won't die, but will just return the error to http server. Warning: in case httpparser.Upgrade will be returned from any other callback, this won't work and parser will die anyway


Q: What's if we have a simple request that doesn't even contains headers, for example, GET / HTTP/1.1\r\n\r\n?

A: There are 7 obligatory callbacks that are guarantateed to be called (if no errors occurred): OnMessageBegin, OnMethod, OnPath, OnProtocol, OnHeadersBegin, OnHeadersComplete, OnMessageComplete. So all them will be called during parsing ANY request except invalid ones

Example:

package main
import (
"github.com/floordiv/snowdrop-http/src/httpparser"
)
typeMyProtocolstruct {
// implement httpparser.Protocol here
}
funcmain() {
protocol:=MyProtocol{...}
parser:=httpparser.NewHTTPRequestParser(&protocol, httpparser.Settings{})
data:=...// http request taken from any source, with []byte typeiferr:=parser.Feed(data); err!=nil {
// parser isn't able to parse anymorelog.Fatal(err)
}
// that's it! Now everything has been processed with your protocol
}

Parser also can return errors:

  • ErrInvalidMethod
  • ErrInvalidPath
  • ErrProtocolNotSupported
  • ErrInvalidHeader
  • ErrBufferOverflow
  • ErrInvalidContentLength
  • ErrRequestSyntaxError
  • ErrBodyTooBig
  • ErrTooBigChunkSize
  • ErrInvalidChunkSize
  • ErrInvalidChunkSplitter
  • ErrConnectionClosed
  • ErrParserIsDead

Important: this is not a finite list of errors may be returned by parser. In case of errors returned from callbacks, parser will die and return error from callback

Also httpparser.Upgrade struct may be returned as an error. It can be constructed from httpparser.NewUpgrade(string) function

Details about errors you can find in httpparser/errors.go

About

HTTP zero-allocations parser for golang, inspired by llhttp

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, '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
This repository was archived by the owner on Jun 15, 2025. It is now read-only.

Latest commit

History

143 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Warning!

This repository is unmaintained anymore. Parser has multiple performance issues and bugs that must be fixed, so if you gonna use, please open an issue

SnowDrop

A LLHTTP-like HTTP requests parser. As there are no external HTTP parsers in golang (excluding wildcat, but it doesn't support stream-based parsing and last time it was contributed is 2014), so I decided to do it by my own as I need it for my web-server. The decision to do parser and external package follows the idea that it'll be more clear to divide web-server and http parser, but also to let other people use it in their projects if they need it.

Simple usage:

This parser is inspired by LLHTTP, as I said before. So, you need to implement a protocol, which is a usual struct, but needs to implement such a methods:

typeProtocolinterface {
OnMessageBegin() errorOnMethod([]byte) errorOnPath([]byte) errorOnProtocol([]byte) errorOnHeadersBegin() errorOnHeader([]byte, []byte) errorOnHeadersComplete() errorOnBody([]byte) errorOnMessageComplete() error
}

Example of implemented protocol you can find here

Also parser has settings structure:

typeSettingsstruct {
// hard limitsMaxPathLengthintMaxHeaderLineLengthintMaxBodyLengthintMaxChunkLengthint// soft limitsInitialPathBufferLengthintInitialHeadersBufferLengthintStartLineBuffer []byteHeadersBuffer []byte
}

This settings are passed to parser ALWAYS. It may be even not specified as parser will set unspecified values with default ones. If buffers aren't specified, they will be allocated automatically. All this stuff you can find in httpparser/settings.go

FAQ

Q: How does parser behave in case of chunked request?

A: OnBody() callback will be called each time when a piece of body was received. It may be even one single byte


Q: How does parser behave in case of extra-bytes are passed?

A: Parser is stream-based, so parser's lifetime equals to connection lifetime. This means that extra-bytes will be parsed as a beginning of the next request


Q: Can it parse requests that use not CRLF, but just LF?

A: Yes. Parser can parse even requests with mixed usage of CRLF and LF


Q: What's if it is not a GET request, but Content-Length is not specified?

A: Request's body will be marked as empty (QA below referrs to this question), if "Connection" header is not set to closed (in this case, request body will be parsed until empty bytes array will be passed as a food)


Q: How will parser behave in case of empty request body?

A: OnBody() will be never called, but OnMessageComplete() will


Q: What will happen if an error will occur?

A: Parser will die (the state of it will be set to "dead" forever), and all the attempts to feed it again will return ParserIsDead error


Q: What's if an error occurred in protocol callback?

A: Parser will die and return error from callback to server, BUT in case httpparser.Upgrade struct is returned from OnMessageComplete(), server won't die, but will just return the error to http server. Warning: in case httpparser.Upgrade will be returned from any other callback, this won't work and parser will die anyway


Q: What's if we have a simple request that doesn't even contains headers, for example, GET / HTTP/1.1\r\n\r\n?

A: There are 7 obligatory callbacks that are guarantateed to be called (if no errors occurred): OnMessageBegin, OnMethod, OnPath, OnProtocol, OnHeadersBegin, OnHeadersComplete, OnMessageComplete. So all them will be called during parsing ANY request except invalid ones

Example:

package main
import (
"github.com/floordiv/snowdrop-http/src/httpparser"
)
typeMyProtocolstruct {
// implement httpparser.Protocol here
}
funcmain() {
protocol:=MyProtocol{...}
parser:=httpparser.NewHTTPRequestParser(&protocol, httpparser.Settings{})
data:=...// http request taken from any source, with []byte typeiferr:=parser.Feed(data); err!=nil {
// parser isn't able to parse anymorelog.Fatal(err)
}
// that's it! Now everything has been processed with your protocol
}

Parser also can return errors:

  • ErrInvalidMethod
  • ErrInvalidPath
  • ErrProtocolNotSupported
  • ErrInvalidHeader
  • ErrBufferOverflow
  • ErrInvalidContentLength
  • ErrRequestSyntaxError
  • ErrBodyTooBig
  • ErrTooBigChunkSize
  • ErrInvalidChunkSize
  • ErrInvalidChunkSplitter
  • ErrConnectionClosed
  • ErrParserIsDead

Important: this is not a finite list of errors may be returned by parser. In case of errors returned from callbacks, parser will die and return error from callback

Also httpparser.Upgrade struct may be returned as an error. It can be constructed from httpparser.NewUpgrade(string) function

Details about errors you can find in httpparser/errors.go

About

HTTP zero-allocations parser for golang, inspired by llhttp

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, '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
This repository was archived by the owner on Jun 15, 2025. It is now read-only.

Latest commit

History

143 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Warning!

This repository is unmaintained anymore. Parser has multiple performance issues and bugs that must be fixed, so if you gonna use, please open an issue

SnowDrop

A LLHTTP-like HTTP requests parser. As there are no external HTTP parsers in golang (excluding wildcat, but it doesn't support stream-based parsing and last time it was contributed is 2014), so I decided to do it by my own as I need it for my web-server. The decision to do parser and external package follows the idea that it'll be more clear to divide web-server and http parser, but also to let other people use it in their projects if they need it.

Simple usage:

This parser is inspired by LLHTTP, as I said before. So, you need to implement a protocol, which is a usual struct, but needs to implement such a methods:

typeProtocolinterface {
OnMessageBegin() errorOnMethod([]byte) errorOnPath([]byte) errorOnProtocol([]byte) errorOnHeadersBegin() errorOnHeader([]byte, []byte) errorOnHeadersComplete() errorOnBody([]byte) errorOnMessageComplete() error
}

Example of implemented protocol you can find here

Also parser has settings structure:

typeSettingsstruct {
// hard limitsMaxPathLengthintMaxHeaderLineLengthintMaxBodyLengthintMaxChunkLengthint// soft limitsInitialPathBufferLengthintInitialHeadersBufferLengthintStartLineBuffer []byteHeadersBuffer []byte
}

This settings are passed to parser ALWAYS. It may be even not specified as parser will set unspecified values with default ones. If buffers aren't specified, they will be allocated automatically. All this stuff you can find in httpparser/settings.go

FAQ

Q: How does parser behave in case of chunked request?

A: OnBody() callback will be called each time when a piece of body was received. It may be even one single byte


Q: How does parser behave in case of extra-bytes are passed?

A: Parser is stream-based, so parser's lifetime equals to connection lifetime. This means that extra-bytes will be parsed as a beginning of the next request


Q: Can it parse requests that use not CRLF, but just LF?

A: Yes. Parser can parse even requests with mixed usage of CRLF and LF


Q: What's if it is not a GET request, but Content-Length is not specified?

A: Request's body will be marked as empty (QA below referrs to this question), if "Connection" header is not set to closed (in this case, request body will be parsed until empty bytes array will be passed as a food)


Q: How will parser behave in case of empty request body?

A: OnBody() will be never called, but OnMessageComplete() will


Q: What will happen if an error will occur?

A: Parser will die (the state of it will be set to "dead" forever), and all the attempts to feed it again will return ParserIsDead error


Q: What's if an error occurred in protocol callback?

A: Parser will die and return error from callback to server, BUT in case httpparser.Upgrade struct is returned from OnMessageComplete(), server won't die, but will just return the error to http server. Warning: in case httpparser.Upgrade will be returned from any other callback, this won't work and parser will die anyway


Q: What's if we have a simple request that doesn't even contains headers, for example, GET / HTTP/1.1\r\n\r\n?

A: There are 7 obligatory callbacks that are guarantateed to be called (if no errors occurred): OnMessageBegin, OnMethod, OnPath, OnProtocol, OnHeadersBegin, OnHeadersComplete, OnMessageComplete. So all them will be called during parsing ANY request except invalid ones

Example:

package main
import (
"github.com/floordiv/snowdrop-http/src/httpparser"
)
typeMyProtocolstruct {
// implement httpparser.Protocol here
}
funcmain() {
protocol:=MyProtocol{...}
parser:=httpparser.NewHTTPRequestParser(&protocol, httpparser.Settings{})
data:=...// http request taken from any source, with []byte typeiferr:=parser.Feed(data); err!=nil {
// parser isn't able to parse anymorelog.Fatal(err)
}
// that's it! Now everything has been processed with your protocol
}

Parser also can return errors:

  • ErrInvalidMethod
  • ErrInvalidPath
  • ErrProtocolNotSupported
  • ErrInvalidHeader
  • ErrBufferOverflow
  • ErrInvalidContentLength
  • ErrRequestSyntaxError
  • ErrBodyTooBig
  • ErrTooBigChunkSize
  • ErrInvalidChunkSize
  • ErrInvalidChunkSplitter
  • ErrConnectionClosed
  • ErrParserIsDead

Important: this is not a finite list of errors may be returned by parser. In case of errors returned from callbacks, parser will die and return error from callback

Also httpparser.Upgrade struct may be returned as an error. It can be constructed from httpparser.NewUpgrade(string) function

Details about errors you can find in httpparser/errors.go

About

HTTP zero-allocations parser for golang, inspired by llhttp

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, '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
This repository was archived by the owner on Jun 15, 2025. It is now read-only.

Latest commit

History

143 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Warning!

This repository is unmaintained anymore. Parser has multiple performance issues and bugs that must be fixed, so if you gonna use, please open an issue

SnowDrop

A LLHTTP-like HTTP requests parser. As there are no external HTTP parsers in golang (excluding wildcat, but it doesn't support stream-based parsing and last time it was contributed is 2014), so I decided to do it by my own as I need it for my web-server. The decision to do parser and external package follows the idea that it'll be more clear to divide web-server and http parser, but also to let other people use it in their projects if they need it.

Simple usage:

This parser is inspired by LLHTTP, as I said before. So, you need to implement a protocol, which is a usual struct, but needs to implement such a methods:

typeProtocolinterface {
OnMessageBegin() errorOnMethod([]byte) errorOnPath([]byte) errorOnProtocol([]byte) errorOnHeadersBegin() errorOnHeader([]byte, []byte) errorOnHeadersComplete() errorOnBody([]byte) errorOnMessageComplete() error
}

Example of implemented protocol you can find here

Also parser has settings structure:

typeSettingsstruct {
// hard limitsMaxPathLengthintMaxHeaderLineLengthintMaxBodyLengthintMaxChunkLengthint// soft limitsInitialPathBufferLengthintInitialHeadersBufferLengthintStartLineBuffer []byteHeadersBuffer []byte
}

This settings are passed to parser ALWAYS. It may be even not specified as parser will set unspecified values with default ones. If buffers aren't specified, they will be allocated automatically. All this stuff you can find in httpparser/settings.go

FAQ

Q: How does parser behave in case of chunked request?

A: OnBody() callback will be called each time when a piece of body was received. It may be even one single byte


Q: How does parser behave in case of extra-bytes are passed?

A: Parser is stream-based, so parser's lifetime equals to connection lifetime. This means that extra-bytes will be parsed as a beginning of the next request


Q: Can it parse requests that use not CRLF, but just LF?

A: Yes. Parser can parse even requests with mixed usage of CRLF and LF


Q: What's if it is not a GET request, but Content-Length is not specified?

A: Request's body will be marked as empty (QA below referrs to this question), if "Connection" header is not set to closed (in this case, request body will be parsed until empty bytes array will be passed as a food)


Q: How will parser behave in case of empty request body?

A: OnBody() will be never called, but OnMessageComplete() will


Q: What will happen if an error will occur?

A: Parser will die (the state of it will be set to "dead" forever), and all the attempts to feed it again will return ParserIsDead error


Q: What's if an error occurred in protocol callback?

A: Parser will die and return error from callback to server, BUT in case httpparser.Upgrade struct is returned from OnMessageComplete(), server won't die, but will just return the error to http server. Warning: in case httpparser.Upgrade will be returned from any other callback, this won't work and parser will die anyway


Q: What's if we have a simple request that doesn't even contains headers, for example, GET / HTTP/1.1\r\n\r\n?

A: There are 7 obligatory callbacks that are guarantateed to be called (if no errors occurred): OnMessageBegin, OnMethod, OnPath, OnProtocol, OnHeadersBegin, OnHeadersComplete, OnMessageComplete. So all them will be called during parsing ANY request except invalid ones

Example:

package main
import (
"github.com/floordiv/snowdrop-http/src/httpparser"
)
typeMyProtocolstruct {
// implement httpparser.Protocol here
}
funcmain() {
protocol:=MyProtocol{...}
parser:=httpparser.NewHTTPRequestParser(&protocol, httpparser.Settings{})
data:=...// http request taken from any source, with []byte typeiferr:=parser.Feed(data); err!=nil {
// parser isn't able to parse anymorelog.Fatal(err)
}
// that's it! Now everything has been processed with your protocol
}

Parser also can return errors:

  • ErrInvalidMethod
  • ErrInvalidPath
  • ErrProtocolNotSupported
  • ErrInvalidHeader
  • ErrBufferOverflow
  • ErrInvalidContentLength
  • ErrRequestSyntaxError
  • ErrBodyTooBig
  • ErrTooBigChunkSize
  • ErrInvalidChunkSize
  • ErrInvalidChunkSplitter
  • ErrConnectionClosed
  • ErrParserIsDead

Important: this is not a finite list of errors may be returned by parser. In case of errors returned from callbacks, parser will die and return error from callback

Also httpparser.Upgrade struct may be returned as an error. It can be constructed from httpparser.NewUpgrade(string) function

Details about errors you can find in httpparser/errors.go

About

HTTP zero-allocations parser for golang, inspired by llhttp

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, '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
This repository was archived by the owner on Jun 15, 2025. It is now read-only.

Latest commit

History

143 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Warning!

This repository is unmaintained anymore. Parser has multiple performance issues and bugs that must be fixed, so if you gonna use, please open an issue

SnowDrop

A LLHTTP-like HTTP requests parser. As there are no external HTTP parsers in golang (excluding wildcat, but it doesn't support stream-based parsing and last time it was contributed is 2014), so I decided to do it by my own as I need it for my web-server. The decision to do parser and external package follows the idea that it'll be more clear to divide web-server and http parser, but also to let other people use it in their projects if they need it.

Simple usage:

This parser is inspired by LLHTTP, as I said before. So, you need to implement a protocol, which is a usual struct, but needs to implement such a methods:

typeProtocolinterface {
OnMessageBegin() errorOnMethod([]byte) errorOnPath([]byte) errorOnProtocol([]byte) errorOnHeadersBegin() errorOnHeader([]byte, []byte) errorOnHeadersComplete() errorOnBody([]byte) errorOnMessageComplete() error
}

Example of implemented protocol you can find here

Also parser has settings structure:

typeSettingsstruct {
// hard limitsMaxPathLengthintMaxHeaderLineLengthintMaxBodyLengthintMaxChunkLengthint// soft limitsInitialPathBufferLengthintInitialHeadersBufferLengthintStartLineBuffer []byteHeadersBuffer []byte
}

This settings are passed to parser ALWAYS. It may be even not specified as parser will set unspecified values with default ones. If buffers aren't specified, they will be allocated automatically. All this stuff you can find in httpparser/settings.go

FAQ

Q: How does parser behave in case of chunked request?

A: OnBody() callback will be called each time when a piece of body was received. It may be even one single byte


Q: How does parser behave in case of extra-bytes are passed?

A: Parser is stream-based, so parser's lifetime equals to connection lifetime. This means that extra-bytes will be parsed as a beginning of the next request


Q: Can it parse requests that use not CRLF, but just LF?

A: Yes. Parser can parse even requests with mixed usage of CRLF and LF


Q: What's if it is not a GET request, but Content-Length is not specified?

A: Request's body will be marked as empty (QA below referrs to this question), if "Connection" header is not set to closed (in this case, request body will be parsed until empty bytes array will be passed as a food)


Q: How will parser behave in case of empty request body?

A: OnBody() will be never called, but OnMessageComplete() will


Q: What will happen if an error will occur?

A: Parser will die (the state of it will be set to "dead" forever), and all the attempts to feed it again will return ParserIsDead error


Q: What's if an error occurred in protocol callback?

A: Parser will die and return error from callback to server, BUT in case httpparser.Upgrade struct is returned from OnMessageComplete(), server won't die, but will just return the error to http server. Warning: in case httpparser.Upgrade will be returned from any other callback, this won't work and parser will die anyway


Q: What's if we have a simple request that doesn't even contains headers, for example, GET / HTTP/1.1\r\n\r\n?

A: There are 7 obligatory callbacks that are guarantateed to be called (if no errors occurred): OnMessageBegin, OnMethod, OnPath, OnProtocol, OnHeadersBegin, OnHeadersComplete, OnMessageComplete. So all them will be called during parsing ANY request except invalid ones

Example:

package main
import (
"github.com/floordiv/snowdrop-http/src/httpparser"
)
typeMyProtocolstruct {
// implement httpparser.Protocol here
}
funcmain() {
protocol:=MyProtocol{...}
parser:=httpparser.NewHTTPRequestParser(&protocol, httpparser.Settings{})
data:=...// http request taken from any source, with []byte typeiferr:=parser.Feed(data); err!=nil {
// parser isn't able to parse anymorelog.Fatal(err)
}
// that's it! Now everything has been processed with your protocol
}

Parser also can return errors:

  • ErrInvalidMethod
  • ErrInvalidPath
  • ErrProtocolNotSupported
  • ErrInvalidHeader
  • ErrBufferOverflow
  • ErrInvalidContentLength
  • ErrRequestSyntaxError
  • ErrBodyTooBig
  • ErrTooBigChunkSize
  • ErrInvalidChunkSize
  • ErrInvalidChunkSplitter
  • ErrConnectionClosed
  • ErrParserIsDead

Important: this is not a finite list of errors may be returned by parser. In case of errors returned from callbacks, parser will die and return error from callback

Also httpparser.Upgrade struct may be returned as an error. It can be constructed from httpparser.NewUpgrade(string) function

Details about errors you can find in httpparser/errors.go

About

HTTP zero-allocations parser for golang, inspired by llhttp

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages

, '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
This repository was archived by the owner on Jun 15, 2025. It is now read-only.

Latest commit

History

143 Commits

Folders and files

NameName
Last commit message
Last commit date

Repository files navigation

Warning!

This repository is unmaintained anymore. Parser has multiple performance issues and bugs that must be fixed, so if you gonna use, please open an issue

SnowDrop

A LLHTTP-like HTTP requests parser. As there are no external HTTP parsers in golang (excluding wildcat, but it doesn't support stream-based parsing and last time it was contributed is 2014), so I decided to do it by my own as I need it for my web-server. The decision to do parser and external package follows the idea that it'll be more clear to divide web-server and http parser, but also to let other people use it in their projects if they need it.

Simple usage:

This parser is inspired by LLHTTP, as I said before. So, you need to implement a protocol, which is a usual struct, but needs to implement such a methods:

typeProtocolinterface {
OnMessageBegin() errorOnMethod([]byte) errorOnPath([]byte) errorOnProtocol([]byte) errorOnHeadersBegin() errorOnHeader([]byte, []byte) errorOnHeadersComplete() errorOnBody([]byte) errorOnMessageComplete() error
}

Example of implemented protocol you can find here

Also parser has settings structure:

typeSettingsstruct {
// hard limitsMaxPathLengthintMaxHeaderLineLengthintMaxBodyLengthintMaxChunkLengthint// soft limitsInitialPathBufferLengthintInitialHeadersBufferLengthintStartLineBuffer []byteHeadersBuffer []byte
}

This settings are passed to parser ALWAYS. It may be even not specified as parser will set unspecified values with default ones. If buffers aren't specified, they will be allocated automatically. All this stuff you can find in httpparser/settings.go

FAQ

Q: How does parser behave in case of chunked request?

A: OnBody() callback will be called each time when a piece of body was received. It may be even one single byte


Q: How does parser behave in case of extra-bytes are passed?

A: Parser is stream-based, so parser's lifetime equals to connection lifetime. This means that extra-bytes will be parsed as a beginning of the next request


Q: Can it parse requests that use not CRLF, but just LF?

A: Yes. Parser can parse even requests with mixed usage of CRLF and LF


Q: What's if it is not a GET request, but Content-Length is not specified?

A: Request's body will be marked as empty (QA below referrs to this question), if "Connection" header is not set to closed (in this case, request body will be parsed until empty bytes array will be passed as a food)


Q: How will parser behave in case of empty request body?

A: OnBody() will be never called, but OnMessageComplete() will


Q: What will happen if an error will occur?

A: Parser will die (the state of it will be set to "dead" forever), and all the attempts to feed it again will return ParserIsDead error


Q: What's if an error occurred in protocol callback?

A: Parser will die and return error from callback to server, BUT in case httpparser.Upgrade struct is returned from OnMessageComplete(), server won't die, but will just return the error to http server. Warning: in case httpparser.Upgrade will be returned from any other callback, this won't work and parser will die anyway


Q: What's if we have a simple request that doesn't even contains headers, for example, GET / HTTP/1.1\r\n\r\n?

A: There are 7 obligatory callbacks that are guarantateed to be called (if no errors occurred): OnMessageBegin, OnMethod, OnPath, OnProtocol, OnHeadersBegin, OnHeadersComplete, OnMessageComplete. So all them will be called during parsing ANY request except invalid ones

Example:

package main
import (
"github.com/floordiv/snowdrop-http/src/httpparser"
)
typeMyProtocolstruct {
// implement httpparser.Protocol here
}
funcmain() {
protocol:=MyProtocol{...}
parser:=httpparser.NewHTTPRequestParser(&protocol, httpparser.Settings{})
data:=...// http request taken from any source, with []byte typeiferr:=parser.Feed(data); err!=nil {
// parser isn't able to parse anymorelog.Fatal(err)
}
// that's it! Now everything has been processed with your protocol
}

Parser also can return errors:

  • ErrInvalidMethod
  • ErrInvalidPath
  • ErrProtocolNotSupported
  • ErrInvalidHeader
  • ErrBufferOverflow
  • ErrInvalidContentLength
  • ErrRequestSyntaxError
  • ErrBodyTooBig
  • ErrTooBigChunkSize
  • ErrInvalidChunkSize
  • ErrInvalidChunkSplitter
  • ErrConnectionClosed
  • ErrParserIsDead

Important: this is not a finite list of errors may be returned by parser. In case of errors returned from callbacks, parser will die and return error from callback

Also httpparser.Upgrade struct may be returned as an error. It can be constructed from httpparser.NewUpgrade(string) function

Details about errors you can find in httpparser/errors.go

About

HTTP zero-allocations parser for golang, inspired by llhttp

Topics

Resources

Stars

3 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages