Fossil SCM

Impose a limit on the depth of nesting of inline footnotes. Also add a few test cases: for depth limiting and HTML hijacking.

george 2022-02-21 04:29 markdown-footnotes
Commit f4ff013ace5f1c557b9089133c0874b11f21b51a8aa5ebcd4092471a5a46ae34
--- src/default.css
+++ src/default.css
@@ -1683,10 +1683,11 @@
16831683
}
16841684
div.markdown ol.footnotes > li.fn-misreference {
16851685
margin-top: 0.75em;
16861686
margin-bottom: 0.75em;
16871687
}
1688
+div.markdown ol.footnotes > li.fn-toodeep > i,
16881689
div.markdown ol.footnotes > li.fn-misreference,
16891690
div.markdown ol.footnotes > li.fn-unreferenced {
16901691
color: gray;
16911692
}
16921693
div.markdown ol.footnotes > li.fn-misreference > span {
@@ -1702,16 +1703,23 @@
17021703
color: red;
17031704
}
17041705
div.markdown ol.footnotes > li.fn-unreferenced > i::after {
17051706
content: " was defined but is not referenced";
17061707
}
1708
+div.markdown ol.footnotes > li.fn-toodeep > i::after {
1709
+ content: " depth of nesting of inline footnotes exceeded the limit";
1710
+}
1711
+div.markdown ol.footnotes > li.fn-toodeep > pre,
17071712
div.markdown ol.footnotes > li.fn-unreferenced > pre {
17081713
color: gray;
17091714
font-size: 85%;
17101715
padding-left: 0.5em;
17111716
margin-top: 0.25em;
17121717
border-left: 2px solid red;
1718
+}
1719
+div.markdown ol.footnotes > li.fn-toodeep > pre {
1720
+ margin-left: 0.5em;
17131721
}
17141722
div.markdown > ol.footnotes > li > .fn-backrefs {
17151723
margin-right: 0.5em;
17161724
font-weight: bold;
17171725
}
17181726
--- src/default.css
+++ src/default.css
@@ -1683,10 +1683,11 @@
1683 }
1684 div.markdown ol.footnotes > li.fn-misreference {
1685 margin-top: 0.75em;
1686 margin-bottom: 0.75em;
1687 }
 
1688 div.markdown ol.footnotes > li.fn-misreference,
1689 div.markdown ol.footnotes > li.fn-unreferenced {
1690 color: gray;
1691 }
1692 div.markdown ol.footnotes > li.fn-misreference > span {
@@ -1702,16 +1703,23 @@
1702 color: red;
1703 }
1704 div.markdown ol.footnotes > li.fn-unreferenced > i::after {
1705 content: " was defined but is not referenced";
1706 }
 
 
 
 
1707 div.markdown ol.footnotes > li.fn-unreferenced > pre {
1708 color: gray;
1709 font-size: 85%;
1710 padding-left: 0.5em;
1711 margin-top: 0.25em;
1712 border-left: 2px solid red;
 
 
 
1713 }
1714 div.markdown > ol.footnotes > li > .fn-backrefs {
1715 margin-right: 0.5em;
1716 font-weight: bold;
1717 }
1718
--- src/default.css
+++ src/default.css
@@ -1683,10 +1683,11 @@
1683 }
1684 div.markdown ol.footnotes > li.fn-misreference {
1685 margin-top: 0.75em;
1686 margin-bottom: 0.75em;
1687 }
1688 div.markdown ol.footnotes > li.fn-toodeep > i,
1689 div.markdown ol.footnotes > li.fn-misreference,
1690 div.markdown ol.footnotes > li.fn-unreferenced {
1691 color: gray;
1692 }
1693 div.markdown ol.footnotes > li.fn-misreference > span {
@@ -1702,16 +1703,23 @@
1703 color: red;
1704 }
1705 div.markdown ol.footnotes > li.fn-unreferenced > i::after {
1706 content: " was defined but is not referenced";
1707 }
1708 div.markdown ol.footnotes > li.fn-toodeep > i::after {
1709 content: " depth of nesting of inline footnotes exceeded the limit";
1710 }
1711 div.markdown ol.footnotes > li.fn-toodeep > pre,
1712 div.markdown ol.footnotes > li.fn-unreferenced > pre {
1713 color: gray;
1714 font-size: 85%;
1715 padding-left: 0.5em;
1716 margin-top: 0.25em;
1717 border-left: 2px solid red;
1718 }
1719 div.markdown ol.footnotes > li.fn-toodeep > pre {
1720 margin-left: 0.5em;
1721 }
1722 div.markdown > ol.footnotes > li > .fn-backrefs {
1723 margin-right: 0.5em;
1724 font-weight: bold;
1725 }
1726
+6 -6
--- src/markdown.c
+++ src/markdown.c
@@ -2732,11 +2732,11 @@
27322732
if( (blob_size(allNotes) || rndr.notes.misref.nUsed) ){
27332733
27342734
/* Footnotes must be parsed for the correct discovery of (back)links */
27352735
Blob *notes = new_work_buffer( &rndr );
27362736
Blob *tmp = new_work_buffer( &rndr );
2737
- int nMarks = -1;
2737
+ int nMarks = -1, maxDepth = 5;
27382738
27392739
/* inline notes may get appended to rndr.notes.all while rendering */
27402740
while(1){
27412741
struct footnote *aNotes;
27422742
const int N = COUNT_FOOTNOTES( allNotes );
@@ -2745,11 +2745,11 @@
27452745
blob_truncate(notes,0);
27462746
blob_append(notes, blob_buffer(allNotes), blob_size(allNotes));
27472747
aNotes = CAST_AS_FOOTNOTES(notes);
27482748
qsort(aNotes, N, sizeof(struct footnote), cmp_footnote_sort);
27492749
2750
- if( nMarks == rndr.notes.nMarks ) break;
2750
+ if( --maxDepth < 0 || nMarks == rndr.notes.nMarks ) break;
27512751
nMarks = rndr.notes.nMarks;
27522752
27532753
for(i=0; i<N; i++){
27542754
const int j = aNotes[i].index;
27552755
struct footnote *x = CAST_AS_FOOTNOTES(allNotes) + j;
@@ -2773,13 +2773,13 @@
27732773
if( rndr.make.footnote_item && rndr.make.footnotes ){
27742774
Blob *all_items = new_work_buffer(&rndr);
27752775
int j = -1;
27762776
for(i=0; i<COUNT_FOOTNOTES(notes); i++){
27772777
const struct footnote* x = CAST_AS_FOOTNOTES(notes) + i;
2778
- if( x->bRndred ){
2778
+ if( x->iMark ){
27792779
rndr.make.footnote_item(all_items, &x->text, x->iMark,
2780
- x->nUsed, rndr.make.opaque);
2780
+ x->bRndred ? x->nUsed : 0, rndr.make.opaque);
27812781
j = i;
27822782
}
27832783
}
27842784
if( rndr.notes.misref.nUsed ){
27852785
rndr.make.footnote_item(all_items, 0, -1,
@@ -2786,15 +2786,15 @@
27862786
rndr.notes.misref.nUsed, rndr.make.opaque);
27872787
g.ftntsIssues[0] += rndr.notes.misref.nUsed;
27882788
}
27892789
while( ++j < COUNT_FOOTNOTES(notes) ){
27902790
const struct footnote* x = CAST_AS_FOOTNOTES(notes) + j;
2791
- assert( !x->nUsed );
2791
+ assert( !x->iMark );
27922792
assert( !x->bRndred );
27932793
assert( (&x->id) + 1 == &x->text ); /* see html_footnote_item() */
27942794
assert( (&x->upc)- 1 == &x->text );
2795
- rndr.make.footnote_item(all_items,&x->text,0,0,rndr.make.opaque);
2795
+ rndr.make.footnote_item(all_items,&x->text,x->iMark,0,rndr.make.opaque);
27962796
g.ftntsIssues[1]++;
27972797
}
27982798
rndr.make.footnotes(ob, all_items, rndr.make.opaque);
27992799
release_work_buffer(&rndr, all_items);
28002800
}
28012801
--- src/markdown.c
+++ src/markdown.c
@@ -2732,11 +2732,11 @@
2732 if( (blob_size(allNotes) || rndr.notes.misref.nUsed) ){
2733
2734 /* Footnotes must be parsed for the correct discovery of (back)links */
2735 Blob *notes = new_work_buffer( &rndr );
2736 Blob *tmp = new_work_buffer( &rndr );
2737 int nMarks = -1;
2738
2739 /* inline notes may get appended to rndr.notes.all while rendering */
2740 while(1){
2741 struct footnote *aNotes;
2742 const int N = COUNT_FOOTNOTES( allNotes );
@@ -2745,11 +2745,11 @@
2745 blob_truncate(notes,0);
2746 blob_append(notes, blob_buffer(allNotes), blob_size(allNotes));
2747 aNotes = CAST_AS_FOOTNOTES(notes);
2748 qsort(aNotes, N, sizeof(struct footnote), cmp_footnote_sort);
2749
2750 if( nMarks == rndr.notes.nMarks ) break;
2751 nMarks = rndr.notes.nMarks;
2752
2753 for(i=0; i<N; i++){
2754 const int j = aNotes[i].index;
2755 struct footnote *x = CAST_AS_FOOTNOTES(allNotes) + j;
@@ -2773,13 +2773,13 @@
2773 if( rndr.make.footnote_item && rndr.make.footnotes ){
2774 Blob *all_items = new_work_buffer(&rndr);
2775 int j = -1;
2776 for(i=0; i<COUNT_FOOTNOTES(notes); i++){
2777 const struct footnote* x = CAST_AS_FOOTNOTES(notes) + i;
2778 if( x->bRndred ){
2779 rndr.make.footnote_item(all_items, &x->text, x->iMark,
2780 x->nUsed, rndr.make.opaque);
2781 j = i;
2782 }
2783 }
2784 if( rndr.notes.misref.nUsed ){
2785 rndr.make.footnote_item(all_items, 0, -1,
@@ -2786,15 +2786,15 @@
2786 rndr.notes.misref.nUsed, rndr.make.opaque);
2787 g.ftntsIssues[0] += rndr.notes.misref.nUsed;
2788 }
2789 while( ++j < COUNT_FOOTNOTES(notes) ){
2790 const struct footnote* x = CAST_AS_FOOTNOTES(notes) + j;
2791 assert( !x->nUsed );
2792 assert( !x->bRndred );
2793 assert( (&x->id) + 1 == &x->text ); /* see html_footnote_item() */
2794 assert( (&x->upc)- 1 == &x->text );
2795 rndr.make.footnote_item(all_items,&x->text,0,0,rndr.make.opaque);
2796 g.ftntsIssues[1]++;
2797 }
2798 rndr.make.footnotes(ob, all_items, rndr.make.opaque);
2799 release_work_buffer(&rndr, all_items);
2800 }
2801
--- src/markdown.c
+++ src/markdown.c
@@ -2732,11 +2732,11 @@
2732 if( (blob_size(allNotes) || rndr.notes.misref.nUsed) ){
2733
2734 /* Footnotes must be parsed for the correct discovery of (back)links */
2735 Blob *notes = new_work_buffer( &rndr );
2736 Blob *tmp = new_work_buffer( &rndr );
2737 int nMarks = -1, maxDepth = 5;
2738
2739 /* inline notes may get appended to rndr.notes.all while rendering */
2740 while(1){
2741 struct footnote *aNotes;
2742 const int N = COUNT_FOOTNOTES( allNotes );
@@ -2745,11 +2745,11 @@
2745 blob_truncate(notes,0);
2746 blob_append(notes, blob_buffer(allNotes), blob_size(allNotes));
2747 aNotes = CAST_AS_FOOTNOTES(notes);
2748 qsort(aNotes, N, sizeof(struct footnote), cmp_footnote_sort);
2749
2750 if( --maxDepth < 0 || nMarks == rndr.notes.nMarks ) break;
2751 nMarks = rndr.notes.nMarks;
2752
2753 for(i=0; i<N; i++){
2754 const int j = aNotes[i].index;
2755 struct footnote *x = CAST_AS_FOOTNOTES(allNotes) + j;
@@ -2773,13 +2773,13 @@
2773 if( rndr.make.footnote_item && rndr.make.footnotes ){
2774 Blob *all_items = new_work_buffer(&rndr);
2775 int j = -1;
2776 for(i=0; i<COUNT_FOOTNOTES(notes); i++){
2777 const struct footnote* x = CAST_AS_FOOTNOTES(notes) + i;
2778 if( x->iMark ){
2779 rndr.make.footnote_item(all_items, &x->text, x->iMark,
2780 x->bRndred ? x->nUsed : 0, rndr.make.opaque);
2781 j = i;
2782 }
2783 }
2784 if( rndr.notes.misref.nUsed ){
2785 rndr.make.footnote_item(all_items, 0, -1,
@@ -2786,15 +2786,15 @@
2786 rndr.notes.misref.nUsed, rndr.make.opaque);
2787 g.ftntsIssues[0] += rndr.notes.misref.nUsed;
2788 }
2789 while( ++j < COUNT_FOOTNOTES(notes) ){
2790 const struct footnote* x = CAST_AS_FOOTNOTES(notes) + j;
2791 assert( !x->iMark );
2792 assert( !x->bRndred );
2793 assert( (&x->id) + 1 == &x->text ); /* see html_footnote_item() */
2794 assert( (&x->upc)- 1 == &x->text );
2795 rndr.make.footnote_item(all_items,&x->text,x->iMark,0,rndr.make.opaque);
2796 g.ftntsIssues[1]++;
2797 }
2798 rndr.make.footnotes(ob, all_items, rndr.make.opaque);
2799 release_work_buffer(&rndr, all_items);
2800 }
2801
--- src/markdown_html.c
+++ src/markdown_html.c
@@ -468,29 +468,35 @@
468468
}
469469
if( i < nUsed ) BLOB_APPEND_LITERAL(ob," &hellip;");
470470
}
471471
BLOB_APPEND_LITERAL(ob,"</sup>\n<span>Misreference</span>");
472472
473
- }else if( nUsed ){ /* a regular footnote */
473
+ }else if( iMark > 0 ){ /* a regular footnote */
474474
char pos[24];
475
- const char *join = "";
475
+ int bJoin = 0;
476476
/* make.footnote_item() invocations should pass args accordingly */
477477
const struct Blob * upc = text+1;
478478
#define _joined_footnote_indicator "<ul class='fn-joined'>"
479479
#define _jfi_sz (sizeof(_joined_footnote_indicator)-1)
480480
assert( text );
481481
assert( blob_size(text) );
482
- if( blob_size(text)>=_jfi_sz &&
483
- !memcmp(blob_buffer(text),_joined_footnote_indicator,_jfi_sz)){
484
- join = "fn-joined ";
485
- }
486482
memset(pos,0,24);
487483
sprintf(pos, "%s-%i", unique, iMark);
488
- blob_appendf(ob, "<li id='footnote%s' class='%s", pos, join);
489
- append_footnote_upc(ob, upc, 0);
484
+
485
+ blob_appendf(ob, "<li id='footnote%s' class='", pos);
486
+ if( nUsed ){
487
+ if( blob_size(text)>=_jfi_sz &&
488
+ !memcmp(blob_buffer(text),_joined_footnote_indicator,_jfi_sz)){
489
+ bJoin = 1;
490
+ BLOB_APPEND_LITERAL(ob, "fn-joined ");
491
+ }
492
+ append_footnote_upc(ob, upc, 0);
493
+ }else{
494
+ BLOB_APPEND_LITERAL(ob, "fn-toodeep ");
495
+ }
490496
491
- if( nUsed == 1 ){
497
+ if( nUsed <= 1 ){
492498
BLOB_APPEND_LITERAL(ob, "fn-monoref'><sup class='fn-backrefs'>");
493499
blob_appendf(ob,"<a id='footnote%s-a' href='", pos);
494500
BLOB_APPEND_URI(ob, ctx);
495501
blob_appendf(ob,"#noteref%s-a'>^</a>", pos);
496502
}else{
@@ -512,22 +518,28 @@
512518
}
513519
if( i < nUsed ) BLOB_APPEND_LITERAL(ob," &hellip;");
514520
}
515521
BLOB_APPEND_LITERAL(ob,"</sup>\n");
516522
append_footnote_upc(ob, upc, 1);
517
- if( join[0] ){
523
+ if( bJoin ){
518524
BLOB_APPEND_LITERAL(ob,"<sup class='fn-joined'></sup><ul>");
519525
blob_append(ob,blob_buffer(text)+_jfi_sz,blob_size(text)-_jfi_sz);
520
- }else{
526
+ }else if( nUsed ){
521527
BLOB_APPEND_BLOB(ob, text);
528
+ }else{
529
+ BLOB_APPEND_LITERAL(ob,"<i></i>\n"
530
+ "<pre><code class='language-markdown'>");
531
+ html_escape(ob, blob_buffer(text), blob_size(text));
532
+ BLOB_APPEND_LITERAL(ob,"</code></pre>");
522533
}
523534
#undef _joined_footnote_indicator
524535
#undef _jfi_sz
525536
}else{
526537
/* a footnote was defined but wasn't used */
527538
/* make.footnote_item() invocations should pass args accordingly */
528539
const struct Blob * id = text-1;
540
+ assert( !nUsed );
529541
assert( text );
530542
assert( blob_size(text) );
531543
assert( blob_size(id) );
532544
BLOB_APPEND_LITERAL(ob,"<li class='fn-unreferenced'>\n[^&nbsp;<code>");
533545
html_escape(ob, blob_buffer(id), blob_size(id));
534546
--- src/markdown_html.c
+++ src/markdown_html.c
@@ -468,29 +468,35 @@
468 }
469 if( i < nUsed ) BLOB_APPEND_LITERAL(ob," &hellip;");
470 }
471 BLOB_APPEND_LITERAL(ob,"</sup>\n<span>Misreference</span>");
472
473 }else if( nUsed ){ /* a regular footnote */
474 char pos[24];
475 const char *join = "";
476 /* make.footnote_item() invocations should pass args accordingly */
477 const struct Blob * upc = text+1;
478 #define _joined_footnote_indicator "<ul class='fn-joined'>"
479 #define _jfi_sz (sizeof(_joined_footnote_indicator)-1)
480 assert( text );
481 assert( blob_size(text) );
482 if( blob_size(text)>=_jfi_sz &&
483 !memcmp(blob_buffer(text),_joined_footnote_indicator,_jfi_sz)){
484 join = "fn-joined ";
485 }
486 memset(pos,0,24);
487 sprintf(pos, "%s-%i", unique, iMark);
488 blob_appendf(ob, "<li id='footnote%s' class='%s", pos, join);
489 append_footnote_upc(ob, upc, 0);
 
 
 
 
 
 
 
 
 
 
490
491 if( nUsed == 1 ){
492 BLOB_APPEND_LITERAL(ob, "fn-monoref'><sup class='fn-backrefs'>");
493 blob_appendf(ob,"<a id='footnote%s-a' href='", pos);
494 BLOB_APPEND_URI(ob, ctx);
495 blob_appendf(ob,"#noteref%s-a'>^</a>", pos);
496 }else{
@@ -512,22 +518,28 @@
512 }
513 if( i < nUsed ) BLOB_APPEND_LITERAL(ob," &hellip;");
514 }
515 BLOB_APPEND_LITERAL(ob,"</sup>\n");
516 append_footnote_upc(ob, upc, 1);
517 if( join[0] ){
518 BLOB_APPEND_LITERAL(ob,"<sup class='fn-joined'></sup><ul>");
519 blob_append(ob,blob_buffer(text)+_jfi_sz,blob_size(text)-_jfi_sz);
520 }else{
521 BLOB_APPEND_BLOB(ob, text);
 
 
 
 
 
522 }
523 #undef _joined_footnote_indicator
524 #undef _jfi_sz
525 }else{
526 /* a footnote was defined but wasn't used */
527 /* make.footnote_item() invocations should pass args accordingly */
528 const struct Blob * id = text-1;
 
529 assert( text );
530 assert( blob_size(text) );
531 assert( blob_size(id) );
532 BLOB_APPEND_LITERAL(ob,"<li class='fn-unreferenced'>\n[^&nbsp;<code>");
533 html_escape(ob, blob_buffer(id), blob_size(id));
534
--- src/markdown_html.c
+++ src/markdown_html.c
@@ -468,29 +468,35 @@
468 }
469 if( i < nUsed ) BLOB_APPEND_LITERAL(ob," &hellip;");
470 }
471 BLOB_APPEND_LITERAL(ob,"</sup>\n<span>Misreference</span>");
472
473 }else if( iMark > 0 ){ /* a regular footnote */
474 char pos[24];
475 int bJoin = 0;
476 /* make.footnote_item() invocations should pass args accordingly */
477 const struct Blob * upc = text+1;
478 #define _joined_footnote_indicator "<ul class='fn-joined'>"
479 #define _jfi_sz (sizeof(_joined_footnote_indicator)-1)
480 assert( text );
481 assert( blob_size(text) );
 
 
 
 
482 memset(pos,0,24);
483 sprintf(pos, "%s-%i", unique, iMark);
484
485 blob_appendf(ob, "<li id='footnote%s' class='", pos);
486 if( nUsed ){
487 if( blob_size(text)>=_jfi_sz &&
488 !memcmp(blob_buffer(text),_joined_footnote_indicator,_jfi_sz)){
489 bJoin = 1;
490 BLOB_APPEND_LITERAL(ob, "fn-joined ");
491 }
492 append_footnote_upc(ob, upc, 0);
493 }else{
494 BLOB_APPEND_LITERAL(ob, "fn-toodeep ");
495 }
496
497 if( nUsed <= 1 ){
498 BLOB_APPEND_LITERAL(ob, "fn-monoref'><sup class='fn-backrefs'>");
499 blob_appendf(ob,"<a id='footnote%s-a' href='", pos);
500 BLOB_APPEND_URI(ob, ctx);
501 blob_appendf(ob,"#noteref%s-a'>^</a>", pos);
502 }else{
@@ -512,22 +518,28 @@
518 }
519 if( i < nUsed ) BLOB_APPEND_LITERAL(ob," &hellip;");
520 }
521 BLOB_APPEND_LITERAL(ob,"</sup>\n");
522 append_footnote_upc(ob, upc, 1);
523 if( bJoin ){
524 BLOB_APPEND_LITERAL(ob,"<sup class='fn-joined'></sup><ul>");
525 blob_append(ob,blob_buffer(text)+_jfi_sz,blob_size(text)-_jfi_sz);
526 }else if( nUsed ){
527 BLOB_APPEND_BLOB(ob, text);
528 }else{
529 BLOB_APPEND_LITERAL(ob,"<i></i>\n"
530 "<pre><code class='language-markdown'>");
531 html_escape(ob, blob_buffer(text), blob_size(text));
532 BLOB_APPEND_LITERAL(ob,"</code></pre>");
533 }
534 #undef _joined_footnote_indicator
535 #undef _jfi_sz
536 }else{
537 /* a footnote was defined but wasn't used */
538 /* make.footnote_item() invocations should pass args accordingly */
539 const struct Blob * id = text-1;
540 assert( !nUsed );
541 assert( text );
542 assert( blob_size(text) );
543 assert( blob_size(id) );
544 BLOB_APPEND_LITERAL(ob,"<li class='fn-unreferenced'>\n[^&nbsp;<code>");
545 html_escape(ob, blob_buffer(id), blob_size(id));
546
--- test/markdown-test3.md
+++ test/markdown-test3.md
@@ -123,10 +123,54 @@
123123
is not interpreted as such, instead it is emitted as plain text.
124124
(^
125125
.bare.classlist.inside.inline.footnote:
126126
)[^bare1]
127127
[^bare2]
128
+
129
+<html>
130
+ Click
131
+ <a href="?a=B&quote='&nonASCII=😂&script=<script>alert('Broken!');</script>">
132
+ here</a> and
133
+ <a href='?a=B&quote="&nonASCII=😂&script=<script>alert("Broken!");</script>'>
134
+ here</a>
135
+ to test escaping of REQUEST_URI in the generated footnote markers.
136
+</html>
137
+
138
+A depth of nesting must be limited.
139
+(^
140
+ A long chain of nested inline footnotes...
141
+ (^
142
+ is a rather unusual thing...
143
+ (^
144
+ and requires extra CPU cycles for processing.
145
+ (^
146
+ Theoretically speaking O(n<sup>2</sup>).
147
+ (^
148
+ Thus it is worth dismissing those footnotes...
149
+ (^
150
+ that are nested deeper than on a certain level.
151
+ (^
152
+ A particular value for that limit...
153
+ (^
154
+ is hard-coded in src/markdown.c ...
155
+ (^
156
+ in function `markdown()` ...
157
+ (^
158
+ in variable named `maxDepth`.
159
+ (^
160
+ For the time being, its value is **5**
161
+ )
162
+ )
163
+ )
164
+ )
165
+ )
166
+ )
167
+ )
168
+ )
169
+ )
170
+ )
171
+)
128172
129173
## Footnotes
130174
131175
[branch]: /timeline?r=markdown-footnotes&nowiki
132176
@@ -177,5 +221,12 @@
177221
178222
[^nostyle]:
179223
.unused.classes:
180224
In that case text of the footnote just looks like as if
181225
no special processing occured.
226
+
227
+
228
+[^ <script>alert("You have been pwned!");</script> ]: Labels are escaped
229
+
230
+[^ <textarea>"Last words here...' ]:
231
+ <textarea>Content is also escaped</textarea>
232
+
182233
--- test/markdown-test3.md
+++ test/markdown-test3.md
@@ -123,10 +123,54 @@
123 is not interpreted as such, instead it is emitted as plain text.
124 (^
125 .bare.classlist.inside.inline.footnote:
126 )[^bare1]
127 [^bare2]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
129 ## Footnotes
130
131 [branch]: /timeline?r=markdown-footnotes&nowiki
132
@@ -177,5 +221,12 @@
177
178 [^nostyle]:
179 .unused.classes:
180 In that case text of the footnote just looks like as if
181 no special processing occured.
 
 
 
 
 
 
 
182
--- test/markdown-test3.md
+++ test/markdown-test3.md
@@ -123,10 +123,54 @@
123 is not interpreted as such, instead it is emitted as plain text.
124 (^
125 .bare.classlist.inside.inline.footnote:
126 )[^bare1]
127 [^bare2]
128
129 <html>
130 Click
131 <a href="?a=B&quote='&nonASCII=😂&script=<script>alert('Broken!');</script>">
132 here</a> and
133 <a href='?a=B&quote="&nonASCII=😂&script=<script>alert("Broken!");</script>'>
134 here</a>
135 to test escaping of REQUEST_URI in the generated footnote markers.
136 </html>
137
138 A depth of nesting must be limited.
139 (^
140 A long chain of nested inline footnotes...
141 (^
142 is a rather unusual thing...
143 (^
144 and requires extra CPU cycles for processing.
145 (^
146 Theoretically speaking O(n<sup>2</sup>).
147 (^
148 Thus it is worth dismissing those footnotes...
149 (^
150 that are nested deeper than on a certain level.
151 (^
152 A particular value for that limit...
153 (^
154 is hard-coded in src/markdown.c ...
155 (^
156 in function `markdown()` ...
157 (^
158 in variable named `maxDepth`.
159 (^
160 For the time being, its value is **5**
161 )
162 )
163 )
164 )
165 )
166 )
167 )
168 )
169 )
170 )
171 )
172
173 ## Footnotes
174
175 [branch]: /timeline?r=markdown-footnotes&nowiki
176
@@ -177,5 +221,12 @@
221
222 [^nostyle]:
223 .unused.classes:
224 In that case text of the footnote just looks like as if
225 no special processing occured.
226
227
228 [^ <script>alert("You have been pwned!");</script> ]: Labels are escaped
229
230 [^ <textarea>"Last words here...' ]:
231 <textarea>Content is also escaped</textarea>
232
233

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button