Fossil SCM

Merge in Markdown changes from trunk.

graham 2020-06-02 13:52 ui-local-diff merge
Commit bf5a21e0364383bca4443ba69f16e4e156109385f259f19a023b8ddb52d7c29b
+2 -1
--- src/config.h
+++ src/config.h
@@ -254,11 +254,12 @@
254254
#endif
255255
256256
/*
257257
** Number of elements in an array
258258
*/
259
-#define count(X) (sizeof(X)/sizeof(X[0]))
259
+#define count(X) (int)(sizeof(X)/sizeof(X[0]))
260
+#define ArraySize(X) (int)(sizeof(X)/sizeof(X[0]))
260261
261262
/*
262263
** The pledge() interface is currently only available on OpenBSD 5.9
263264
** and later. Make calls to fossil_pledge() no-ops on all platforms
264265
** that omit the HAVE_PLEDGE configuration parameter.
265266
--- src/config.h
+++ src/config.h
@@ -254,11 +254,12 @@
254 #endif
255
256 /*
257 ** Number of elements in an array
258 */
259 #define count(X) (sizeof(X)/sizeof(X[0]))
 
260
261 /*
262 ** The pledge() interface is currently only available on OpenBSD 5.9
263 ** and later. Make calls to fossil_pledge() no-ops on all platforms
264 ** that omit the HAVE_PLEDGE configuration parameter.
265
--- src/config.h
+++ src/config.h
@@ -254,11 +254,12 @@
254 #endif
255
256 /*
257 ** Number of elements in an array
258 */
259 #define count(X) (int)(sizeof(X)/sizeof(X[0]))
260 #define ArraySize(X) (int)(sizeof(X)/sizeof(X[0]))
261
262 /*
263 ** The pledge() interface is currently only available on OpenBSD 5.9
264 ** and later. Make calls to fossil_pledge() no-ops on all platforms
265 ** that omit the HAVE_PLEDGE configuration parameter.
266
--- src/forum.c
+++ src/forum.c
@@ -667,11 +667,10 @@
667667
@ <div id='forum%d(fpid)' class='forumHierRoot%s(zSel)'>
668668
}else{
669669
@ <div id='forum%d(fpid)' class='forumHier%s(zSel)' \
670670
@ style='margin-left: %d((p->nIndent-1)*iIndentScale)ex;'>
671671
}
672
- pPost = manifest_get(fpid, CFTYPE_FORUM, 0);
673672
if( pPost==0 ) continue;
674673
if( pPost->zThreadTitle ){
675674
@ <h1>%h(pPost->zThreadTitle)</h1>
676675
}
677676
zDate = db_text(0, "SELECT datetime(%.17g)", pOPost->rDate);
678677
--- src/forum.c
+++ src/forum.c
@@ -667,11 +667,10 @@
667 @ <div id='forum%d(fpid)' class='forumHierRoot%s(zSel)'>
668 }else{
669 @ <div id='forum%d(fpid)' class='forumHier%s(zSel)' \
670 @ style='margin-left: %d((p->nIndent-1)*iIndentScale)ex;'>
671 }
672 pPost = manifest_get(fpid, CFTYPE_FORUM, 0);
673 if( pPost==0 ) continue;
674 if( pPost->zThreadTitle ){
675 @ <h1>%h(pPost->zThreadTitle)</h1>
676 }
677 zDate = db_text(0, "SELECT datetime(%.17g)", pOPost->rDate);
678
--- src/forum.c
+++ src/forum.c
@@ -667,11 +667,10 @@
667 @ <div id='forum%d(fpid)' class='forumHierRoot%s(zSel)'>
668 }else{
669 @ <div id='forum%d(fpid)' class='forumHier%s(zSel)' \
670 @ style='margin-left: %d((p->nIndent-1)*iIndentScale)ex;'>
671 }
 
672 if( pPost==0 ) continue;
673 if( pPost->zThreadTitle ){
674 @ <h1>%h(pPost->zThreadTitle)</h1>
675 }
676 zDate = db_text(0, "SELECT datetime(%.17g)", pOPost->rDate);
677
+2 -1
--- src/markdown.c
+++ src/markdown.c
@@ -2008,11 +2008,12 @@
20082008
){
20092009
size_t beg, end, i;
20102010
char *txt_data;
20112011
int has_table = (rndr->make.table
20122012
&& rndr->make.table_row
2013
- && rndr->make.table_cell);
2013
+ && rndr->make.table_cell
2014
+ && memchr(data, '|', size)!=0);
20142015
20152016
beg = 0;
20162017
while( beg<size ){
20172018
txt_data = data+beg;
20182019
end = size-beg;
20192020
--- src/markdown.c
+++ src/markdown.c
@@ -2008,11 +2008,12 @@
2008 ){
2009 size_t beg, end, i;
2010 char *txt_data;
2011 int has_table = (rndr->make.table
2012 && rndr->make.table_row
2013 && rndr->make.table_cell);
 
2014
2015 beg = 0;
2016 while( beg<size ){
2017 txt_data = data+beg;
2018 end = size-beg;
2019
--- src/markdown.c
+++ src/markdown.c
@@ -2008,11 +2008,12 @@
2008 ){
2009 size_t beg, end, i;
2010 char *txt_data;
2011 int has_table = (rndr->make.table
2012 && rndr->make.table_row
2013 && rndr->make.table_cell
2014 && memchr(data, '|', size)!=0);
2015
2016 beg = 0;
2017 while( beg<size ){
2018 txt_data = data+beg;
2019 end = size-beg;
2020
--- src/markdown_html.c
+++ src/markdown_html.c
@@ -45,11 +45,11 @@
4545
* the error is not overly explicit.
4646
*/
4747
4848
/* BLOB_APPEND_BLOB -- append blob contents to another */
4949
#define BLOB_APPEND_BLOB(dest, src) \
50
- blob_append((dest), blob_buffer(src), blob_size(src))
50
+ safe_html_append((dest), blob_buffer(src), blob_size(src))
5151
5252
5353
/* HTML escapes
5454
**
5555
** html_escape() converts < to &lt;, > to &gt;, and & to &amp;.
@@ -129,11 +129,11 @@
129129
static void html_epilog(struct Blob *ob, void *opaque){
130130
INTER_BLOCK(ob);
131131
BLOB_APPEND_LITERAL(ob, "</div>\n");
132132
}
133133
134
-static void html_raw_block(struct Blob *ob, struct Blob *text, void *opaque){
134
+static void html_blockhtml(struct Blob *ob, struct Blob *text, void *opaque){
135135
char *data = blob_buffer(text);
136136
size_t size = blob_size(text);
137137
Blob *title = (Blob*)opaque;
138138
while( size>0 && fossil_isspace(data[0]) ){ data++; size--; }
139139
while( size>0 && fossil_isspace(data[size-1]) ){ size--; }
@@ -142,16 +142,16 @@
142142
&& size>9
143143
&& title!=0
144144
&& sqlite3_strnicmp("<h1",data,3)==0
145145
&& sqlite3_strnicmp("</h1>", &data[size-5],5)==0
146146
){
147
- int nTag = htmlTagLength(data);
147
+ int nTag = html_tag_length(data);
148148
blob_append(title, data+nTag, size - nTag - 5);
149149
return;
150150
}
151151
INTER_BLOCK(ob);
152
- blob_append(ob, data, size);
152
+ safe_html_append(ob, data, size);
153153
BLOB_APPEND_LITERAL(ob, "\n");
154154
}
155155
156156
static void html_blockcode(struct Blob *ob, struct Blob *text, void *opaque){
157157
INTER_BLOCK(ob);
@@ -298,13 +298,12 @@
298298
299299
300300
301301
/* HTML span tags */
302302
303
-static int html_raw_span(struct Blob *ob, struct Blob *text, void *opaque){
304
- /* If the document begins with a <h1> markup, take that as the header. */
305
- BLOB_APPEND_BLOB(ob, text);
303
+static int html_raw_html_tag(struct Blob *ob, struct Blob *text, void *opaque){
304
+ blob_append(ob, blob_buffer(text), blob_size(text));
306305
return 1;
307306
}
308307
309308
static int html_autolink(
310309
struct Blob *ob,
@@ -334,11 +333,11 @@
334333
** * https://spec.commonmark.org/0.29/#code-spans
335334
**
336335
** If nSep is 1 or 2, then this is a code-span which is inline.
337336
** If nSep is 3 or more, then this is a fenced code block
338337
*/
339
-static int html_code_span(
338
+static int html_codespan(
340339
struct Blob *ob, /* Write the output here */
341340
struct Blob *text, /* The stuff in between the code span marks */
342341
int nSep, /* Number of grave accents marks as delimiters */
343342
void *opaque
344343
){
@@ -414,11 +413,11 @@
414413
}
415414
BLOB_APPEND_LITERAL(ob, "\" />");
416415
return 1;
417416
}
418417
419
-static int html_line_break(struct Blob *ob, void *opaque){
418
+static int html_linebreak(struct Blob *ob, void *opaque){
420419
BLOB_APPEND_LITERAL(ob, "<br />\n");
421420
return 1;
422421
}
423422
424423
static int html_link(
@@ -484,11 +483,11 @@
484483
html_epilog,
485484
486485
/* block level elements */
487486
html_blockcode,
488487
html_blockquote,
489
- html_raw_block,
488
+ html_blockhtml,
490489
html_header,
491490
html_hrule,
492491
html_list,
493492
html_list_item,
494493
html_paragraph,
@@ -496,27 +495,27 @@
496495
html_table_cell,
497496
html_table_row,
498497
499498
/* span level elements */
500499
html_autolink,
501
- html_code_span,
500
+ html_codespan,
502501
html_double_emphasis,
503502
html_emphasis,
504503
html_image,
505
- html_line_break,
504
+ html_linebreak,
506505
html_link,
507
- html_raw_span,
506
+ html_raw_html_tag,
508507
html_triple_emphasis,
509508
510509
/* low level elements */
511
- 0, /* entities are copied verbatim */
510
+ 0, /* entity */
512511
html_normal_text,
513512
514513
/* misc. parameters */
515
- "*_", /* emphasis characters */
516
- 0 /* opaque data */
514
+ "*_", /* emph_chars */
515
+ 0 /* opaque */
517516
};
518517
html_renderer.opaque = output_title;
519518
if( output_title ) blob_reset(output_title);
520519
blob_reset(output_body);
521520
markdown(output_body, input_markdown, &html_renderer);
522521
}
523522
--- src/markdown_html.c
+++ src/markdown_html.c
@@ -45,11 +45,11 @@
45 * the error is not overly explicit.
46 */
47
48 /* BLOB_APPEND_BLOB -- append blob contents to another */
49 #define BLOB_APPEND_BLOB(dest, src) \
50 blob_append((dest), blob_buffer(src), blob_size(src))
51
52
53 /* HTML escapes
54 **
55 ** html_escape() converts < to &lt;, > to &gt;, and & to &amp;.
@@ -129,11 +129,11 @@
129 static void html_epilog(struct Blob *ob, void *opaque){
130 INTER_BLOCK(ob);
131 BLOB_APPEND_LITERAL(ob, "</div>\n");
132 }
133
134 static void html_raw_block(struct Blob *ob, struct Blob *text, void *opaque){
135 char *data = blob_buffer(text);
136 size_t size = blob_size(text);
137 Blob *title = (Blob*)opaque;
138 while( size>0 && fossil_isspace(data[0]) ){ data++; size--; }
139 while( size>0 && fossil_isspace(data[size-1]) ){ size--; }
@@ -142,16 +142,16 @@
142 && size>9
143 && title!=0
144 && sqlite3_strnicmp("<h1",data,3)==0
145 && sqlite3_strnicmp("</h1>", &data[size-5],5)==0
146 ){
147 int nTag = htmlTagLength(data);
148 blob_append(title, data+nTag, size - nTag - 5);
149 return;
150 }
151 INTER_BLOCK(ob);
152 blob_append(ob, data, size);
153 BLOB_APPEND_LITERAL(ob, "\n");
154 }
155
156 static void html_blockcode(struct Blob *ob, struct Blob *text, void *opaque){
157 INTER_BLOCK(ob);
@@ -298,13 +298,12 @@
298
299
300
301 /* HTML span tags */
302
303 static int html_raw_span(struct Blob *ob, struct Blob *text, void *opaque){
304 /* If the document begins with a <h1> markup, take that as the header. */
305 BLOB_APPEND_BLOB(ob, text);
306 return 1;
307 }
308
309 static int html_autolink(
310 struct Blob *ob,
@@ -334,11 +333,11 @@
334 ** * https://spec.commonmark.org/0.29/#code-spans
335 **
336 ** If nSep is 1 or 2, then this is a code-span which is inline.
337 ** If nSep is 3 or more, then this is a fenced code block
338 */
339 static int html_code_span(
340 struct Blob *ob, /* Write the output here */
341 struct Blob *text, /* The stuff in between the code span marks */
342 int nSep, /* Number of grave accents marks as delimiters */
343 void *opaque
344 ){
@@ -414,11 +413,11 @@
414 }
415 BLOB_APPEND_LITERAL(ob, "\" />");
416 return 1;
417 }
418
419 static int html_line_break(struct Blob *ob, void *opaque){
420 BLOB_APPEND_LITERAL(ob, "<br />\n");
421 return 1;
422 }
423
424 static int html_link(
@@ -484,11 +483,11 @@
484 html_epilog,
485
486 /* block level elements */
487 html_blockcode,
488 html_blockquote,
489 html_raw_block,
490 html_header,
491 html_hrule,
492 html_list,
493 html_list_item,
494 html_paragraph,
@@ -496,27 +495,27 @@
496 html_table_cell,
497 html_table_row,
498
499 /* span level elements */
500 html_autolink,
501 html_code_span,
502 html_double_emphasis,
503 html_emphasis,
504 html_image,
505 html_line_break,
506 html_link,
507 html_raw_span,
508 html_triple_emphasis,
509
510 /* low level elements */
511 0, /* entities are copied verbatim */
512 html_normal_text,
513
514 /* misc. parameters */
515 "*_", /* emphasis characters */
516 0 /* opaque data */
517 };
518 html_renderer.opaque = output_title;
519 if( output_title ) blob_reset(output_title);
520 blob_reset(output_body);
521 markdown(output_body, input_markdown, &html_renderer);
522 }
523
--- src/markdown_html.c
+++ src/markdown_html.c
@@ -45,11 +45,11 @@
45 * the error is not overly explicit.
46 */
47
48 /* BLOB_APPEND_BLOB -- append blob contents to another */
49 #define BLOB_APPEND_BLOB(dest, src) \
50 safe_html_append((dest), blob_buffer(src), blob_size(src))
51
52
53 /* HTML escapes
54 **
55 ** html_escape() converts < to &lt;, > to &gt;, and & to &amp;.
@@ -129,11 +129,11 @@
129 static void html_epilog(struct Blob *ob, void *opaque){
130 INTER_BLOCK(ob);
131 BLOB_APPEND_LITERAL(ob, "</div>\n");
132 }
133
134 static void html_blockhtml(struct Blob *ob, struct Blob *text, void *opaque){
135 char *data = blob_buffer(text);
136 size_t size = blob_size(text);
137 Blob *title = (Blob*)opaque;
138 while( size>0 && fossil_isspace(data[0]) ){ data++; size--; }
139 while( size>0 && fossil_isspace(data[size-1]) ){ size--; }
@@ -142,16 +142,16 @@
142 && size>9
143 && title!=0
144 && sqlite3_strnicmp("<h1",data,3)==0
145 && sqlite3_strnicmp("</h1>", &data[size-5],5)==0
146 ){
147 int nTag = html_tag_length(data);
148 blob_append(title, data+nTag, size - nTag - 5);
149 return;
150 }
151 INTER_BLOCK(ob);
152 safe_html_append(ob, data, size);
153 BLOB_APPEND_LITERAL(ob, "\n");
154 }
155
156 static void html_blockcode(struct Blob *ob, struct Blob *text, void *opaque){
157 INTER_BLOCK(ob);
@@ -298,13 +298,12 @@
298
299
300
301 /* HTML span tags */
302
303 static int html_raw_html_tag(struct Blob *ob, struct Blob *text, void *opaque){
304 blob_append(ob, blob_buffer(text), blob_size(text));
 
305 return 1;
306 }
307
308 static int html_autolink(
309 struct Blob *ob,
@@ -334,11 +333,11 @@
333 ** * https://spec.commonmark.org/0.29/#code-spans
334 **
335 ** If nSep is 1 or 2, then this is a code-span which is inline.
336 ** If nSep is 3 or more, then this is a fenced code block
337 */
338 static int html_codespan(
339 struct Blob *ob, /* Write the output here */
340 struct Blob *text, /* The stuff in between the code span marks */
341 int nSep, /* Number of grave accents marks as delimiters */
342 void *opaque
343 ){
@@ -414,11 +413,11 @@
413 }
414 BLOB_APPEND_LITERAL(ob, "\" />");
415 return 1;
416 }
417
418 static int html_linebreak(struct Blob *ob, void *opaque){
419 BLOB_APPEND_LITERAL(ob, "<br />\n");
420 return 1;
421 }
422
423 static int html_link(
@@ -484,11 +483,11 @@
483 html_epilog,
484
485 /* block level elements */
486 html_blockcode,
487 html_blockquote,
488 html_blockhtml,
489 html_header,
490 html_hrule,
491 html_list,
492 html_list_item,
493 html_paragraph,
@@ -496,27 +495,27 @@
495 html_table_cell,
496 html_table_row,
497
498 /* span level elements */
499 html_autolink,
500 html_codespan,
501 html_double_emphasis,
502 html_emphasis,
503 html_image,
504 html_linebreak,
505 html_link,
506 html_raw_html_tag,
507 html_triple_emphasis,
508
509 /* low level elements */
510 0, /* entity */
511 html_normal_text,
512
513 /* misc. parameters */
514 "*_", /* emph_chars */
515 0 /* opaque */
516 };
517 html_renderer.opaque = output_title;
518 if( output_title ) blob_reset(output_title);
519 blob_reset(output_body);
520 markdown(output_body, input_markdown, &html_renderer);
521 }
522
+1 -1
--- src/name.c
+++ src/name.c
@@ -380,11 +380,11 @@
380380
if( zType[0]=='*' ){
381381
db_prepare(&q, "SELECT rid FROM blob WHERE uuid GLOB '%q*'", zUuid);
382382
}else{
383383
db_prepare(&q,
384384
"SELECT blob.rid"
385
- " FROM blob, event"
385
+ " FROM blob CROSS JOIN event"
386386
" WHERE blob.uuid GLOB '%q*'"
387387
" AND event.objid=blob.rid"
388388
" AND event.type GLOB '%q'",
389389
zUuid, zType
390390
);
391391
--- src/name.c
+++ src/name.c
@@ -380,11 +380,11 @@
380 if( zType[0]=='*' ){
381 db_prepare(&q, "SELECT rid FROM blob WHERE uuid GLOB '%q*'", zUuid);
382 }else{
383 db_prepare(&q,
384 "SELECT blob.rid"
385 " FROM blob, event"
386 " WHERE blob.uuid GLOB '%q*'"
387 " AND event.objid=blob.rid"
388 " AND event.type GLOB '%q'",
389 zUuid, zType
390 );
391
--- src/name.c
+++ src/name.c
@@ -380,11 +380,11 @@
380 if( zType[0]=='*' ){
381 db_prepare(&q, "SELECT rid FROM blob WHERE uuid GLOB '%q*'", zUuid);
382 }else{
383 db_prepare(&q,
384 "SELECT blob.rid"
385 " FROM blob CROSS JOIN event"
386 " WHERE blob.uuid GLOB '%q*'"
387 " AND event.objid=blob.rid"
388 " AND event.type GLOB '%q'",
389 zUuid, zType
390 );
391
+208 -3
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -249,10 +249,13 @@
249249
#define MUTYPE_TR 0x0080 /* <tr> */
250250
#define MUTYPE_TD 0x0100 /* <td> or <th> */
251251
#define MUTYPE_SPECIAL 0x0200 /* <nowiki> or <verbatim> */
252252
#define MUTYPE_HYPERLINK 0x0400 /* <a> */
253253
254
+/* MUTYPE values for elements that require strictly nested end-tags */
255
+#define MUTYPE_Nested 0x0656
256
+
254257
/*
255258
** These markup types must have an end tag.
256259
*/
257260
#define MUTYPE_STACK (MUTYPE_BLOCK | MUTYPE_FONT | MUTYPE_LIST | MUTYPE_TABLE)
258261
@@ -469,11 +472,11 @@
469472
** z points to a "<" character. Check to see if this is the start of
470473
** a valid markup. If it is, return the total number of characters in
471474
** the markup including the initial "<" and the terminating ">". If
472475
** it is not well-formed markup, return 0.
473476
*/
474
-int htmlTagLength(const char *z){
477
+int html_tag_length(const char *z){
475478
int n = 1;
476479
int inparen = 0;
477480
int c;
478481
if( z[n]=='/' ){ n++; }
479482
if( !fossil_isalpha(z[n]) ) return 0;
@@ -656,11 +659,11 @@
656659
** characters in that token. Write the token type into *pTokenType.
657660
*/
658661
static int nextWikiToken(const char *z, Renderer *p, int *pTokenType){
659662
int n;
660663
if( z[0]=='<' ){
661
- n = htmlTagLength(z);
664
+ n = html_tag_length(z);
662665
if( n>0 ){
663666
*pTokenType = TOKEN_MARKUP;
664667
return n;
665668
}else{
666669
*pTokenType = TOKEN_CHARACTER;
@@ -2026,11 +2029,11 @@
20262029
*/
20272030
int html_token_length(const char *z){
20282031
int n;
20292032
char c;
20302033
if( (c=z[0])=='<' ){
2031
- n = htmlTagLength(z);
2034
+ n = html_tag_length(z);
20322035
if( n<=0 ) n = 1;
20332036
}else if( fossil_isspace(c) ){
20342037
for(n=1; z[n] && fossil_isspace(z[n]); n++){}
20352038
}else if( c=='&' ){
20362039
n = z[1]=='#' ? 2 : 1;
@@ -2396,5 +2399,207 @@
23962399
blob_reset(&in);
23972400
fossil_puts(blob_str(&out), 0);
23982401
blob_reset(&out);
23992402
}
24002403
}
2404
+
2405
+/****************************************************************************
2406
+** safe-html:
2407
+**
2408
+** An interface for preventing HTML constructs (ex: <style>, <form>, etc)
2409
+** from being inserted into Wiki and Forum posts using Markdown. See the
2410
+** comment on safe_html_append() for additional information on what is meant
2411
+** by "safe".
2412
+**
2413
+** The safe-html restrictions only apply to Markdown, as Fossil-Wiki only
2414
+** allows safe-html by design - unsafe-HTML is never and has never been
2415
+** allowed in Fossil-Wiki.
2416
+**
2417
+** This code is in the wikiformat.c file so that it can have access to the
2418
+** white-list of acceptable HTML in the aMarkup[] array.
2419
+*/
2420
+
2421
+/*
2422
+** An instance of this object keeps track of the nesting of HTML
2423
+** elements for safe_html_append().
2424
+*/
2425
+typedef struct HtmlTagStack HtmlTagStack;
2426
+struct HtmlTagStack {
2427
+ int n; /* Current tag stack depth */
2428
+ int nAlloc; /* Space allocated for aStack[] */
2429
+ int *aStack; /* The stack of tags */
2430
+ int aSpace[10]; /* Initial static space, to avoid malloc() */
2431
+};
2432
+
2433
+/*
2434
+** Initialize bulk memory to a valid empty tagstack.
2435
+*/
2436
+static void html_tagstack_init(HtmlTagStack *p){
2437
+ p->n = 0;
2438
+ p->nAlloc = 0;
2439
+ p->aStack = p->aSpace;
2440
+}
2441
+
2442
+/*
2443
+** Push a new element onto the tag statk
2444
+*/
2445
+static void html_tagstack_push(HtmlTagStack *p, int e){
2446
+ if( p->n>=ArraySize(p->aSpace) && p->n>=p->nAlloc ){
2447
+ if( p->nAlloc==0 ){
2448
+ int *aNew;
2449
+ p->nAlloc = 50;
2450
+ aNew = fossil_malloc( sizeof(p->aStack[0])*p->nAlloc );
2451
+ memcpy(aNew, p->aStack, sizeof(p->aStack[0])*p->n );
2452
+ p->aStack = aNew;
2453
+ }else{
2454
+ p->nAlloc *= 2;
2455
+ p->aStack = fossil_realloc(p->aStack, sizeof(p->aStack[0])*p->nAlloc );
2456
+ }
2457
+ }
2458
+ p->aStack[p->n++] = e;
2459
+}
2460
+
2461
+/*
2462
+** Clear a tag stack, reclaiming any memory allocations.
2463
+*/
2464
+static void html_tagstack_clear(HtmlTagStack *p){
2465
+ if( p->nAlloc ){
2466
+ fossil_free(p->aStack);
2467
+ p->nAlloc = 0;
2468
+ p->aStack = p->aSpace;
2469
+ }
2470
+ p->n = 0;
2471
+}
2472
+
2473
+/*
2474
+** The HTML end-tag eEnd wants to be added to pBlob.
2475
+**
2476
+** If an open-tag for eEnd exists anywhere on the stack, then
2477
+** pop it and all prior elements from the task, issuing appropriate
2478
+** end-tags as you go.
2479
+**
2480
+** If there is no open-tag for eEnd on the stack, then this
2481
+** routine is a no-op.
2482
+*/
2483
+static void html_tagstack_pop(HtmlTagStack *p, Blob *pBlob, int eEnd){
2484
+ int i, e;
2485
+ if( eEnd!=0 ){
2486
+ for(i=p->n-1; i>=0 && p->aStack[i]!=eEnd; i--){}
2487
+ if( i<0 ){
2488
+ blob_appendf(pBlob, "<span class='error'>&lt;/%s&gt;</span>",
2489
+ aMarkup[eEnd].zName);
2490
+ return;
2491
+ }
2492
+ }else if( p->n==0 ){
2493
+ return;
2494
+ }
2495
+ do{
2496
+ e = p->aStack[--p->n];
2497
+ if( e==eEnd || (aMarkup[e].iType & MUTYPE_Nested)!=0 ){
2498
+ blob_appendf(pBlob, "</%s>", aMarkup[e].zName);
2499
+ }
2500
+ }while( e!=eEnd && p->n>0 );
2501
+}
2502
+
2503
+/*
2504
+** Append HTML text to a Blob object. The appended text is modified
2505
+** changed in the following ways:
2506
+**
2507
+** 1. Omit any elements that are not on the AllowedMarkup list.
2508
+**
2509
+** 2. Omit any attributes that are not on the AllowedMarkup list.
2510
+**
2511
+** 3. Omit any surplus close-tags. (This prevents a surplus </div>
2512
+** or </body> or similar element from interferring with formatting
2513
+** of the outer context in which the HTML is being inserted.)
2514
+**
2515
+** 4. Insert additional close-tags as necessary so that any
2516
+** tag in the input that needs a close-tag has one. (This prevents
2517
+** the inserted HTML from messing up the formatting of subsequent
2518
+** sections of the document into which it is being inserted.)
2519
+**
2520
+** The input must be writable. Temporary changes may be made to the
2521
+** input, but the input is restored to its original state prior to
2522
+** returning. If zHtml[nHtml] is not a zero character, then a zero
2523
+** might be written in that position temporarily, but that slot will
2524
+** also be restored before this routine returns.
2525
+*/
2526
+void safe_html_append(Blob *pBlob, char *zHtml, int nHtml){
2527
+ char cLast;
2528
+ int i, j, n;
2529
+ HtmlTagStack s;
2530
+ ParsedMarkup markup;
2531
+
2532
+ if( nHtml<=0 ) return;
2533
+ cLast = zHtml[nHtml];
2534
+ zHtml[nHtml] = 0;
2535
+ html_tagstack_init(&s);
2536
+
2537
+ i = 0;
2538
+ while( i<nHtml ){
2539
+ if( zHtml[i]=='<' ){
2540
+ j = i;
2541
+ }else{
2542
+ char *z = strchr(zHtml+i, '<');
2543
+ if( z==0 ){
2544
+ blob_append(pBlob, zHtml+i, nHtml-i);
2545
+ break;
2546
+ }
2547
+ j = (int)(z - zHtml);
2548
+ blob_append(pBlob, zHtml+i, j-i);
2549
+ }
2550
+ n = html_tag_length(zHtml+j);
2551
+ if( n==0 ){
2552
+ blob_append(pBlob, "&lt;", 4);
2553
+ i = j+1;
2554
+ continue;
2555
+ }else{
2556
+ i = j + n;
2557
+ }
2558
+ parseMarkup(&markup, zHtml+j);
2559
+ if( markup.iCode==MARKUP_INVALID ){
2560
+ blob_appendf(pBlob, "<span class='error'>&lt;%.*s&gt;</span>",
2561
+ n-2, zHtml+j+1);
2562
+ }else{
2563
+ if( markup.endTag ){
2564
+ html_tagstack_pop(&s, pBlob, markup.iCode);
2565
+ }else{
2566
+ renderMarkup(pBlob, &markup);
2567
+ html_tagstack_push(&s, markup.iCode);
2568
+ }
2569
+ }
2570
+ unparseMarkup(&markup);
2571
+ }
2572
+ html_tagstack_pop(&s, pBlob, 0);
2573
+ html_tagstack_clear(&s);
2574
+ zHtml[nHtml] = cLast;
2575
+}
2576
+
2577
+
2578
+/*
2579
+** COMMAND: test-safe-html
2580
+**
2581
+** Usage: %fossil test-safe-html FILE ...
2582
+**
2583
+** Read files named on the command-line. Send the text of each file
2584
+** through safe_html_append() and then write the result on
2585
+** standard output.
2586
+*/
2587
+void test_safe_html_cmd(void){
2588
+ int i;
2589
+ Blob x;
2590
+ Blob y;
2591
+ for(i=2; i<g.argc; i++){
2592
+ char *z;
2593
+ int n;
2594
+ blob_read_from_file(&x, g.argv[i], ExtFILE);
2595
+ blob_init(&y, 0, 0);
2596
+ blob_terminate(&x);
2597
+ safe_html_append(&y, blob_buffer(&x), blob_size(&x));
2598
+ blob_reset(&x);
2599
+ z = blob_str(&y);
2600
+ n = blob_size(&y);
2601
+ while( n>0 && (z[n-1]=='\n' || z[n-1]=='\r') ) n--;
2602
+ fossil_print("%.*s\n", n, z);
2603
+ blob_reset(&y);
2604
+ }
2605
+}
24012606
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -249,10 +249,13 @@
249 #define MUTYPE_TR 0x0080 /* <tr> */
250 #define MUTYPE_TD 0x0100 /* <td> or <th> */
251 #define MUTYPE_SPECIAL 0x0200 /* <nowiki> or <verbatim> */
252 #define MUTYPE_HYPERLINK 0x0400 /* <a> */
253
 
 
 
254 /*
255 ** These markup types must have an end tag.
256 */
257 #define MUTYPE_STACK (MUTYPE_BLOCK | MUTYPE_FONT | MUTYPE_LIST | MUTYPE_TABLE)
258
@@ -469,11 +472,11 @@
469 ** z points to a "<" character. Check to see if this is the start of
470 ** a valid markup. If it is, return the total number of characters in
471 ** the markup including the initial "<" and the terminating ">". If
472 ** it is not well-formed markup, return 0.
473 */
474 int htmlTagLength(const char *z){
475 int n = 1;
476 int inparen = 0;
477 int c;
478 if( z[n]=='/' ){ n++; }
479 if( !fossil_isalpha(z[n]) ) return 0;
@@ -656,11 +659,11 @@
656 ** characters in that token. Write the token type into *pTokenType.
657 */
658 static int nextWikiToken(const char *z, Renderer *p, int *pTokenType){
659 int n;
660 if( z[0]=='<' ){
661 n = htmlTagLength(z);
662 if( n>0 ){
663 *pTokenType = TOKEN_MARKUP;
664 return n;
665 }else{
666 *pTokenType = TOKEN_CHARACTER;
@@ -2026,11 +2029,11 @@
2026 */
2027 int html_token_length(const char *z){
2028 int n;
2029 char c;
2030 if( (c=z[0])=='<' ){
2031 n = htmlTagLength(z);
2032 if( n<=0 ) n = 1;
2033 }else if( fossil_isspace(c) ){
2034 for(n=1; z[n] && fossil_isspace(z[n]); n++){}
2035 }else if( c=='&' ){
2036 n = z[1]=='#' ? 2 : 1;
@@ -2396,5 +2399,207 @@
2396 blob_reset(&in);
2397 fossil_puts(blob_str(&out), 0);
2398 blob_reset(&out);
2399 }
2400 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2401
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -249,10 +249,13 @@
249 #define MUTYPE_TR 0x0080 /* <tr> */
250 #define MUTYPE_TD 0x0100 /* <td> or <th> */
251 #define MUTYPE_SPECIAL 0x0200 /* <nowiki> or <verbatim> */
252 #define MUTYPE_HYPERLINK 0x0400 /* <a> */
253
254 /* MUTYPE values for elements that require strictly nested end-tags */
255 #define MUTYPE_Nested 0x0656
256
257 /*
258 ** These markup types must have an end tag.
259 */
260 #define MUTYPE_STACK (MUTYPE_BLOCK | MUTYPE_FONT | MUTYPE_LIST | MUTYPE_TABLE)
261
@@ -469,11 +472,11 @@
472 ** z points to a "<" character. Check to see if this is the start of
473 ** a valid markup. If it is, return the total number of characters in
474 ** the markup including the initial "<" and the terminating ">". If
475 ** it is not well-formed markup, return 0.
476 */
477 int html_tag_length(const char *z){
478 int n = 1;
479 int inparen = 0;
480 int c;
481 if( z[n]=='/' ){ n++; }
482 if( !fossil_isalpha(z[n]) ) return 0;
@@ -656,11 +659,11 @@
659 ** characters in that token. Write the token type into *pTokenType.
660 */
661 static int nextWikiToken(const char *z, Renderer *p, int *pTokenType){
662 int n;
663 if( z[0]=='<' ){
664 n = html_tag_length(z);
665 if( n>0 ){
666 *pTokenType = TOKEN_MARKUP;
667 return n;
668 }else{
669 *pTokenType = TOKEN_CHARACTER;
@@ -2026,11 +2029,11 @@
2029 */
2030 int html_token_length(const char *z){
2031 int n;
2032 char c;
2033 if( (c=z[0])=='<' ){
2034 n = html_tag_length(z);
2035 if( n<=0 ) n = 1;
2036 }else if( fossil_isspace(c) ){
2037 for(n=1; z[n] && fossil_isspace(z[n]); n++){}
2038 }else if( c=='&' ){
2039 n = z[1]=='#' ? 2 : 1;
@@ -2396,5 +2399,207 @@
2399 blob_reset(&in);
2400 fossil_puts(blob_str(&out), 0);
2401 blob_reset(&out);
2402 }
2403 }
2404
2405 /****************************************************************************
2406 ** safe-html:
2407 **
2408 ** An interface for preventing HTML constructs (ex: <style>, <form>, etc)
2409 ** from being inserted into Wiki and Forum posts using Markdown. See the
2410 ** comment on safe_html_append() for additional information on what is meant
2411 ** by "safe".
2412 **
2413 ** The safe-html restrictions only apply to Markdown, as Fossil-Wiki only
2414 ** allows safe-html by design - unsafe-HTML is never and has never been
2415 ** allowed in Fossil-Wiki.
2416 **
2417 ** This code is in the wikiformat.c file so that it can have access to the
2418 ** white-list of acceptable HTML in the aMarkup[] array.
2419 */
2420
2421 /*
2422 ** An instance of this object keeps track of the nesting of HTML
2423 ** elements for safe_html_append().
2424 */
2425 typedef struct HtmlTagStack HtmlTagStack;
2426 struct HtmlTagStack {
2427 int n; /* Current tag stack depth */
2428 int nAlloc; /* Space allocated for aStack[] */
2429 int *aStack; /* The stack of tags */
2430 int aSpace[10]; /* Initial static space, to avoid malloc() */
2431 };
2432
2433 /*
2434 ** Initialize bulk memory to a valid empty tagstack.
2435 */
2436 static void html_tagstack_init(HtmlTagStack *p){
2437 p->n = 0;
2438 p->nAlloc = 0;
2439 p->aStack = p->aSpace;
2440 }
2441
2442 /*
2443 ** Push a new element onto the tag statk
2444 */
2445 static void html_tagstack_push(HtmlTagStack *p, int e){
2446 if( p->n>=ArraySize(p->aSpace) && p->n>=p->nAlloc ){
2447 if( p->nAlloc==0 ){
2448 int *aNew;
2449 p->nAlloc = 50;
2450 aNew = fossil_malloc( sizeof(p->aStack[0])*p->nAlloc );
2451 memcpy(aNew, p->aStack, sizeof(p->aStack[0])*p->n );
2452 p->aStack = aNew;
2453 }else{
2454 p->nAlloc *= 2;
2455 p->aStack = fossil_realloc(p->aStack, sizeof(p->aStack[0])*p->nAlloc );
2456 }
2457 }
2458 p->aStack[p->n++] = e;
2459 }
2460
2461 /*
2462 ** Clear a tag stack, reclaiming any memory allocations.
2463 */
2464 static void html_tagstack_clear(HtmlTagStack *p){
2465 if( p->nAlloc ){
2466 fossil_free(p->aStack);
2467 p->nAlloc = 0;
2468 p->aStack = p->aSpace;
2469 }
2470 p->n = 0;
2471 }
2472
2473 /*
2474 ** The HTML end-tag eEnd wants to be added to pBlob.
2475 **
2476 ** If an open-tag for eEnd exists anywhere on the stack, then
2477 ** pop it and all prior elements from the task, issuing appropriate
2478 ** end-tags as you go.
2479 **
2480 ** If there is no open-tag for eEnd on the stack, then this
2481 ** routine is a no-op.
2482 */
2483 static void html_tagstack_pop(HtmlTagStack *p, Blob *pBlob, int eEnd){
2484 int i, e;
2485 if( eEnd!=0 ){
2486 for(i=p->n-1; i>=0 && p->aStack[i]!=eEnd; i--){}
2487 if( i<0 ){
2488 blob_appendf(pBlob, "<span class='error'>&lt;/%s&gt;</span>",
2489 aMarkup[eEnd].zName);
2490 return;
2491 }
2492 }else if( p->n==0 ){
2493 return;
2494 }
2495 do{
2496 e = p->aStack[--p->n];
2497 if( e==eEnd || (aMarkup[e].iType & MUTYPE_Nested)!=0 ){
2498 blob_appendf(pBlob, "</%s>", aMarkup[e].zName);
2499 }
2500 }while( e!=eEnd && p->n>0 );
2501 }
2502
2503 /*
2504 ** Append HTML text to a Blob object. The appended text is modified
2505 ** changed in the following ways:
2506 **
2507 ** 1. Omit any elements that are not on the AllowedMarkup list.
2508 **
2509 ** 2. Omit any attributes that are not on the AllowedMarkup list.
2510 **
2511 ** 3. Omit any surplus close-tags. (This prevents a surplus </div>
2512 ** or </body> or similar element from interferring with formatting
2513 ** of the outer context in which the HTML is being inserted.)
2514 **
2515 ** 4. Insert additional close-tags as necessary so that any
2516 ** tag in the input that needs a close-tag has one. (This prevents
2517 ** the inserted HTML from messing up the formatting of subsequent
2518 ** sections of the document into which it is being inserted.)
2519 **
2520 ** The input must be writable. Temporary changes may be made to the
2521 ** input, but the input is restored to its original state prior to
2522 ** returning. If zHtml[nHtml] is not a zero character, then a zero
2523 ** might be written in that position temporarily, but that slot will
2524 ** also be restored before this routine returns.
2525 */
2526 void safe_html_append(Blob *pBlob, char *zHtml, int nHtml){
2527 char cLast;
2528 int i, j, n;
2529 HtmlTagStack s;
2530 ParsedMarkup markup;
2531
2532 if( nHtml<=0 ) return;
2533 cLast = zHtml[nHtml];
2534 zHtml[nHtml] = 0;
2535 html_tagstack_init(&s);
2536
2537 i = 0;
2538 while( i<nHtml ){
2539 if( zHtml[i]=='<' ){
2540 j = i;
2541 }else{
2542 char *z = strchr(zHtml+i, '<');
2543 if( z==0 ){
2544 blob_append(pBlob, zHtml+i, nHtml-i);
2545 break;
2546 }
2547 j = (int)(z - zHtml);
2548 blob_append(pBlob, zHtml+i, j-i);
2549 }
2550 n = html_tag_length(zHtml+j);
2551 if( n==0 ){
2552 blob_append(pBlob, "&lt;", 4);
2553 i = j+1;
2554 continue;
2555 }else{
2556 i = j + n;
2557 }
2558 parseMarkup(&markup, zHtml+j);
2559 if( markup.iCode==MARKUP_INVALID ){
2560 blob_appendf(pBlob, "<span class='error'>&lt;%.*s&gt;</span>",
2561 n-2, zHtml+j+1);
2562 }else{
2563 if( markup.endTag ){
2564 html_tagstack_pop(&s, pBlob, markup.iCode);
2565 }else{
2566 renderMarkup(pBlob, &markup);
2567 html_tagstack_push(&s, markup.iCode);
2568 }
2569 }
2570 unparseMarkup(&markup);
2571 }
2572 html_tagstack_pop(&s, pBlob, 0);
2573 html_tagstack_clear(&s);
2574 zHtml[nHtml] = cLast;
2575 }
2576
2577
2578 /*
2579 ** COMMAND: test-safe-html
2580 **
2581 ** Usage: %fossil test-safe-html FILE ...
2582 **
2583 ** Read files named on the command-line. Send the text of each file
2584 ** through safe_html_append() and then write the result on
2585 ** standard output.
2586 */
2587 void test_safe_html_cmd(void){
2588 int i;
2589 Blob x;
2590 Blob y;
2591 for(i=2; i<g.argc; i++){
2592 char *z;
2593 int n;
2594 blob_read_from_file(&x, g.argv[i], ExtFILE);
2595 blob_init(&y, 0, 0);
2596 blob_terminate(&x);
2597 safe_html_append(&y, blob_buffer(&x), blob_size(&x));
2598 blob_reset(&x);
2599 z = blob_str(&y);
2600 n = blob_size(&y);
2601 while( n>0 && (z[n-1]=='\n' || z[n-1]=='\r') ) n--;
2602 fossil_print("%.*s\n", n, z);
2603 blob_reset(&y);
2604 }
2605 }
2606
--- www/server/debian/nginx.md
+++ www/server/debian/nginx.md
@@ -109,19 +109,15 @@
109109
110110
## <a name="scgi"></a>Running Fossil in SCGI Mode
111111
112112
For the following nginx configuration to work, it needs to contact a
113113
Fossil instance speaking the SCGI protocol. There are [many ways](../)
114
-to set that up. For Debian type systems, we primarily recommend
115
-following [our systemd user service guide](service.md).
116
-
117
-Another option would be to customize [the `fslsrv` shell
118
-script](/file/tools/fslsrv) that ships with Fossil as an example of
119
-launching multiple Fossil instances in the background to serve multiple
120
-URLs.
121
-
122
-However you do it, you need to match up the TCP port numbers between it
114
+to set that up. For Debian type systems, we recommend
115
+following [our systemd system service guide](service.md).
116
+
117
+There are other ways to arrange for Fossil to run as a service backing
118
+nginx, but however you do it, you need to match up the TCP port numbers between it
123119
and those in the nginx configuration below.
124120
125121
126122
## <a name="config"></a>Configuration
127123
128124
--- www/server/debian/nginx.md
+++ www/server/debian/nginx.md
@@ -109,19 +109,15 @@
109
110 ## <a name="scgi"></a>Running Fossil in SCGI Mode
111
112 For the following nginx configuration to work, it needs to contact a
113 Fossil instance speaking the SCGI protocol. There are [many ways](../)
114 to set that up. For Debian type systems, we primarily recommend
115 following [our systemd user service guide](service.md).
116
117 Another option would be to customize [the `fslsrv` shell
118 script](/file/tools/fslsrv) that ships with Fossil as an example of
119 launching multiple Fossil instances in the background to serve multiple
120 URLs.
121
122 However you do it, you need to match up the TCP port numbers between it
123 and those in the nginx configuration below.
124
125
126 ## <a name="config"></a>Configuration
127
128
--- www/server/debian/nginx.md
+++ www/server/debian/nginx.md
@@ -109,19 +109,15 @@
109
110 ## <a name="scgi"></a>Running Fossil in SCGI Mode
111
112 For the following nginx configuration to work, it needs to contact a
113 Fossil instance speaking the SCGI protocol. There are [many ways](../)
114 to set that up. For Debian type systems, we recommend
115 following [our systemd system service guide](service.md).
116
117 There are other ways to arrange for Fossil to run as a service backing
118 nginx, but however you do it, you need to match up the TCP port numbers between it
 
 
 
 
119 and those in the nginx configuration below.
120
121
122 ## <a name="config"></a>Configuration
123
124
--- www/server/debian/service.md
+++ www/server/debian/service.md
@@ -43,17 +43,23 @@
4343
WantedBy=sockets.target
4444
WantedBy=multi-user.target
4545
```
4646
4747
Unlike with `inetd` and `xinetd`, we don’t need to tell `systemd` which
48
-user and group to run this service as, because we’ve installed it as a
49
-user service under the account we’re logged into.
48
+user and group to run this service as, because we’ve installed it
49
+under the account we’re logged into, which `systemd` will use as the
50
+service’s owner.
5051
5152
We’ve told `systemd` that we want automatic service restarts with
5253
back-off logic, making this much more robust than the by-hand launches
5354
of `fossil` in the platform-independent Fossil server instructions. The
5455
service will stay up until we explicitly tell it to shut down.
56
+
57
+A simple and useful modification to the above scheme is to add the
58
+`--scgi` and `--localhost` flags to the `ExecStart` line to replace the
59
+use of `fslsrv` in [the generic SCGI instructions](../any/scgi.md),
60
+giving a much more robust configuration.
5561
5662
Because we’ve set this up as a user service, the commands you give to
5763
manipulate the service vary somewhat from the sort you’re more likely to
5864
find online:
5965
@@ -69,14 +75,40 @@
6975
7076
This scheme isolates the permissions needed by the Fossil server, which
7177
reduces the amount of damage it can do if there is ever a
7278
remotely-triggerable security flaw found in Fossil.
7379
74
-A simple and useful modification to the above scheme is to add the
75
-`--scgi` and `--localhost` flags to the `ExecStart` line to replace the
76
-use of `fslsrv` in [the generic SCGI instructions](../any/scgi.md),
77
-giving a much more robust configuration.
80
+On some `systemd` based OSes, user services only run while that user is
81
+logged in interactively. This is common on systems aiming to provide
82
+desktop environments, where this is the behavior you often want. To
83
+allow background services to continue to run after logout, say:
84
+
85
+ $ sudo loginctl enable-linger $USER
86
+
87
+You can paste the command just like that into your terminal, since
88
+`$USER` will expand to your login name.
89
+
90
+
91
+
92
+### System Service Alternative
93
+
94
+Another workaround for the problem with user services above is to
95
+install the service as a system service instead. This is a better path
96
+when you are proxying Fossil with a system-level service, such as
97
+[nginx](./nginx.md).
98
+
99
+There are just a small set of changes required:
100
+
101
+1. Install the unit file to one of the persistent system-level unit
102
+ file directories. Typically, these are:
103
+
104
+ /etc/systemd/system
105
+ /lib/systemd/system
106
+
107
+2. Add `User` and `Group` directives to the `[Service]` section so
108
+ Fossil runs as a normal user, preferrably one with access only to
109
+ the Fossil repo files, rather than running as `root`.
78110
79111
80112
## Socket Activation
81113
82114
Another useful method to serve a Fossil repo via `systemd` is via a
83115
--- www/server/debian/service.md
+++ www/server/debian/service.md
@@ -43,17 +43,23 @@
43 WantedBy=sockets.target
44 WantedBy=multi-user.target
45 ```
46
47 Unlike with `inetd` and `xinetd`, we don’t need to tell `systemd` which
48 user and group to run this service as, because we’ve installed it as a
49 user service under the account we’re logged into.
 
50
51 We’ve told `systemd` that we want automatic service restarts with
52 back-off logic, making this much more robust than the by-hand launches
53 of `fossil` in the platform-independent Fossil server instructions. The
54 service will stay up until we explicitly tell it to shut down.
 
 
 
 
 
55
56 Because we’ve set this up as a user service, the commands you give to
57 manipulate the service vary somewhat from the sort you’re more likely to
58 find online:
59
@@ -69,14 +75,40 @@
69
70 This scheme isolates the permissions needed by the Fossil server, which
71 reduces the amount of damage it can do if there is ever a
72 remotely-triggerable security flaw found in Fossil.
73
74 A simple and useful modification to the above scheme is to add the
75 `--scgi` and `--localhost` flags to the `ExecStart` line to replace the
76 use of `fslsrv` in [the generic SCGI instructions](../any/scgi.md),
77 giving a much more robust configuration.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
79
80 ## Socket Activation
81
82 Another useful method to serve a Fossil repo via `systemd` is via a
83
--- www/server/debian/service.md
+++ www/server/debian/service.md
@@ -43,17 +43,23 @@
43 WantedBy=sockets.target
44 WantedBy=multi-user.target
45 ```
46
47 Unlike with `inetd` and `xinetd`, we don’t need to tell `systemd` which
48 user and group to run this service as, because we’ve installed it
49 under the account we’re logged into, which `systemd` will use as the
50 service’s owner.
51
52 We’ve told `systemd` that we want automatic service restarts with
53 back-off logic, making this much more robust than the by-hand launches
54 of `fossil` in the platform-independent Fossil server instructions. The
55 service will stay up until we explicitly tell it to shut down.
56
57 A simple and useful modification to the above scheme is to add the
58 `--scgi` and `--localhost` flags to the `ExecStart` line to replace the
59 use of `fslsrv` in [the generic SCGI instructions](../any/scgi.md),
60 giving a much more robust configuration.
61
62 Because we’ve set this up as a user service, the commands you give to
63 manipulate the service vary somewhat from the sort you’re more likely to
64 find online:
65
@@ -69,14 +75,40 @@
75
76 This scheme isolates the permissions needed by the Fossil server, which
77 reduces the amount of damage it can do if there is ever a
78 remotely-triggerable security flaw found in Fossil.
79
80 On some `systemd` based OSes, user services only run while that user is
81 logged in interactively. This is common on systems aiming to provide
82 desktop environments, where this is the behavior you often want. To
83 allow background services to continue to run after logout, say:
84
85 $ sudo loginctl enable-linger $USER
86
87 You can paste the command just like that into your terminal, since
88 `$USER` will expand to your login name.
89
90
91
92 ### System Service Alternative
93
94 Another workaround for the problem with user services above is to
95 install the service as a system service instead. This is a better path
96 when you are proxying Fossil with a system-level service, such as
97 [nginx](./nginx.md).
98
99 There are just a small set of changes required:
100
101 1. Install the unit file to one of the persistent system-level unit
102 file directories. Typically, these are:
103
104 /etc/systemd/system
105 /lib/systemd/system
106
107 2. Add `User` and `Group` directives to the `[Service]` section so
108 Fossil runs as a normal user, preferrably one with access only to
109 the Fossil repo files, rather than running as `root`.
110
111
112 ## Socket Activation
113
114 Another useful method to serve a Fossil repo via `systemd` is via a
115
+25 -34
--- www/webpage-ex.md
+++ www/webpage-ex.md
@@ -2,112 +2,103 @@
22
=================
33
44
Here are just a few examples of the many web pages supported
55
by Fossil. Follow hyperlinks on the examples below to see many
66
other examples.
7
-<style>
8
-.exbtn {
9
- border: 1px solid #000;
10
- margin: 1ex;
11
- border-radius: 1ex;
12
- padding: 0 1ex;
13
- background-color: #eee;
14
-}
15
-</style>
167
178
* <a target='_blank' class='exbtn'
18
- href='$ROOT/timeline?y=ci&n=100'>Example</a>
9
+ href='$ROOT/timeline?y=ci&n=100'>(Example)</a> &rarr;
1910
100 most recent check-ins.
2011
2112
* <a target='_blank' class='exbtn'
22
- href='$ROOT/finfo?name=src/file.c'>Example</a>
13
+ href='$ROOT/finfo?name=src/file.c'>(Example)</a> &rarr;
2314
All changes to the <b>src/file.c</b> source file.
2415
2516
* <a target='_blank' class='exbtn'
26
- href='$ROOT/timeline?n=200&uf=0c3c2d086a'>Example</a>
17
+ href='$ROOT/timeline?n=200&uf=0c3c2d086a'>(Example)</a> &rarr;
2718
All check-ins using a particular version of the <b>src/file.c</b>
2819
source file.
2920
3021
* <a target='_blank' class='exbtn'
31
- href='$ROOT/timeline?n=11&y=ci&c=2014-01-01'>Example</a>
22
+ href='$ROOT/timeline?n=11&y=ci&c=2014-01-01'>(Example)</a> &rarr;
3223
Check-ins proximate to an historical point in time (2014-01-01).
3324
3425
* <a target='_blank' class='exbtn'
35
- href='$ROOT/timeline?n=11&y=ci&c=2014-01-01&v=1'>Example</a>
26
+ href='$ROOT/timeline?n=11&y=ci&c=2014-01-01&v=1'>(Example)</a> &rarr;
3627
The previous example augmented with file changes.
3728
3829
* <a target='_blank' class='exbtn'
39
- href='$ROOT/timeline?n=25&y=ci&a=1970-01-01'>Example</a>
30
+ href='$ROOT/timeline?n=25&y=ci&a=1970-01-01'>(Example)</a> &rarr;
4031
First 25 check-ins after 1970-01-01. (The first 25 check-ins of
4132
the project.)
4233
4334
* <a target='_blank' class='exbtn'
44
- href='$ROOT/timeline?n=200&r=svn-import'>Example</a>
35
+ href='$ROOT/timeline?n=200&r=svn-import'>(Example)</a> &rarr;
4536
All check-ins of the "svn-import" branch together with check-ins
4637
that merge with that branch.
4738
4839
* <a target='_blank' class='exbtn'
49
- href='$ROOT/timeline?n=200&t=svn-import'>Example</a>
40
+ href='$ROOT/timeline?n=200&t=svn-import'>(Example)</a> &rarr;
5041
All check-ins of the "svn-import" branch only.
5142
5243
* <a target='_blank' class='exbtn'
53
- href='$ROOT/timeline?n=100&y=ci&ubg'>Example</a>
44
+ href='$ROOT/timeline?n=100&y=ci&ubg'>(Example)</a> &rarr;
5445
100 most recent check-ins color coded by committer rather than by branch.
5546
5647
* <a target='_blank' class='exbtn'
57
- href='$ROOT/timeline?from=version-1.27&to=version-1.28'>Example</a>
48
+ href='$ROOT/timeline?from=version-1.27&to=version-1.28'>(Example)</a> &rarr;
5849
All check-ins on the most direct path from
5950
version-1.27 to version-1.28
6051
6152
* <a target='_blank' class='exbtn'
62
- href='$ROOT/timeline?namechng'>Example</a>
53
+ href='$ROOT/timeline?namechng'>(Example)</a> &rarr;
6354
Show check-ins that contain file name changes
6455
6556
* <a target='_blank' class='exbtn'
66
- href='$ROOT/timeline?u=drh&c=2014-01-08&y=ci'>Example</a>
57
+ href='$ROOT/timeline?u=drh&c=2014-01-08&y=ci'>(Example)</a> &rarr;
6758
Show check-ins circa 2014-01-08 by user "drh".
6859
6960
* <a target='_blank' class='exbtn'
70
- href='$ROOT/timeline?from=version-1.34&to=version-1.35&chng=src/timeline.c,src/doc.c'>Example</a>
61
+ href='$ROOT/timeline?from=version-1.34&to=version-1.35&chng=src/timeline.c,src/doc.c'>(Example)</a> &rarr;
7162
Show all check-ins between version-1.34 and version-1.35 that make
7263
changes to either of the files src/timeline.c or src/doc.c.
7364
7465
<big><b>&rarr;</b></big> (Hint: In the pages above, click the graph nodes
7566
for any two check-ins or files to see a diff.)
7667
<big><b>&larr;</b></big>
7768
7869
* <a target='_blank' class='exbtn'
79
- href='$ROOT/search?s=interesting+pages'>Example</a>
70
+ href='$ROOT/search?s=interesting+pages'>(Example)</a> &rarr;
8071
Full-text search for "interesting pages".
8172
8273
* <a target='_blank' class='exbtn'
83
- href='$ROOT/tree?ci=daff9d20621&type=tree'>Example</a>
74
+ href='$ROOT/tree?ci=daff9d20621&type=tree'>(Example)</a> &rarr;
8475
All files for a particular check-in (daff9d20621480)
8576
8677
* <a target='_blank' class='exbtn'
87
- href='$ROOT/tree?ci=trunk&type=tree&mtime=1'>Example</a>
78
+ href='$ROOT/tree?ci=trunk&type=tree&mtime=1'>(Example)</a> &rarr;
8879
All files for the latest check-in on a branch (trunk) sorted by
8980
last modification time.
9081
9182
* <a target='_blank' class='exbtn'
92
- href='$ROOT/fileage?name=svn-import'>Example</a>
83
+ href='$ROOT/fileage?name=svn-import'>(Example)</a> &rarr;
9384
Age of all files in the latest checking for branch "svn-import".
9485
9586
* <a target='_blank' class='exbtn'
96
- href='$ROOT/brlist'>Example</a>
87
+ href='$ROOT/brlist'>(Example)</a> &rarr;
9788
Table of branches. (Click on column headers to sort.)
9889
9990
* <a target='_blank' class='exbtn'
100
- href='$ROOT/stat'>Example</a>
91
+ href='$ROOT/stat'>(Example)</a> &rarr;
10192
Overall repository status.
10293
10394
* <a target='_blank' class='exbtn'
104
- href='$ROOT/reports?type=ci&view=byuser'>Example</a>
95
+ href='$ROOT/reports?type=ci&view=byuser'>(Example)</a> &rarr;
10596
Number of check-ins per committer.
10697
10798
* <a target='_blank' class='exbtn'
108
- href='$ROOT/reports?view=byfile'>Example</a>
99
+ href='$ROOT/reports?view=byfile'>(Example)</a> &rarr;
109100
Number of check-ins for each source file.
110101
(Click on column headers to sort.)
111102
112103
* <a target='_blank' class='exbtn'
113104
href='$ROOT/blame?checkin=5260fbf63287&filename=src/rss.c&limit=-1'>
@@ -114,19 +105,19 @@
114105
Example</a>
115106
Most recent change to each line of a particular source file in a
116107
particular check-in.
117108
118109
* <a target='_blank' class='exbtn'
119
- href='$ROOT/taglist'>Example</a>
110
+ href='$ROOT/taglist'>(Example)</a> &rarr;
120111
List of tags on check-ins.
121112
122113
* <a target='_blank' class='exbtn'
123
- href='$ROOT/bigbloblist'>Example</a>
114
+ href='$ROOT/bigbloblist'>(Example)</a> &rarr;
124115
The largest objects in the repository.
125116
126117
* <a target='_blank' class='exbtn'
127
- href='$ROOT/hash-collisions'>Example</a>
118
+ href='$ROOT/hash-collisions'>(Example)</a> &rarr;
128119
Hash prefix collisions
129120
130121
* <a target='_blank' class='exbtn'
131
- href='$ROOT/sitemap'>Example</a>
122
+ href='$ROOT/sitemap'>(Example)</a> &rarr;
132123
The "sitemap" containing links to many other pages
133124
--- www/webpage-ex.md
+++ www/webpage-ex.md
@@ -2,112 +2,103 @@
2 =================
3
4 Here are just a few examples of the many web pages supported
5 by Fossil. Follow hyperlinks on the examples below to see many
6 other examples.
7 <style>
8 .exbtn {
9 border: 1px solid #000;
10 margin: 1ex;
11 border-radius: 1ex;
12 padding: 0 1ex;
13 background-color: #eee;
14 }
15 </style>
16
17 * <a target='_blank' class='exbtn'
18 href='$ROOT/timeline?y=ci&n=100'>Example</a>
19 100 most recent check-ins.
20
21 * <a target='_blank' class='exbtn'
22 href='$ROOT/finfo?name=src/file.c'>Example</a>
23 All changes to the <b>src/file.c</b> source file.
24
25 * <a target='_blank' class='exbtn'
26 href='$ROOT/timeline?n=200&uf=0c3c2d086a'>Example</a>
27 All check-ins using a particular version of the <b>src/file.c</b>
28 source file.
29
30 * <a target='_blank' class='exbtn'
31 href='$ROOT/timeline?n=11&y=ci&c=2014-01-01'>Example</a>
32 Check-ins proximate to an historical point in time (2014-01-01).
33
34 * <a target='_blank' class='exbtn'
35 href='$ROOT/timeline?n=11&y=ci&c=2014-01-01&v=1'>Example</a>
36 The previous example augmented with file changes.
37
38 * <a target='_blank' class='exbtn'
39 href='$ROOT/timeline?n=25&y=ci&a=1970-01-01'>Example</a>
40 First 25 check-ins after 1970-01-01. (The first 25 check-ins of
41 the project.)
42
43 * <a target='_blank' class='exbtn'
44 href='$ROOT/timeline?n=200&r=svn-import'>Example</a>
45 All check-ins of the "svn-import" branch together with check-ins
46 that merge with that branch.
47
48 * <a target='_blank' class='exbtn'
49 href='$ROOT/timeline?n=200&t=svn-import'>Example</a>
50 All check-ins of the "svn-import" branch only.
51
52 * <a target='_blank' class='exbtn'
53 href='$ROOT/timeline?n=100&y=ci&ubg'>Example</a>
54 100 most recent check-ins color coded by committer rather than by branch.
55
56 * <a target='_blank' class='exbtn'
57 href='$ROOT/timeline?from=version-1.27&to=version-1.28'>Example</a>
58 All check-ins on the most direct path from
59 version-1.27 to version-1.28
60
61 * <a target='_blank' class='exbtn'
62 href='$ROOT/timeline?namechng'>Example</a>
63 Show check-ins that contain file name changes
64
65 * <a target='_blank' class='exbtn'
66 href='$ROOT/timeline?u=drh&c=2014-01-08&y=ci'>Example</a>
67 Show check-ins circa 2014-01-08 by user "drh".
68
69 * <a target='_blank' class='exbtn'
70 href='$ROOT/timeline?from=version-1.34&to=version-1.35&chng=src/timeline.c,src/doc.c'>Example</a>
71 Show all check-ins between version-1.34 and version-1.35 that make
72 changes to either of the files src/timeline.c or src/doc.c.
73
74 <big><b>&rarr;</b></big> (Hint: In the pages above, click the graph nodes
75 for any two check-ins or files to see a diff.)
76 <big><b>&larr;</b></big>
77
78 * <a target='_blank' class='exbtn'
79 href='$ROOT/search?s=interesting+pages'>Example</a>
80 Full-text search for "interesting pages".
81
82 * <a target='_blank' class='exbtn'
83 href='$ROOT/tree?ci=daff9d20621&type=tree'>Example</a>
84 All files for a particular check-in (daff9d20621480)
85
86 * <a target='_blank' class='exbtn'
87 href='$ROOT/tree?ci=trunk&type=tree&mtime=1'>Example</a>
88 All files for the latest check-in on a branch (trunk) sorted by
89 last modification time.
90
91 * <a target='_blank' class='exbtn'
92 href='$ROOT/fileage?name=svn-import'>Example</a>
93 Age of all files in the latest checking for branch "svn-import".
94
95 * <a target='_blank' class='exbtn'
96 href='$ROOT/brlist'>Example</a>
97 Table of branches. (Click on column headers to sort.)
98
99 * <a target='_blank' class='exbtn'
100 href='$ROOT/stat'>Example</a>
101 Overall repository status.
102
103 * <a target='_blank' class='exbtn'
104 href='$ROOT/reports?type=ci&view=byuser'>Example</a>
105 Number of check-ins per committer.
106
107 * <a target='_blank' class='exbtn'
108 href='$ROOT/reports?view=byfile'>Example</a>
109 Number of check-ins for each source file.
110 (Click on column headers to sort.)
111
112 * <a target='_blank' class='exbtn'
113 href='$ROOT/blame?checkin=5260fbf63287&filename=src/rss.c&limit=-1'>
@@ -114,19 +105,19 @@
114 Example</a>
115 Most recent change to each line of a particular source file in a
116 particular check-in.
117
118 * <a target='_blank' class='exbtn'
119 href='$ROOT/taglist'>Example</a>
120 List of tags on check-ins.
121
122 * <a target='_blank' class='exbtn'
123 href='$ROOT/bigbloblist'>Example</a>
124 The largest objects in the repository.
125
126 * <a target='_blank' class='exbtn'
127 href='$ROOT/hash-collisions'>Example</a>
128 Hash prefix collisions
129
130 * <a target='_blank' class='exbtn'
131 href='$ROOT/sitemap'>Example</a>
132 The "sitemap" containing links to many other pages
133
--- www/webpage-ex.md
+++ www/webpage-ex.md
@@ -2,112 +2,103 @@
2 =================
3
4 Here are just a few examples of the many web pages supported
5 by Fossil. Follow hyperlinks on the examples below to see many
6 other examples.
 
 
 
 
 
 
 
 
 
7
8 * <a target='_blank' class='exbtn'
9 href='$ROOT/timeline?y=ci&n=100'>(Example)</a> &rarr;
10 100 most recent check-ins.
11
12 * <a target='_blank' class='exbtn'
13 href='$ROOT/finfo?name=src/file.c'>(Example)</a> &rarr;
14 All changes to the <b>src/file.c</b> source file.
15
16 * <a target='_blank' class='exbtn'
17 href='$ROOT/timeline?n=200&uf=0c3c2d086a'>(Example)</a> &rarr;
18 All check-ins using a particular version of the <b>src/file.c</b>
19 source file.
20
21 * <a target='_blank' class='exbtn'
22 href='$ROOT/timeline?n=11&y=ci&c=2014-01-01'>(Example)</a> &rarr;
23 Check-ins proximate to an historical point in time (2014-01-01).
24
25 * <a target='_blank' class='exbtn'
26 href='$ROOT/timeline?n=11&y=ci&c=2014-01-01&v=1'>(Example)</a> &rarr;
27 The previous example augmented with file changes.
28
29 * <a target='_blank' class='exbtn'
30 href='$ROOT/timeline?n=25&y=ci&a=1970-01-01'>(Example)</a> &rarr;
31 First 25 check-ins after 1970-01-01. (The first 25 check-ins of
32 the project.)
33
34 * <a target='_blank' class='exbtn'
35 href='$ROOT/timeline?n=200&r=svn-import'>(Example)</a> &rarr;
36 All check-ins of the "svn-import" branch together with check-ins
37 that merge with that branch.
38
39 * <a target='_blank' class='exbtn'
40 href='$ROOT/timeline?n=200&t=svn-import'>(Example)</a> &rarr;
41 All check-ins of the "svn-import" branch only.
42
43 * <a target='_blank' class='exbtn'
44 href='$ROOT/timeline?n=100&y=ci&ubg'>(Example)</a> &rarr;
45 100 most recent check-ins color coded by committer rather than by branch.
46
47 * <a target='_blank' class='exbtn'
48 href='$ROOT/timeline?from=version-1.27&to=version-1.28'>(Example)</a> &rarr;
49 All check-ins on the most direct path from
50 version-1.27 to version-1.28
51
52 * <a target='_blank' class='exbtn'
53 href='$ROOT/timeline?namechng'>(Example)</a> &rarr;
54 Show check-ins that contain file name changes
55
56 * <a target='_blank' class='exbtn'
57 href='$ROOT/timeline?u=drh&c=2014-01-08&y=ci'>(Example)</a> &rarr;
58 Show check-ins circa 2014-01-08 by user "drh".
59
60 * <a target='_blank' class='exbtn'
61 href='$ROOT/timeline?from=version-1.34&to=version-1.35&chng=src/timeline.c,src/doc.c'>(Example)</a> &rarr;
62 Show all check-ins between version-1.34 and version-1.35 that make
63 changes to either of the files src/timeline.c or src/doc.c.
64
65 <big><b>&rarr;</b></big> (Hint: In the pages above, click the graph nodes
66 for any two check-ins or files to see a diff.)
67 <big><b>&larr;</b></big>
68
69 * <a target='_blank' class='exbtn'
70 href='$ROOT/search?s=interesting+pages'>(Example)</a> &rarr;
71 Full-text search for "interesting pages".
72
73 * <a target='_blank' class='exbtn'
74 href='$ROOT/tree?ci=daff9d20621&type=tree'>(Example)</a> &rarr;
75 All files for a particular check-in (daff9d20621480)
76
77 * <a target='_blank' class='exbtn'
78 href='$ROOT/tree?ci=trunk&type=tree&mtime=1'>(Example)</a> &rarr;
79 All files for the latest check-in on a branch (trunk) sorted by
80 last modification time.
81
82 * <a target='_blank' class='exbtn'
83 href='$ROOT/fileage?name=svn-import'>(Example)</a> &rarr;
84 Age of all files in the latest checking for branch "svn-import".
85
86 * <a target='_blank' class='exbtn'
87 href='$ROOT/brlist'>(Example)</a> &rarr;
88 Table of branches. (Click on column headers to sort.)
89
90 * <a target='_blank' class='exbtn'
91 href='$ROOT/stat'>(Example)</a> &rarr;
92 Overall repository status.
93
94 * <a target='_blank' class='exbtn'
95 href='$ROOT/reports?type=ci&view=byuser'>(Example)</a> &rarr;
96 Number of check-ins per committer.
97
98 * <a target='_blank' class='exbtn'
99 href='$ROOT/reports?view=byfile'>(Example)</a> &rarr;
100 Number of check-ins for each source file.
101 (Click on column headers to sort.)
102
103 * <a target='_blank' class='exbtn'
104 href='$ROOT/blame?checkin=5260fbf63287&filename=src/rss.c&limit=-1'>
@@ -114,19 +105,19 @@
105 Example</a>
106 Most recent change to each line of a particular source file in a
107 particular check-in.
108
109 * <a target='_blank' class='exbtn'
110 href='$ROOT/taglist'>(Example)</a> &rarr;
111 List of tags on check-ins.
112
113 * <a target='_blank' class='exbtn'
114 href='$ROOT/bigbloblist'>(Example)</a> &rarr;
115 The largest objects in the repository.
116
117 * <a target='_blank' class='exbtn'
118 href='$ROOT/hash-collisions'>(Example)</a> &rarr;
119 Hash prefix collisions
120
121 * <a target='_blank' class='exbtn'
122 href='$ROOT/sitemap'>(Example)</a> &rarr;
123 The "sitemap" containing links to many other pages
124

Keyboard Shortcuts

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