<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="/rss.xsl.xml"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/">
<channel>
    <title>Changes in GfmLink.php</title>
    <description></description>
    <language>en</language>
    <copyright>Copyright 2025</copyright>
    <generator>Java</generator><item>
        <title>b22130d2b9e76b1247849cd618b2bcf664ee020f - fix(parser): stop group-quantifier body patterns from exhausting memory</title>
        <link>http://127.0.0.1:8080/history/dokuwiki/inc/Parsing/ParserMode/GfmLink.php#b22130d2b9e76b1247849cd618b2bcf664ee020f</link>
        <description>fix(parser): stop group-quantifier body patterns from exhausting memorySeveral patterns repeat a group &#8212; (?:&#8230;)* / (?:&#8230;)+ &#8212; over a body that canspan a large region. On the non-JIT PCRE engine each iteration of agroup repetition keeps its own backtracking frame, so a big body retainsone frame per byte: a linear, unbounded memory spike that can fatal arequest (and, with JIT on, trips pcre.jit_stacklimit so the lexer dumpsthe rest of the document as literal text). A repetition over a singleitem (.* , [^x]+) is optimized by PCRE and unaffected.Make each body possessive: the repeated group cannot match the delimiterthat follows it, so it always stops at the first closer and never needsto backtrack.- media {{&#8230;}}, windowssharelink, gfm_quote, gfm_link: possessive body.- email validation (used by emaillink and mail_isvalid): possessive  local-part and domain groups; a long dotted `a.a.a&#8230;` local part or  domain was a ReDoS vector. Match results are unchanged.

            List of files:
            /dokuwiki/inc/Parsing/ParserMode/GfmLink.php</description>
        <pubDate>Wed, 08 Jul 2026 17:43:28 +0000</pubDate>
        <dc:creator>Andreas Gohr &lt;gohr@cosmocode.de&gt;</dc:creator>
    </item>
<item>
        <title>1c00c02121477c81b95fe750b94acdf109cba20a - fix(parser): validate inline formatting closers with a single memoized scan</title>
        <link>http://127.0.0.1:8080/history/dokuwiki/inc/Parsing/ParserMode/GfmLink.php#1c00c02121477c81b95fe750b94acdf109cba20a</link>
        <description>fix(parser): validate inline formatting closers with a single memoized scanThe inline formatting modes only open a span when a valid closer existsahead. That check was a lookahead built on CONTENT_UNTIL_PARA, testedcharacter by character up to the next paragraph break and re-evaluatedfrom scratch for every opener candidate &#8212; openers times paragraphlength. With pcre.jit=0 a crafted 32KB page took 16s and an ordinary34KB page with long paragraphs 37s; with the JIT on (the PHP default)the per-character lookahead exhausted the JIT stack, the match silentlyfailed, and the formatting &#8212; or everything after it &#8212; rendered as plaintext.The check also decided the wrong thing. It scanned raw text, so a closerlookalike inside content the lexer consumes atomically &#8212; a nowiki or %%span, a backtick code span, a link, a URL &#8212; counted as a real closereven though the mode&apos;s exit pattern can never fire there. And it ignoredthe enclosing span: an inner delimiter whose only closer lay past thecloser of the mode it sits in was entered anyway, so a stray delimiterpaired with one in a following sibling span and dragged the boundaryalong &#8212; the `*` in &apos;&apos;glob/*.conf&apos;&apos; joined the `*` of the next &apos;&apos;...&apos;&apos;span and corrupted the paragraph; the same held for //, ** and __ insidemonospace, and an emphasis opened inside ((...)) ran past the footnote&apos;s)) and the enclosing bold&apos;s **.Each formatting mode now declares its closer throughLexer::addCloserPattern(), mirroring addExitPattern(), and the lexeranswers &quot;does a valid closer exist ahead&quot; with one anchored possessivescan per range instead of a lookahead per opener:- The scan runs left to right from the opener, hopping over opaque spans  derived from already-registered patterns &#8212; a plain or special match is  consumed in one step, an entry into a verbatim mode (nowiki, the  backtick code spans) extends to that mode&apos;s first exit &#8212; so a closer  lookalike inside consumed content is never mistaken for a closer. Each  hop finds the earliest of boundary, closer, or opaque span in a single  leftmost search, keeping the check linear.- An opener is rejected when the nearest enclosing mode that has a closer  of its own would close before the opener&apos;s own closer, so a delimiter  that can never close within its span stays literal. That ancestor is  found by walking the mode stack past modes that declare no closer  (plugins, footnotes); the nearest guarded ancestor suffices, as it was  itself validated against its own when it opened.- Both verdicts are memoized and reset per parse() run: a proven closer  validates every earlier candidate, and a proven closer-free range  rejects every later candidate before the next boundary. With the lexer  consuming each opened span, the whole parse is linear in document size.Closer patterns match the closing delimiter itself with flanking contextin lookarounds &#8212; the convention exit patterns already follow &#8212; so closerpositions compare exactly across modes and a closer directly after aninner opener is seen. AbstractFormatting derives the closer from the exitpattern and registers it with the paragraph break as the boundary,preserving the rule that formatting never spans paragraphs; a mode withother needs can pass a different boundary or none.Footnote declares its )) as a closer rather than guarding its (( entrywith a (?=.*)) lookahead, so the footnote becomes a boundary the scansees and formatting inside it no longer pairs across the )); its closertakes no paragraph boundary, as footnotes are block-level. GfmEmphasisgains a closer pattern so single * emphasis is validated the same way,while its entry lookahead still enforces CommonMark nearest-delimiterpairing. GfmEmphasis and GfmStrong span bodies cannot contain theirdelimiter, so their in-pattern lookaheads stay linear on their own; theGFM backtick span bodies get deterministic alternatives with possessivequantifiers, removing their per-character backtracking.CONTENT_UNTIL_PARA is removed: any entry pattern built with it recreatesthe quadratic scan. ParallelRegex gains escapePattern() so embeddedcloser fragments follow the lexer&apos;s bare-parenthesis convention, reportsPREG_JIT_STACKLIMIT_ERROR so a future JIT exhaustion surfaces instead ofsilently truncating, and no longer rewrites its registered patterns inplace while compiling the compound regex.The adversarial 32KB page drops to 0.1s, the 37-second benign page to0.1s, and a 128KB variant stays under 0.6s.

            List of files:
            /dokuwiki/inc/Parsing/ParserMode/GfmLink.php</description>
        <pubDate>Thu, 09 Jul 2026 12:09:52 +0000</pubDate>
        <dc:creator>Andreas Gohr &lt;gohr@cosmocode.de&gt;</dc:creator>
    </item>
<item>
        <title>4f32c45be746b2e49db6bcc6cc733a89bbd14d81 - GfmLink: allow soft line break inside link text</title>
        <link>http://127.0.0.1:8080/history/dokuwiki/inc/Parsing/ParserMode/GfmLink.php#4f32c45be746b2e49db6bcc6cc733a89bbd14d81</link>
        <description>GfmLink: allow soft line break inside link textThe label character class explicitly forbade `\n`, so a CommonMarksoft line break inside link text (e.g. `[link with&lt;EOL&gt;more](url)`)fell through to literal text instead of producing a link. Loosen theclass to accept a bare `\n` as long as it is not followed by a blankline &#8212; soft breaks are spec-allowed inside link text, blank lines arenot, and refusing them also keeps `\n#`-anchored block modes (header,hr, ...) from being swallowed by a runaway link match.The `\n` survives into the label string and renders as a literal lineending in HTML, which browsers display as a single space. This softbreak behavior has been checked againsthttps://spec.commonmark.org/dingus/Note that this behavior differs from github where the line break isrendered as a hard break &lt;br&gt;.

            List of files:
            /dokuwiki/inc/Parsing/ParserMode/GfmLink.php</description>
        <pubDate>Tue, 26 May 2026 20:05:54 +0000</pubDate>
        <dc:creator>Andreas Gohr &lt;gohr@cosmocode.de&gt;</dc:creator>
    </item>
<item>
        <title>0f694376a45b6a9e3a163cf19dccda0c2dc008f0 - GfmLink: accept escaped brackets inside link labels</title>
        <link>http://127.0.0.1:8080/history/dokuwiki/inc/Parsing/ParserMode/GfmLink.php#0f694376a45b6a9e3a163cf19dccda0c2dc008f0</link>
        <description>GfmLink: accept escaped brackets inside link labelsThe label slot used `[^\[\]\n]+`, which rejected `\[` / `\]` andleft labels with escaped brackets unmatched. Promote it to`(?:\\.|[^\[\]\n])+` &#8212; the same backslash-escape trick the URLslot already uses &#8212; so spec example 523 (`[link \[bar](/uri)`)matches and unescapes cleanly. The image-as-label sub-patterngets the same upgrade.handle() needs no change: the new class still rejects bare `]`,so the first literal `](` in the match is still the separator;Escape::unescapeBackslashes() was already collapsing `\[` to `[`before the label reached the link handler.Adds two GfmLinkTest cases for the `\[` / `\]` forms.

            List of files:
            /dokuwiki/inc/Parsing/ParserMode/GfmLink.php</description>
        <pubDate>Tue, 05 May 2026 20:04:32 +0000</pubDate>
        <dc:creator>Andreas Gohr &lt;gohr@cosmocode.de&gt;</dc:creator>
    </item>
<item>
        <title>eb15e634e1400f6c4d78f5fb40179ca25f41574d - extract Helpers\HtmlEntity, wire into GfmCode and GfmLink URL slot</title>
        <link>http://127.0.0.1:8080/history/dokuwiki/inc/Parsing/ParserMode/GfmLink.php#eb15e634e1400f6c4d78f5fb40179ca25f41574d</link>
        <description>extract Helpers\HtmlEntity, wire into GfmCode and GfmLink URL slotNumeric and named HTML entity decoding moves out of GfmHtmlEntity intoa pure helper, so capture-by-regex modes can apply the same decodepost-extraction (the inline lexer never reaches their bodies). Mirrorsthe Helpers\Escape pattern.Wired up in two slots:  - GfmCode info string: f&amp;ouml;&amp;ouml; now decodes to f&#246;&#246; in the    language class. Clears spec example #330.  - GfmLink URL: GfmLink::extractUrl() decodes entities. URL pattern    extends from `[^)\n]+` to `(?:\\.|[^)\n])+` so an escaped \) no    longer terminates the URL early; the existing post-classify    Escape::unescapeBackslashes call strips the backslashes after    Link::classify has done its work. Clears #504, #506, #508.Skip #328 with a self-contained title-slot reason: the URL side nowdecodes correctly, but the title attribute is still discarded(DokuWiki link instructions have no title slot).

            List of files:
            /dokuwiki/inc/Parsing/ParserMode/GfmLink.php</description>
        <pubDate>Mon, 04 May 2026 13:00:28 +0000</pubDate>
        <dc:creator>Andreas Gohr &lt;andi@splitbrain.org&gt;</dc:creator>
    </item>
<item>
        <title>74031e463764923581b9204cebc0fc3f34ce881f - add GfmEscape for GFM backslash escapes</title>
        <link>http://127.0.0.1:8080/history/dokuwiki/inc/Parsing/ParserMode/GfmLink.php#74031e463764923581b9204cebc0fc3f34ce881f</link>
        <description>add GfmEscape for GFM backslash escapesImplements GFM &#167;6.1 backslash-escape handling. GfmEscape is a sort-5inline mode in CATEGORY_SUBSTITION that claims `\X` for any escapableASCII punctuation char before competing delimiters can match. Theshared character class lives on Helpers\Escape so the lexer patternand the post-hoc unescape stay in lockstep.Whole-span captures (GfmCode info string, GfmLink label/URL) bypassthe lexer; those modes call Escape::unescapeBackslashes() on therelevant slot. GfmLink skips the unescape when the URL classifies asa windowssharelink so the leading \\host survives intact.GfmTable cells get a separate per-cell `\|` to `|` pass in therewriter to honour the tables-extension rule that pipes alwaysunescape, even inside code spans where standard &#167;6.1 escapes don&apos;tfire.

            List of files:
            /dokuwiki/inc/Parsing/ParserMode/GfmLink.php</description>
        <pubDate>Tue, 28 Apr 2026 17:08:30 +0000</pubDate>
        <dc:creator>Andreas Gohr &lt;andi@splitbrain.org&gt;</dc:creator>
    </item>
<item>
        <title>1e28e406b358f79221c515b2a56520d5dbbfb6c8 - split Parsing\Helpers into per-domain Link / Media / Code classes</title>
        <link>http://127.0.0.1:8080/history/dokuwiki/inc/Parsing/ParserMode/GfmLink.php#1e28e406b358f79221c515b2a56520d5dbbfb6c8</link>
        <description>split Parsing\Helpers into per-domain Link / Media / Code classes

            List of files:
            /dokuwiki/inc/Parsing/ParserMode/GfmLink.php</description>
        <pubDate>Thu, 23 Apr 2026 14:37:53 +0000</pubDate>
        <dc:creator>Andreas Gohr &lt;andi@splitbrain.org&gt;</dc:creator>
    </item>
<item>
        <title>3440a8c07d59952439e180d2c33a32262fd3a84c - add GfmMedia and extend GfmLink with image-as-label form</title>
        <link>http://127.0.0.1:8080/history/dokuwiki/inc/Parsing/ParserMode/GfmLink.php#3440a8c07d59952439e180d2c33a32262fd3a84c</link>
        <description>add GfmMedia and extend GfmLink with image-as-label form- New GfmMedia parses `![alt](url)` with the full DokuWiki media-parameter  vocabulary in the URL slot (?100x200, ?right, ?nolink, ?recache, &#8230;).  Adds `?left`/`?right`/`?center` align keywords shared with DW `{{&#8230;}}`  &#8212; gives pure-Markdown users a way to align inline images.- GfmLink now also matches `[![alt](img)](target)` &#8212; the GFM equivalent  of `[[target|{{img}}]]`. Detection is post-entry, mirroring  Internallink&apos;s `^{{&#8230;}}$` check; one mode covers the whole family.- LinkDispatch trait replaced by Helpers::classifyLink and  Helpers::parseMediaParameters &#8212; two pure static methods, shared by  DW and GFM counterparts.- Entry patterns for GfmLink / GfmMedia simplified (permissive URL slot,  handle-time parsing), following DW&apos;s Internallink style.- GfmSpecTest drives a test-only SpecCompatRenderer that emits bare  &lt;img&gt; / &lt;a&gt; instead of DW&apos;s wiki-wrapped HTML, recovering 13 spec  tests that previously failed/skipped only because of renderer shape.

            List of files:
            /dokuwiki/inc/Parsing/ParserMode/GfmLink.php</description>
        <pubDate>Wed, 22 Apr 2026 14:28:30 +0000</pubDate>
        <dc:creator>Andreas Gohr &lt;gohr@cosmocode.de&gt;</dc:creator>
    </item>
<item>
        <title>e89aeebd5989e476b6a69236d9aabf72a9a01f14 - add GfmLink for GFM inline links `[text](url)`</title>
        <link>http://127.0.0.1:8080/history/dokuwiki/inc/Parsing/ParserMode/GfmLink.php#e89aeebd5989e476b6a69236d9aabf72a9a01f14</link>
        <description>add GfmLink for GFM inline links `[text](url)`Extracts the URL-classification ladder from Internallink into aLinkDispatch trait so both modes route identically across all sixDokuWiki link flavors (internal, external, interwiki, email,windowsshare, local anchor). GfmLink parses the `[text](url)` formwith optional `&quot;title&quot;` / `&apos;title&apos;` and hands the URL to the trait.The GFM title attribute is discarded &#8212; DokuWiki link instructionshave no slot for it.

            List of files:
            /dokuwiki/inc/Parsing/ParserMode/GfmLink.php</description>
        <pubDate>Wed, 22 Apr 2026 10:30:14 +0000</pubDate>
        <dc:creator>Andreas Gohr &lt;gohr@cosmocode.de&gt;</dc:creator>
    </item>
</channel>
</rss>
