diff options
-rw-r--r-- | .stylelintrc.json | 1 | ||||
-rw-r--r-- | interface/css/codejar-linenumbers.css | 17 | ||||
-rw-r--r-- | interface/css/rspamd.css | 10 | ||||
-rw-r--r-- | interface/index.html | 1 | ||||
-rw-r--r-- | interface/js/app/config.js | 4 | ||||
-rw-r--r-- | interface/js/lib/codejar-linenumbers.min.js | 6 | ||||
-rw-r--r-- | interface/js/lib/codejar.min.js | 4 | ||||
-rw-r--r-- | interface/js/lib/linenumbers.min.js | 5 | ||||
-rw-r--r-- | interface/js/main.js | 2 | ||||
-rw-r--r-- | src/libserver/hyperscan_tools.cxx | 16 | ||||
-rw-r--r-- | src/libserver/hyperscan_tools.h | 11 | ||||
-rw-r--r-- | src/libserver/rspamd_control.c | 65 | ||||
-rw-r--r-- | test/functional/lib/rspamd.robot | 16 |
13 files changed, 104 insertions, 54 deletions
diff --git a/.stylelintrc.json b/.stylelintrc.json index 040ffaa9e..6fd1323b9 100644 --- a/.stylelintrc.json +++ b/.stylelintrc.json @@ -10,6 +10,7 @@ "**/*.min.css", "**/*.js", "interface/css/d3evolution.css", + "interface/css/codejar-linenumbers.css", "interface/css/nprogress.css", "interface/css/prism.css" ], diff --git a/interface/css/codejar-linenumbers.css b/interface/css/codejar-linenumbers.css new file mode 100644 index 000000000..cc19f4117 --- /dev/null +++ b/interface/css/codejar-linenumbers.css @@ -0,0 +1,17 @@ +.codejar-linenumbers-inner-wrap { + position: absolute; + top: 0px; + left: 0px; + bottom: 0px; + overflow: hidden; +} + +.codejar-linenumbers { + mix-blend-mode: initial; + height: 100%; +} + +.codejar-linenumber { + position: relative; + top: 0px; +} diff --git a/interface/css/rspamd.css b/interface/css/rspamd.css index 47062f60d..5ddd4aa9c 100644 --- a/interface/css/rspamd.css +++ b/interface/css/rspamd.css @@ -548,15 +548,15 @@ table#symbolsTable input[type="number"] { /* Fix line wrapping */ scrollbar-width: thin; } +.codejar-linenumbers-inner-wrap { + bottom: unset; +} .codejar-linenumbers { background: rgba(255 255 255 / 0.07) !important; - bottom: unset !important; +} +.codejar-linenumber { color: rgba(120 120 120 / 1) !important; - height: inherit; - mix-blend-mode: unset !important; text-align: right; - overflow: unset !important; - user-select: none; } .editor { font-family: monospace; diff --git a/interface/index.html b/interface/index.html index 993d9e55b..2eddd2a77 100644 --- a/interface/index.html +++ b/interface/index.html @@ -22,6 +22,7 @@ <link rel="stylesheet" type="text/css" href="./css/d3evolution.css"> <link rel="stylesheet" type="text/css" href="./css/d3pie.css"> <link rel="stylesheet" type="text/css" href="./css/nprogress.css"/> + <link rel="stylesheet" type="text/css" href="./css/codejar-linenumbers.css"/> <link rel="stylesheet" type="text/css" href="./css/prism.css"/> <link href="./css/rspamd.css" rel="stylesheet"> </head> diff --git a/interface/js/app/config.js b/interface/js/app/config.js index 8d979f1f2..b3f4e5661 100644 --- a/interface/js/app/config.js +++ b/interface/js/app/config.js @@ -181,7 +181,6 @@ define(["jquery", "codejar", "linenumbers", "prism"], mode = (new Blob([data[0].data]).size > 5120) ? "basic" : $("input[name=editorMode]:checked").val(); $("<" + editor[mode].elt + ' id="editor" class="' + editor[mode].class + '" data-id="' + item.map + '">' + - rspamd.escapeHTML(data[0].data) + "</" + editor[mode].elt + ">").appendTo("#modalBody"); if (editor[mode].codejar) { @@ -189,6 +188,9 @@ define(["jquery", "codejar", "linenumbers", "prism"], document.querySelector("#editor"), withLineNumbers((el) => Prism.highlightElement(el)) ); + jar.updateCode(data[0].data); + } else { + document.querySelector("#editor").innerHTML = rspamd.escapeHTML(data[0].data); } var icon = "fa-edit"; diff --git a/interface/js/lib/codejar-linenumbers.min.js b/interface/js/lib/codejar-linenumbers.min.js new file mode 100644 index 000000000..e3ca168ce --- /dev/null +++ b/interface/js/lib/codejar-linenumbers.min.js @@ -0,0 +1,6 @@ +/*! + * codejar-linenumbers v1.0.0 (https://github.com/julianpoemp/codejar-linenumbers) + * Copyright (c) 2023, Julian Poemp, MIT + */ +function withLineNumbers(r,e={}){const d={class:"codejar-linenumbers",wrapClass:"codejar-wrap",width:"35px",backgroundColor:"rgba(128, 128, 128, 0.15)",color:"",...e};let l;return function(e){r(e),l||(l=init(e,d),e.addEventListener("scroll",()=>l.style.top=`-${e.scrollTop}px`));var t=(e.textContent||"").replace(/\n\n$/g,"\n").split("\n").length;let o="";for(let e=0;e<t;e++)o+=e+1+` +`;l.innerText=o}}function init(e,t){var o=getComputedStyle(e),r=document.createElement("div"),d=(r.className=t.wrapClass,r.style.position="relative",document.createElement("div")),l=(d.className="codejar-linenumbers-inner-wrap",d.style.background=o.background,d.style.marginTop=o.borderTopWidth,d.style.marginBottom=o.borderBottomWidth,d.style.marginLeft=o.borderLeftWidth,d.style.borderTopLeftRadius=o.borderTopLeftRadius,d.style.borderBottomLeftRadius=o.borderBottomLeftRadius,document.createElement("div")),d=(l.className=t.class,d.appendChild(l),r.appendChild(d),l.style.width=t.width,l.style.overflow="hidden",l.style.backgroundColor=t.backgroundColor,l.style.fontFamily=o.fontFamily,l.style.fontSize=o.fontSize,l.style.lineHeight=o.lineHeight,l.style.paddingTop=`calc(${o.paddingTop})`,l.style.paddingLeft=o.paddingLeft,l.style.borderTopLeftRadius=o.borderTopLeftRadius,l.style.borderBottomLeftRadius=o.borderBottomLeftRadius,document.createElement("div"));return d.setAttribute("class","codejar-linenumber"),d.style.color=t.color||o.color,d.style.setProperty("mix-blend-mode","unset"),l.appendChild(d),e.style.paddingLeft=`calc(${t.width} + ${l.style.paddingLeft} + 5px)`,e.style.whiteSpace="pre",e.parentNode.insertBefore(r,e),r.appendChild(e),d}
\ No newline at end of file diff --git a/interface/js/lib/codejar.min.js b/interface/js/lib/codejar.min.js index d2b860deb..6326ea3fe 100644 --- a/interface/js/lib/codejar.min.js +++ b/interface/js/lib/codejar.min.js @@ -1,5 +1,5 @@ /*! - * CodeJar 3.7.0 (https://github.com/antonmedv/codejar) + * CodeJar 4.2.0 (https://github.com/antonmedv/codejar) * Copyright (c) 2020, Anton Medvedev, MIT */ -const globalWindow=window;function CodeJar(u,n,e={}){const f=Object.assign({tab:"\t",indentOn:/[({\[]$/,moveToNewLine:/^[)}\]]/,spellcheck:!1,catchTab:!0,preserveIdent:!0,addClosing:!0,history:!0,window:globalWindow},e),o=f.window,p=o.document;let r=[],h=[],g=-1,i=!1,s,y,v=(u.setAttribute("contenteditable","plaintext-only"),u.setAttribute("spellcheck",f.spellcheck?"true":"false"),u.style.outline="none",u.style.overflowWrap="break-word",u.style.overflowY="auto",!(u.style.whiteSpace="pre-wrap"));n(u),(v="plaintext-only"!==u.contentEditable?!0:v)&&u.setAttribute("contenteditable","true");const t=d(()=>{var e=T();n(u,e),b(e)},30);let C=!1;const N=e=>!O(e)&&!M(e)&&"Meta"!==e.key&&"Control"!==e.key&&"Alt"!==e.key&&!e.key.startsWith("Arrow"),a=d(e=>{N(e)&&(w(),C=!1)},300);e=(e,t)=>{r.push([e,t]),u.addEventListener(e,t)};function T(){var e=H();const t={start:0,end:0,dir:void 0};let{anchorNode:n,anchorOffset:r,focusNode:o,focusOffset:i}=e;if(n&&o)return n===u&&o===u?(t.start=0<r&&u.textContent?u.textContent.length:0,t.end=0<i&&u.textContent?u.textContent.length:0,t.dir=i>=r?"->":"<-"):(n.nodeType===Node.ELEMENT_NODE&&(e=p.createTextNode(""),n.insertBefore(e,n.childNodes[r]),n=e,r=0),o.nodeType===Node.ELEMENT_NODE&&(e=p.createTextNode(""),o.insertBefore(e,o.childNodes[i]),o=e,i=0),l(u,e=>{if(e===n&&e===o)return t.start+=r,t.end+=i,t.dir=r<=i?"->":"<-","stop";if(e===n){if(t.start+=r,t.dir)return"stop";t.dir="->"}else if(e===o){if(t.end+=i,t.dir)return"stop";t.dir="<-"}e.nodeType===Node.TEXT_NODE&&("->"!=t.dir&&(t.start+=e.nodeValue.length),"<-"!=t.dir)&&(t.end+=e.nodeValue.length)}),u.normalize()),t;throw"error1"}function b(n){var e,t,r=H();let o,i=0,s,a=0,d=(n.dir||(n.dir="->"),n.start<0&&(n.start=0),n.end<0&&(n.end=0),"<-"==n.dir&&({start:e,end:t}=n,n.start=t,n.end=e),0);l(u,e=>{var t;if(e.nodeType===Node.TEXT_NODE)return t=(e.nodeValue||"").length,d+t>n.start&&(o||(o=e,i=n.start-d),d+t>n.end)?(s=e,a=n.end-d,"stop"):void(d+=t)}),o||(o=u,i=u.childNodes.length),s||(s=u,a=u.childNodes.length),"<-"==n.dir&&([o,i,s,a]=[s,a,o,i]),r.setBaseAndExtent(o,i,s,a)}function E(){var e=H().getRangeAt(0),t=p.createRange();return t.selectNodeContents(u),t.setEnd(e.startContainer,e.startOffset),t.toString()}function m(){var e=H().getRangeAt(0),t=p.createRange();return t.selectNodeContents(u),t.setStart(e.endContainer,e.endOffset),t.toString()}function k(e){v&&"Enter"===e.key&&(_(e),e.stopPropagation(),""==m()?(S("\n "),(e=T()).start=--e.end,b(e)):S("\n"))}function w(){var e,t,n;i&&(e=u.innerHTML,t=T(),(n=h[g])&&n.html===e&&n.pos.start===t.start&&n.pos.end===t.end||(g++,h[g]={html:e,pos:t},h.splice(g+1),300<g&&(g=300,h.splice(0,1))))}function l(e,t){var n=[];e.firstChild&&n.push(e.firstChild);let r=n.pop();for(;r&&"stop"!==t(r);)r.nextSibling&&n.push(r.nextSibling),r.firstChild&&n.push(r.firstChild),r=n.pop()}function x(e){return e.metaKey||e.ctrlKey}function O(e){return x(e)&&!e.shiftKey&&"Z"===L(e)}function M(e){return x(e)&&e.shiftKey&&"Z"===L(e)}function L(e){e=e.key||e.keyCode||e.which;if(e)return("string"==typeof e?e:String.fromCharCode(e)).toUpperCase()}function S(e){e=e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'"),p.execCommand("insertHTML",!1,e)}function d(t,n){let r=0;return(...e)=>{clearTimeout(r),r=o.setTimeout(()=>t(...e),n)}}function A(e){let t=e.length-1;for(;0<=t&&"\n"!==e[t];)t--;let n=++t;for(;n<e.length&&/[ \t]/.test(e[n]);)n++;return[e.substring(t,n)||"",t,n]}function D(){return u.textContent||""}function _(e){e.preventDefault()}function H(){var e;return((null==(e=u.parentNode)?void 0:e.nodeType)==Node.DOCUMENT_FRAGMENT_NODE?u.parentNode:o).getSelection()}return e("keydown",e=>{if(!e.defaultPrevented){if(y=D(),f.preserveIdent){var t=e;if("Enter"===t.key){var n=E(),r=m(),[o]=A(n);let e=o;f.indentOn.test(n)&&(e+=f.tab),0<e.length?(_(t),t.stopPropagation(),S("\n"+e)):k(t),e!==o&&f.moveToNewLine.test(r)&&(n=T(),S("\n"+o),b(n))}}else k(e);if(f.catchTab){t=e;"Tab"===t.key&&(_(t),t.shiftKey?([t,r]=A(E()),0<t.length&&(o=T(),t=Math.min(f.tab.length,t.length),b({start:r,end:r+t}),p.execCommand("delete"),o.start-=t,o.end-=t,b(o))):S(f.tab))}if(f.addClosing){var i,n=e,s=`([{'"`,a=`)]}'"`,d=m(),l="\\"===(l=E()).substr(l.length-1),d=d.substr(0,1);a.includes(n.key)&&!l&&d===n.key?(i=T(),_(n),i.start=++i.end,b(i)):s.includes(n.key)&&!l&&(`"'`.includes(n.key)||[""," ","\n"].includes(d))&&(_(n),i=T(),l=i.start==i.end?"":H().toString(),S(n.key+l+a[s.indexOf(n.key)]),i.start++,i.end++,b(i))}var c;f.history&&(O(d=e)&&(_(d),g--,(c=h[g])&&(u.innerHTML=c.html,b(c.pos)),g<0)&&(g=0),M(d)&&(_(d),g++,(c=h[g])&&(u.innerHTML=c.html,b(c.pos)),g>=h.length)&&g--,N(e))&&!C&&(w(),C=!0),v&&(!x(l=e)||"C"!==L(l))&&b(T())}}),e("keyup",e=>{e.defaultPrevented||e.isComposing||(y!==D()&&t(),a(e),s&&s(D()))}),e("focus",e=>{i=!0}),e("blur",e=>{i=!1}),e("paste",e=>{var t;w(),_(e=e),e=(e.originalEvent||e).clipboardData.getData("text/plain").replace(/\r/g,""),t=T(),S(e),n(u),b({start:Math.min(t.start,t.end)+e.length,end:Math.min(t.start,t.end)+e.length,dir:"<-"}),w(),s&&s(D())}),{updateOptions(e){Object.assign(f,e)},updateCode(e){u.textContent=e,n(u)},onUpdate(e){s=e},toString:D,save:T,restore:b,recordHistory:w,destroy(){for(var[e,t]of r)u.removeEventListener(e,t)}}}
\ No newline at end of file +const globalWindow=window;function CodeJar(l,n,e={}){const c={tab:"\t",indentOn:/[({\[]$/,moveToNewLine:/^[)}\]]/,spellcheck:!1,catchTab:!0,preserveIdent:!0,addClosing:!0,history:!0,window:globalWindow,...e},o=c.window,f=o.document,r=[],u=[];let p=-1,a=!1,i=()=>{},h;l.setAttribute("contenteditable","plaintext-only"),l.setAttribute("spellcheck",c.spellcheck?"true":"false"),l.style.outline="none",l.style.overflowWrap="break-word",l.style.overflowY="auto",l.style.whiteSpace="pre-wrap";const d=(e,t)=>{n(e,t)};let g=!1;(g="plaintext-only"!==l.contentEditable?!0:g)&&l.setAttribute("contenteditable","true");const t=S(()=>{var e=v();d(l,e),T(e)},30);let y=!1;const N=e=>!O(e)&&!M(e)&&"Meta"!==e.key&&"Control"!==e.key&&"Alt"!==e.key&&!e.key.startsWith("Arrow"),s=S(e=>{N(e)&&(x(),y=!1)},300);e=(e,t)=>{r.push([e,t]),l.addEventListener(e,t)};function v(){var e=H();const t={start:0,end:0,dir:void 0};let{anchorNode:n,anchorOffset:r,focusNode:o,focusOffset:a}=e;if(n&&o)return n===l&&o===l?(t.start=0<r&&l.textContent?l.textContent.length:0,t.end=0<a&&l.textContent?l.textContent.length:0,t.dir=a>=r?"->":"<-"):(n.nodeType===Node.ELEMENT_NODE&&(e=f.createTextNode(""),n.insertBefore(e,n.childNodes[r]),n=e,r=0),o.nodeType===Node.ELEMENT_NODE&&(e=f.createTextNode(""),o.insertBefore(e,o.childNodes[a]),o=e,a=0),w(l,e=>{if(e===n&&e===o)return t.start+=r,t.end+=a,t.dir=r<=a?"->":"<-","stop";if(e===n){if(t.start+=r,t.dir)return"stop";t.dir="->"}else if(e===o){if(t.end+=a,t.dir)return"stop";t.dir="<-"}e.nodeType===Node.TEXT_NODE&&("->"!=t.dir&&(t.start+=e.nodeValue.length),"<-"!=t.dir)&&(t.end+=e.nodeValue.length)}),l.normalize()),t;throw"error1"}function T(n){var e=H();let r,o=0,a,i=0,d=(n.dir||(n.dir="->"),n.start<0&&(n.start=0),n.end<0&&(n.end=0),"<-"==n.dir&&({start:t,end:s}=n,n.start=s,n.end=t),0);w(l,e=>{var t;if(e.nodeType===Node.TEXT_NODE)return t=(e.nodeValue||"").length,d+t>n.start&&(r||(r=e,o=n.start-d),d+t>n.end)?(a=e,i=n.end-d,"stop"):void(d+=t)}),r||(r=l,o=l.childNodes.length),a||(a=l,i=l.childNodes.length),"<-"==n.dir&&([r,o,a,i]=[a,i,r,o]);var t,s=C(r),s=(s&&(t=f.createTextNode(""),s.parentNode?.insertBefore(t,s),r=t,o=0),C(a));s&&(t=f.createTextNode(""),s.parentNode?.insertBefore(t,s),a=t,i=0),e.setBaseAndExtent(r,o,a,i),l.normalize()}function C(e){for(;e&&e!==l;){if(e.nodeType===Node.ELEMENT_NODE){var t=e;if("false"==t.getAttribute("contenteditable"))return t}e=e.parentNode}}function E(){var e=H().getRangeAt(0),t=f.createRange();return t.selectNodeContents(l),t.setEnd(e.startContainer,e.startOffset),t.toString()}function m(){var e=H().getRangeAt(0),t=f.createRange();return t.selectNodeContents(l),t.setStart(e.endContainer,e.endOffset),t.toString()}function b(e){g&&"Enter"===e.key&&(B(e),e.stopPropagation(),""==m()?(L("\n "),(e=v()).start=--e.end,T(e)):L("\n"))}function x(){var e,t,n;a&&(e=l.innerHTML,t=v(),(n=u[p])&&n.html===e&&n.pos.start===t.start&&n.pos.end===t.end||(p++,u[p]={html:e,pos:t},u.splice(p+1),300<p&&(p=300,u.splice(0,1))))}function w(e,t){var n=[];e.firstChild&&n.push(e.firstChild);let r=n.pop();for(;r&&"stop"!==t(r);)r.nextSibling&&n.push(r.nextSibling),r.firstChild&&n.push(r.firstChild),r=n.pop()}function k(e){return e.metaKey||e.ctrlKey}function O(e){return k(e)&&!e.shiftKey&&"Z"===D(e)}function M(e){return k(e)&&e.shiftKey&&"Z"===D(e)}function D(e){e=e.key||e.keyCode||e.which;if(e)return("string"==typeof e?e:String.fromCharCode(e)).toUpperCase()}function L(e){e=e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'"),f.execCommand("insertHTML",!1,e)}function S(t,n){let r=0;return(...e)=>{clearTimeout(r),r=o.setTimeout(()=>t(...e),n)}}function A(e){let t=e.length-1;for(;0<=t&&"\n"!==e[t];)t--;let n=++t;for(;n<e.length&&/[ \t]/.test(e[n]);)n++;return[e.substring(t,n)||"",t,n]}function _(){return l.textContent||""}function B(e){e.preventDefault()}function H(){return(l.parentNode?.nodeType==Node.DOCUMENT_FRAGMENT_NODE?l.parentNode:o).getSelection()}return e("keydown",e=>{if(!e.defaultPrevented){if(h=_(),c.preserveIdent){var t=e;if("Enter"===t.key){var n=E(),r=m(),[o]=A(n);let e=o;c.indentOn.test(n)&&(e+=c.tab),0<e.length?(B(t),t.stopPropagation(),L("\n"+e)):b(t),e!==o&&c.moveToNewLine.test(r)&&(n=v(),L("\n"+o),T(n))}}else b(e);if(c.catchTab){t=e;"Tab"===t.key&&(B(t),t.shiftKey?([t,r]=A(E()),0<t.length&&(o=v(),t=Math.min(c.tab.length,t.length),T({start:r,end:r+t}),f.execCommand("delete"),o.start-=t,o.end-=t,T(o))):L(c.tab))}if(c.addClosing){var a,n=e,i=`([{'"`;i.includes(n.key)&&(B(n),a=v(),d=a.start==a.end?"":H().toString(),L(n.key+d+`)]}'"`[i.indexOf(n.key)]),a.start++,a.end++,T(a))}var d,s;c.history&&(O(d=e)&&(B(d),p--,(s=u[p])&&(l.innerHTML=s.html,T(s.pos)),p<0)&&(p=0),M(d)&&(B(d),p++,(s=u[p])&&(l.innerHTML=s.html,T(s.pos)),p>=u.length)&&p--,N(e))&&!y&&(x(),y=!0),g&&(!k(i=e)||"C"!==D(i))&&T(v())}}),e("keyup",e=>{e.defaultPrevented||e.isComposing||(h!==_()&&t(),s(e),i(_()))}),e("focus",e=>{a=!0}),e("blur",e=>{a=!1}),e("paste",e=>{var t;x(),(e=e).defaultPrevented||(B(e),e=(e.originalEvent??e).clipboardData.getData("text/plain").replace(/\r\n?/g,"\n"),t=v(),L(e),d(l),T({start:Math.min(t.start,t.end)+e.length,end:Math.min(t.start,t.end)+e.length,dir:"<-"})),x(),i(_())}),e("cut",e=>{var t,n;x(),e=e,t=v(),n=H(),(e.originalEvent??e).clipboardData.setData("text/plain",n.toString()),f.execCommand("delete"),d(l),T({start:Math.min(t.start,t.end),end:Math.min(t.start,t.end),dir:"<-"}),B(e),x(),i(_())}),{updateOptions(e){Object.assign(c,e)},updateCode(e){l.textContent=e,d(l),i(e)},onUpdate(e){i=e},toString:_,save:v,restore:T,recordHistory:x,destroy(){for(var[e,t]of r)l.removeEventListener(e,t)}}}
\ No newline at end of file diff --git a/interface/js/lib/linenumbers.min.js b/interface/js/lib/linenumbers.min.js deleted file mode 100644 index 0dd83d0d0..000000000 --- a/interface/js/lib/linenumbers.min.js +++ /dev/null @@ -1,5 +0,0 @@ -/*! - * CodeJar 3.2.2 helper: lineNumbers (https://github.com/antonmedv/codejar) - * Copyright (c) 2020, Anton Medvedev, MIT - */ -function withLineNumbers(e,t={}){const o=Object.assign({class:"codejar-linenumbers",wrapClass:"codejar-wrap",width:"35px",backgroundColor:"rgba(128, 128, 128, 0.15)",color:""},t);let l;return function(t){e(t),l||(l=init(t,o),t.addEventListener("scroll",()=>l.style.top=`-${t.scrollTop}px`));const n=(t.textContent||"").replace(/\n+$/,"\n").split("\n").length+1;let s="";for(let e=1;e<n;e++)s+=`${e}\n`;l.innerText=s}}function init(e,t){const o=getComputedStyle(e),l=document.createElement("div");l.className=t.wrapClass,l.style.position="relative";const n=document.createElement("div");n.className=t.class,l.appendChild(n),n.style.position="absolute",n.style.top="0px",n.style.left="0px",n.style.bottom="0px",n.style.width=t.width,n.style.overflow="hidden",n.style.backgroundColor=t.backgroundColor,n.style.color=t.color||o.color,n.style.setProperty("mix-blend-mode","difference"),n.style.fontFamily=o.fontFamily,n.style.fontSize=o.fontSize,n.style.lineHeight=o.lineHeight,n.style.paddingTop=o.paddingTop,n.style.paddingLeft=o.paddingLeft,n.style.borderTopLeftRadius=o.borderTopLeftRadius,n.style.borderBottomLeftRadius=o.borderBottomLeftRadius;const s=document.createElement("div");return s.style.position="relative",s.style.top="0px",n.appendChild(s),e.style.paddingLeft=`calc(${t.width} + ${n.style.paddingLeft})`,e.style.whiteSpace="pre",e.parentNode.insertBefore(l,e),l.appendChild(e),s}
\ No newline at end of file diff --git a/interface/js/main.js b/interface/js/main.js index d0e904f37..4182bb2bc 100644 --- a/interface/js/main.js +++ b/interface/js/main.js @@ -14,7 +14,7 @@ requirejs.config({ fontawesome: "fontawesome.min", fontawesome_solid: "solid.min", footable: "footable.min", - linenumbers: "linenumbers.min", + linenumbers: "codejar-linenumbers.min", nprogress: "nprogress.min", prism: "prism", stickytabs: "jquery.stickytabs.min" diff --git a/src/libserver/hyperscan_tools.cxx b/src/libserver/hyperscan_tools.cxx index 4bcc68e4a..3fce3ce26 100644 --- a/src/libserver/hyperscan_tools.cxx +++ b/src/libserver/hyperscan_tools.cxx @@ -94,6 +94,7 @@ private: ankerl::svector<std::string, 4> cache_dirs; ankerl::svector<std::string, 8> cache_extensions; ankerl::unordered_dense::set<std::string> known_cached_files; + bool loaded = false; private: hs_known_files_cache() = default; @@ -203,7 +204,7 @@ public: { auto env_cleanup_disable = std::getenv("RSPAMD_NO_CLEANUP"); /* We clean dir merely if we are running from the main process */ - if (rspamd_current_worker == nullptr && env_cleanup_disable == nullptr) { + if (rspamd_current_worker == nullptr && env_cleanup_disable == nullptr && loaded) { const auto *log_func = RSPAMD_LOG_FUNC; auto cleanup_dir = [&](std::string_view dir) -> void { for (const auto &ext: cache_extensions) { @@ -259,6 +260,14 @@ public: else if (rspamd_current_worker == nullptr && env_cleanup_disable != nullptr) { msg_debug_hyperscan("disable hyperscan cleanup: env variable RSPAMD_NO_CLEANUP is set"); } + else if (!loaded) { + msg_debug_hyperscan("disable hyperscan cleanup: not loaded"); + } + } + + auto notice_loaded() -> void + { + loaded = true; } }; @@ -601,4 +610,9 @@ void rspamd_hyperscan_cleanup_maybe(void) rspamd::util::hs_known_files_cache::get().cleanup_maybe(); } +void rspamd_hyperscan_notice_loaded(void) +{ + rspamd::util::hs_known_files_cache::get().notice_loaded(); +} + #endif// WITH_HYPERSCAN
\ No newline at end of file diff --git a/src/libserver/hyperscan_tools.h b/src/libserver/hyperscan_tools.h index c8dd490ab..624b7b069 100644 --- a/src/libserver/hyperscan_tools.h +++ b/src/libserver/hyperscan_tools.h @@ -1,11 +1,11 @@ -/*- - * Copyright 2022 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -61,6 +61,11 @@ void rspamd_hyperscan_free(rspamd_hyperscan_t *db, bool invalid); void rspamd_hyperscan_notice_known(const char *fname); /** + * Notice that hyperscan files are all loaded (e.g. in the main process), so we can cleanup old files on termination + */ +void rspamd_hyperscan_notice_loaded(void); + +/** * Cleans up old files. This method should be called on config free (in the main process) */ void rspamd_hyperscan_cleanup_maybe(void); diff --git a/src/libserver/rspamd_control.c b/src/libserver/rspamd_control.c index 9ed78a316..986a4a2ea 100644 --- a/src/libserver/rspamd_control.c +++ b/src/libserver/rspamd_control.c @@ -1,11 +1,11 @@ -/*- - * Copyright 2016 Vsevolod Stakhov +/* + * Copyright 2023 Vsevolod Stakhov * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -838,7 +838,7 @@ rspamd_srv_handler(EV_P_ ev_io *w, int revents) { struct rspamd_worker *worker; static struct rspamd_srv_command cmd; - struct rspamd_main *srv; + struct rspamd_main *rspamd_main; struct rspamd_srv_reply_data *rdata; struct msghdr msg; struct cmsghdr *cmsg; @@ -851,7 +851,7 @@ rspamd_srv_handler(EV_P_ ev_io *w, int revents) if (revents == EV_READ) { worker = (struct rspamd_worker *) w->data; - srv = worker->srv; + rspamd_main = worker->srv; iov.iov_base = &cmd; iov.iov_len = sizeof(cmd); memset(&msg, 0, sizeof(msg)); @@ -864,8 +864,8 @@ rspamd_srv_handler(EV_P_ ev_io *w, int revents) if (r == -1) { if (errno != EAGAIN) { - msg_err("cannot read from worker's srv pipe: %s", - strerror(errno)); + msg_err_main("cannot read from worker's srv pipe: %s", + strerror(errno)); } else { return; @@ -876,18 +876,18 @@ rspamd_srv_handler(EV_P_ ev_io *w, int revents) * Usually this means that a worker is dead, so do not try to read * anything */ - msg_err("cannot read from worker's srv pipe connection closed; command = %s", - rspamd_srv_command_to_string(cmd.type)); + msg_err_main("cannot read from worker's srv pipe connection closed; command = %s", + rspamd_srv_command_to_string(cmd.type)); ev_io_stop(EV_A_ w); } else if (r != sizeof(cmd)) { - msg_err("cannot read from worker's srv pipe incomplete command: %d != %d; command = %s", - (gint) r, (gint) sizeof(cmd), rspamd_srv_command_to_string(cmd.type)); + msg_err_main("cannot read from worker's srv pipe incomplete command: %d != %d; command = %s", + (gint) r, (gint) sizeof(cmd), rspamd_srv_command_to_string(cmd.type)); } else { rdata = g_malloc0(sizeof(*rdata)); rdata->worker = worker; - rdata->srv = srv; + rdata->srv = rspamd_main; rdata->rep.id = cmd.id; rdata->rep.type = cmd.type; rdata->fd = -1; @@ -899,19 +899,19 @@ rspamd_srv_handler(EV_P_ ev_io *w, int revents) switch (cmd.type) { case RSPAMD_SRV_SOCKETPAIR: - spair = g_hash_table_lookup(srv->spairs, cmd.cmd.spair.pair_id); + spair = g_hash_table_lookup(rspamd_main->spairs, cmd.cmd.spair.pair_id); if (spair == NULL) { spair = g_malloc(sizeof(gint) * 2); if (rspamd_socketpair(spair, cmd.cmd.spair.af) == -1) { rdata->rep.reply.spair.code = errno; - msg_err("cannot create socket pair: %s", strerror(errno)); + msg_err_main("cannot create socket pair: %s", strerror(errno)); } else { nid = g_malloc(sizeof(cmd.cmd.spair.pair_id)); memcpy(nid, cmd.cmd.spair.pair_id, sizeof(cmd.cmd.spair.pair_id)); - g_hash_table_insert(srv->spairs, nid, spair); + g_hash_table_insert(rspamd_main->spairs, nid, spair); rdata->rep.reply.spair.code = 0; rdata->fd = cmd.cmd.spair.pair_num ? spair[1] : spair[0]; } @@ -923,14 +923,19 @@ rspamd_srv_handler(EV_P_ ev_io *w, int revents) break; case RSPAMD_SRV_HYPERSCAN_LOADED: /* Load RE cache to provide it for new forks */ - if (rspamd_re_cache_is_hs_loaded(srv->cfg->re_cache) != RSPAMD_HYPERSCAN_LOADED_FULL || + if (rspamd_re_cache_is_hs_loaded(rspamd_main->cfg->re_cache) != RSPAMD_HYPERSCAN_LOADED_FULL || cmd.cmd.hs_loaded.forced) { rspamd_re_cache_load_hyperscan( - srv->cfg->re_cache, + rspamd_main->cfg->re_cache, cmd.cmd.hs_loaded.cache_dir, false); } + /* After getting this notice, we can clean up old hyperscan files */ + rspamd_hyperscan_notice_loaded(); + msg_info_main("received hyperscan cache loaded from %s", + cmd.cmd.hs_loaded.cache_dir); + /* Broadcast command to all workers */ memset(&wcmd, 0, sizeof(wcmd)); wcmd.type = RSPAMD_CONTROL_HYPERSCAN_LOADED; @@ -938,7 +943,7 @@ rspamd_srv_handler(EV_P_ ev_io *w, int revents) cmd.cmd.hs_loaded.cache_dir, sizeof(wcmd.cmd.hs_loaded.cache_dir)); wcmd.cmd.hs_loaded.forced = cmd.cmd.hs_loaded.forced; - rspamd_control_broadcast_cmd(srv, &wcmd, rfd, + rspamd_control_broadcast_cmd(rspamd_main, &wcmd, rfd, rspamd_control_ignore_io_handler, NULL, worker->pid); break; case RSPAMD_SRV_MONITORED_CHANGE: @@ -950,26 +955,26 @@ rspamd_srv_handler(EV_P_ ev_io *w, int revents) sizeof(wcmd.cmd.monitored_change.tag)); wcmd.cmd.monitored_change.alive = cmd.cmd.monitored_change.alive; wcmd.cmd.monitored_change.sender = cmd.cmd.monitored_change.sender; - rspamd_control_broadcast_cmd(srv, &wcmd, rfd, + rspamd_control_broadcast_cmd(rspamd_main, &wcmd, rfd, rspamd_control_ignore_io_handler, NULL, 0); break; case RSPAMD_SRV_LOG_PIPE: memset(&wcmd, 0, sizeof(wcmd)); wcmd.type = RSPAMD_CONTROL_LOG_PIPE; wcmd.cmd.log_pipe.type = cmd.cmd.log_pipe.type; - rspamd_control_broadcast_cmd(srv, &wcmd, rfd, + rspamd_control_broadcast_cmd(rspamd_main, &wcmd, rfd, rspamd_control_log_pipe_io_handler, NULL, 0); break; case RSPAMD_SRV_ON_FORK: rdata->rep.reply.on_fork.status = 0; - rspamd_control_handle_on_fork(&cmd, srv); + rspamd_control_handle_on_fork(&cmd, rspamd_main); break; case RSPAMD_SRV_HEARTBEAT: worker->hb.last_event = ev_time(); rdata->rep.reply.heartbeat.status = 0; break; case RSPAMD_SRV_HEALTH: - rspamd_fill_health_reply(srv, &rdata->rep); + rspamd_fill_health_reply(rspamd_main, &rdata->rep); break; case RSPAMD_SRV_NOTICE_HYPERSCAN_CACHE: #ifdef WITH_HYPERSCAN @@ -984,11 +989,11 @@ rspamd_srv_handler(EV_P_ ev_io *w, int revents) /* Ensure that memcpy is safe */ G_STATIC_ASSERT(sizeof(wcmd.cmd.fuzzy_blocked) == sizeof(cmd.cmd.fuzzy_blocked)); memcpy(&wcmd.cmd.fuzzy_blocked, &cmd.cmd.fuzzy_blocked, sizeof(wcmd.cmd.fuzzy_blocked)); - rspamd_control_broadcast_cmd(srv, &wcmd, rfd, + rspamd_control_broadcast_cmd(rspamd_main, &wcmd, rfd, rspamd_control_ignore_io_handler, NULL, worker->pid); break; default: - msg_err("unknown command type: %d", cmd.type); + msg_err_main("unknown command type: %d", cmd.type); break; } @@ -1008,7 +1013,7 @@ rspamd_srv_handler(EV_P_ ev_io *w, int revents) rdata = (struct rspamd_srv_reply_data *) w->data; worker = rdata->worker; worker->tmp_data = NULL; /* Avoid race */ - srv = rdata->srv; + rspamd_main = rdata->srv; memset(&msg, 0, sizeof(msg)); @@ -1032,13 +1037,13 @@ rspamd_srv_handler(EV_P_ ev_io *w, int revents) r = sendmsg(w->fd, &msg, 0); if (r == -1) { - msg_err("cannot write to worker's srv pipe when writing reply: %s; command = %s", - strerror(errno), rspamd_srv_command_to_string(rdata->rep.type)); + msg_err_main("cannot write to worker's srv pipe when writing reply: %s; command = %s", + strerror(errno), rspamd_srv_command_to_string(rdata->rep.type)); } else if (r != sizeof(rdata->rep)) { - msg_err("cannot write to worker's srv pipe: %d != %d; command = %s", - (int) r, (int) sizeof(rdata->rep), - rspamd_srv_command_to_string(rdata->rep.type)); + msg_err_main("cannot write to worker's srv pipe: %d != %d; command = %s", + (int) r, (int) sizeof(rdata->rep), + rspamd_srv_command_to_string(rdata->rep.type)); } g_free(rdata); diff --git a/test/functional/lib/rspamd.robot b/test/functional/lib/rspamd.robot index 27dad96ee..696b5f97d 100644 --- a/test/functional/lib/rspamd.robot +++ b/test/functional/lib/rspamd.robot @@ -163,16 +163,20 @@ Export Rspamd Variables To Environment Export Scoped Variables [Arguments] ${scope} &{vars} - FOR ${k} ${v} IN &{vars} - IF '${scope}' == 'Test' + IF '${scope}' == 'Test' + FOR ${k} ${v} IN &{vars} Set Test Variable ${${k}} ${v} - ELSE IF '${scope}' == 'Suite' + END + ELSE IF '${scope}' == 'Suite' + FOR ${k} ${v} IN &{vars} Set Suite Variable ${${k}} ${v} - ELSE IF '${scope}' == 'Global' + END + ELSE IF '${scope}' == 'Global' + FOR ${k} ${v} IN &{vars} Set Global Variable ${${k}} ${v} - ELSE - Fail message="Don't know what to do with scope: ${scope}" END + ELSE + Fail message="Don't know what to do with scope: ${scope}" END Log does not contain segfault record |