Fossil SCM

An attepmt to fix the [https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base|<code><base href="..."></code>] element of webpages so that the value of <var>href</var> attribute matches the URL being served. This should fix "#fragment" hyperlinks on all pages where these were broken (all except [/help?cmd=/doc|<code>/doc</code>]). The values for [/help?cmd=/wiki|<code>/wiki</code>] and [/help?cmd=/info|<code>/info</code>] were left unchanged (it's yet unclear if they should also be changed).

george 2022-02-12 19:53 trunk
Commit 03b39f1d00ce06e67ee83ca92116e6f9daaf67988bdea07893b524fadb770691
+3
--- src/info.c
+++ src/info.c
@@ -1432,10 +1432,11 @@
14321432
}else{
14331433
@ <li>File
14341434
if( bNeedBase ){
14351435
bNeedBase = 0;
14361436
style_set_current_page("doc/%S/%s",zVers,zName);
1437
+ style_set_base_href_suffix("doc/%S/%s",zVers,zName);
14371438
}
14381439
}
14391440
objType |= OBJTYPE_CONTENT;
14401441
@ %z(href("%R/finfo?name=%T&ci=%!S&m=%!S",zName,zVers,zUuid))\
14411442
@ %h(zName)</a>
@@ -2574,13 +2575,15 @@
25742575
25752576
if( isFile ){
25762577
if( isSymbolicCI ){
25772578
zHeader = mprintf("%s at %s", file_tail(zName), zCI);
25782579
style_set_current_page("doc/%t/%T", zCI, zName);
2580
+ style_set_base_href_suffix("doc/%t/%T", zCI, zName);
25792581
}else if( zCIUuid && zCIUuid[0] ){
25802582
zHeader = mprintf("%s at [%S]", file_tail(zName), zCIUuid);
25812583
style_set_current_page("doc/%S/%T", zCIUuid, zName);
2584
+ style_set_base_href_suffix("doc/%S/%T", zCIUuid, zName);
25822585
}else{
25832586
zHeader = mprintf("%s", file_tail(zName));
25842587
style_set_current_page("doc/tip/%T", zName);
25852588
}
25862589
}else if( descOnly ){
25872590
--- src/info.c
+++ src/info.c
@@ -1432,10 +1432,11 @@
1432 }else{
1433 @ <li>File
1434 if( bNeedBase ){
1435 bNeedBase = 0;
1436 style_set_current_page("doc/%S/%s",zVers,zName);
 
1437 }
1438 }
1439 objType |= OBJTYPE_CONTENT;
1440 @ %z(href("%R/finfo?name=%T&ci=%!S&m=%!S",zName,zVers,zUuid))\
1441 @ %h(zName)</a>
@@ -2574,13 +2575,15 @@
2574
2575 if( isFile ){
2576 if( isSymbolicCI ){
2577 zHeader = mprintf("%s at %s", file_tail(zName), zCI);
2578 style_set_current_page("doc/%t/%T", zCI, zName);
 
2579 }else if( zCIUuid && zCIUuid[0] ){
2580 zHeader = mprintf("%s at [%S]", file_tail(zName), zCIUuid);
2581 style_set_current_page("doc/%S/%T", zCIUuid, zName);
 
2582 }else{
2583 zHeader = mprintf("%s", file_tail(zName));
2584 style_set_current_page("doc/tip/%T", zName);
2585 }
2586 }else if( descOnly ){
2587
--- src/info.c
+++ src/info.c
@@ -1432,10 +1432,11 @@
1432 }else{
1433 @ <li>File
1434 if( bNeedBase ){
1435 bNeedBase = 0;
1436 style_set_current_page("doc/%S/%s",zVers,zName);
1437 style_set_base_href_suffix("doc/%S/%s",zVers,zName);
1438 }
1439 }
1440 objType |= OBJTYPE_CONTENT;
1441 @ %z(href("%R/finfo?name=%T&ci=%!S&m=%!S",zName,zVers,zUuid))\
1442 @ %h(zName)</a>
@@ -2574,13 +2575,15 @@
2575
2576 if( isFile ){
2577 if( isSymbolicCI ){
2578 zHeader = mprintf("%s at %s", file_tail(zName), zCI);
2579 style_set_current_page("doc/%t/%T", zCI, zName);
2580 style_set_base_href_suffix("doc/%t/%T", zCI, zName);
2581 }else if( zCIUuid && zCIUuid[0] ){
2582 zHeader = mprintf("%s at [%S]", file_tail(zName), zCIUuid);
2583 style_set_current_page("doc/%S/%T", zCIUuid, zName);
2584 style_set_base_href_suffix("doc/%S/%T", zCIUuid, zName);
2585 }else{
2586 zHeader = mprintf("%s", file_tail(zName));
2587 style_set_current_page("doc/tip/%T", zName);
2588 }
2589 }else if( descOnly ){
2590
+14 -1
--- src/main.c
+++ src/main.c
@@ -178,11 +178,13 @@
178178
const char *zHttpCmd; /* External program to do HTTP requests */
179179
int fNoSync; /* Do not do an autosync ever. --nosync */
180180
int fIPv4; /* Use only IPv4, not IPv6. --ipv4 */
181181
char *zPath; /* Name of webpage being served */
182182
char *zExtra; /* Extra path information past the webpage name */
183
- char *zBaseURL; /* Full text of the URL being served */
183
+ char *zBaseURL; /* Full URL for the toplevel of the fossil tree */
184
+ const char *zUrlSuffix; /* Suffix of the URL including query string
185
+ zBaseUrl/zUrlSuffix == Full text of the URL being served */
184186
char *zHttpsURL; /* zBaseURL translated to https: */
185187
char *zTop; /* Parent directory of zPath */
186188
int nExtraURL; /* Extra bytes added to SCRIPT_NAME */
187189
const char *zExtRoot; /* Document root for the /ext sub-website */
188190
const char *zContentType; /* The content type of the input HTTP request */
@@ -1352,10 +1354,13 @@
13521354
void set_base_url(const char *zAltBase){
13531355
int i;
13541356
const char *zHost;
13551357
const char *zMode;
13561358
const char *zCur;
1359
+ const char *zRU; /* REQUEST_URI */
1360
+ const char *zQS; /* QUERY_STRING */
1361
+ size_t nTop; /* length of g.zTop */
13571362
13581363
if( g.zBaseURL!=0 ) return;
13591364
if( zAltBase ){
13601365
int i, n, c;
13611366
g.zTop = g.zBaseURL = mprintf("%s", zAltBase);
@@ -1411,10 +1416,18 @@
14111416
g.zHttpsURL = mprintf("https://%s%.*s", z, i, zCur);
14121417
}
14131418
fossil_free(z);
14141419
}
14151420
1421
+ zRU = PD("REQUEST_URI","");
1422
+ nTop = strlen( g.zTop );
1423
+ g.zUrlSuffix = strncmp(zRU,g.zTop,nTop) ? "" : zRU+nTop;
1424
+ if(g.zUrlSuffix[0]=='/') g.zUrlSuffix++;
1425
+ zQS = PD("QUERY_STRING","");
1426
+ if( zQS[0] ) g.zUrlSuffix = mprintf("%s?%s", g.zUrlSuffix, zQS);
1427
+ else g.zUrlSuffix = mprintf("%s", g.zUrlSuffix);
1428
+
14161429
/* Try to record the base URL as a CONFIG table entry with a name
14171430
** of the form: "baseurl:BASE". This keeps a record of how the
14181431
** the repository is used as a server, to help in answering questions
14191432
** like "where is the CGI script that references this repository?"
14201433
**
14211434
--- src/main.c
+++ src/main.c
@@ -178,11 +178,13 @@
178 const char *zHttpCmd; /* External program to do HTTP requests */
179 int fNoSync; /* Do not do an autosync ever. --nosync */
180 int fIPv4; /* Use only IPv4, not IPv6. --ipv4 */
181 char *zPath; /* Name of webpage being served */
182 char *zExtra; /* Extra path information past the webpage name */
183 char *zBaseURL; /* Full text of the URL being served */
 
 
184 char *zHttpsURL; /* zBaseURL translated to https: */
185 char *zTop; /* Parent directory of zPath */
186 int nExtraURL; /* Extra bytes added to SCRIPT_NAME */
187 const char *zExtRoot; /* Document root for the /ext sub-website */
188 const char *zContentType; /* The content type of the input HTTP request */
@@ -1352,10 +1354,13 @@
1352 void set_base_url(const char *zAltBase){
1353 int i;
1354 const char *zHost;
1355 const char *zMode;
1356 const char *zCur;
 
 
 
1357
1358 if( g.zBaseURL!=0 ) return;
1359 if( zAltBase ){
1360 int i, n, c;
1361 g.zTop = g.zBaseURL = mprintf("%s", zAltBase);
@@ -1411,10 +1416,18 @@
1411 g.zHttpsURL = mprintf("https://%s%.*s", z, i, zCur);
1412 }
1413 fossil_free(z);
1414 }
1415
 
 
 
 
 
 
 
 
1416 /* Try to record the base URL as a CONFIG table entry with a name
1417 ** of the form: "baseurl:BASE". This keeps a record of how the
1418 ** the repository is used as a server, to help in answering questions
1419 ** like "where is the CGI script that references this repository?"
1420 **
1421
--- src/main.c
+++ src/main.c
@@ -178,11 +178,13 @@
178 const char *zHttpCmd; /* External program to do HTTP requests */
179 int fNoSync; /* Do not do an autosync ever. --nosync */
180 int fIPv4; /* Use only IPv4, not IPv6. --ipv4 */
181 char *zPath; /* Name of webpage being served */
182 char *zExtra; /* Extra path information past the webpage name */
183 char *zBaseURL; /* Full URL for the toplevel of the fossil tree */
184 const char *zUrlSuffix; /* Suffix of the URL including query string
185 zBaseUrl/zUrlSuffix == Full text of the URL being served */
186 char *zHttpsURL; /* zBaseURL translated to https: */
187 char *zTop; /* Parent directory of zPath */
188 int nExtraURL; /* Extra bytes added to SCRIPT_NAME */
189 const char *zExtRoot; /* Document root for the /ext sub-website */
190 const char *zContentType; /* The content type of the input HTTP request */
@@ -1352,10 +1354,13 @@
1354 void set_base_url(const char *zAltBase){
1355 int i;
1356 const char *zHost;
1357 const char *zMode;
1358 const char *zCur;
1359 const char *zRU; /* REQUEST_URI */
1360 const char *zQS; /* QUERY_STRING */
1361 size_t nTop; /* length of g.zTop */
1362
1363 if( g.zBaseURL!=0 ) return;
1364 if( zAltBase ){
1365 int i, n, c;
1366 g.zTop = g.zBaseURL = mprintf("%s", zAltBase);
@@ -1411,10 +1416,18 @@
1416 g.zHttpsURL = mprintf("https://%s%.*s", z, i, zCur);
1417 }
1418 fossil_free(z);
1419 }
1420
1421 zRU = PD("REQUEST_URI","");
1422 nTop = strlen( g.zTop );
1423 g.zUrlSuffix = strncmp(zRU,g.zTop,nTop) ? "" : zRU+nTop;
1424 if(g.zUrlSuffix[0]=='/') g.zUrlSuffix++;
1425 zQS = PD("QUERY_STRING","");
1426 if( zQS[0] ) g.zUrlSuffix = mprintf("%s?%s", g.zUrlSuffix, zQS);
1427 else g.zUrlSuffix = mprintf("%s", g.zUrlSuffix);
1428
1429 /* Try to record the base URL as a CONFIG table entry with a name
1430 ** of the form: "baseurl:BASE". This keeps a record of how the
1431 ** the repository is used as a server, to help in answering questions
1432 ** like "where is the CGI script that references this repository?"
1433 **
1434
+28 -1
--- src/style.c
+++ src/style.c
@@ -404,10 +404,30 @@
404404
va_start(ap, zFormat);
405405
local_zCurrentPage = vmprintf(zFormat, ap);
406406
va_end(ap);
407407
}
408408
}
409
+
410
+/* Use this for the $base_href_suffix variable if it is not NULL.
411
+** If it is NULL then use g.zUrlSuffix
412
+*/
413
+static char *local_zBaseHrefSuffix = 0;
414
+
415
+/*
416
+** Set the desired $base_href_suffix to something other than g.zUrlSuffix
417
+*/
418
+void style_set_base_href_suffix(const char *zFormat, ...){
419
+ fossil_free(local_zBaseHrefSuffix);
420
+ if( zFormat==0 ){
421
+ local_zBaseHrefSuffix = 0;
422
+ }else{
423
+ va_list ap;
424
+ va_start(ap, zFormat);
425
+ local_zBaseHrefSuffix = vmprintf(zFormat, ap);
426
+ va_end(ap);
427
+ }
428
+}
409429
410430
/*
411431
** Create a TH1 variable containing the URL for the stylesheet.
412432
**
413433
** The name of the new variable will be "stylesheet_url".
@@ -647,11 +667,11 @@
647667
** prepended.
648668
*/
649669
static const char zDfltHeader[] =
650670
@ <html>
651671
@ <head>
652
-@ <base href="$baseurl/$current_page" />
672
+@ <base href="$baseurl/$base_href_suffix" />
653673
@ <meta charset="UTF-8">
654674
@ <meta http-equiv="Content-Security-Policy" content="$default_csp" />
655675
@ <meta name="viewport" content="width=device-width, initial-scale=1.0">
656676
@ <title>$<project_name>: $<title></title>
657677
@ <link rel="alternate" type="application/rss+xml" title="RSS Feed" \
@@ -769,10 +789,16 @@
769789
Th_Store("secureurl", fossil_wants_https(1)? g.zHttpsURL: g.zBaseURL);
770790
Th_Store("home", g.zTop);
771791
Th_Store("index_page", db_get("index-page","/home"));
772792
if( local_zCurrentPage==0 ) style_set_current_page("%T", g.zPath);
773793
Th_Store("current_page", local_zCurrentPage);
794
+ if( local_zBaseHrefSuffix==0 ){
795
+ style_set_base_href_suffix("%s",g.zUrlSuffix);
796
+ /* %s because g.zUrlSuffix is already encoded (FIXME: really so?) */
797
+ }
798
+ Th_Store("base_href_suffix", local_zBaseHrefSuffix);
799
+ Th_Store("requested_url_suffix", g.zUrlSuffix);
774800
Th_Store("csrf_token", g.zCsrfToken);
775801
Th_Store("release_version", RELEASE_VERSION);
776802
Th_Store("manifest_version", MANIFEST_VERSION);
777803
Th_Store("manifest_date", MANIFEST_DATE);
778804
Th_Store("compiler_name", COMPILER_NAME);
@@ -1383,10 +1409,11 @@
13831409
#if !defined(_WIN32)
13841410
@ uid=%d(getuid()), gid=%d(getgid())<br />
13851411
#endif
13861412
@ g.zBaseURL = %h(g.zBaseURL)<br />
13871413
@ g.zHttpsURL = %h(g.zHttpsURL)<br />
1414
+ @ g.zUrlSuffix = %h(g.zUrlSuffix)<br />
13881415
@ g.zTop = %h(g.zTop)<br />
13891416
@ g.zPath = %h(g.zPath)<br />
13901417
@ g.userUid = %d(g.userUid)<br />
13911418
@ g.zLogin = %h(g.zLogin)<br />
13921419
@ g.isHuman = %d(g.isHuman)<br />
13931420
--- src/style.c
+++ src/style.c
@@ -404,10 +404,30 @@
404 va_start(ap, zFormat);
405 local_zCurrentPage = vmprintf(zFormat, ap);
406 va_end(ap);
407 }
408 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
409
410 /*
411 ** Create a TH1 variable containing the URL for the stylesheet.
412 **
413 ** The name of the new variable will be "stylesheet_url".
@@ -647,11 +667,11 @@
647 ** prepended.
648 */
649 static const char zDfltHeader[] =
650 @ <html>
651 @ <head>
652 @ <base href="$baseurl/$current_page" />
653 @ <meta charset="UTF-8">
654 @ <meta http-equiv="Content-Security-Policy" content="$default_csp" />
655 @ <meta name="viewport" content="width=device-width, initial-scale=1.0">
656 @ <title>$<project_name>: $<title></title>
657 @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" \
@@ -769,10 +789,16 @@
769 Th_Store("secureurl", fossil_wants_https(1)? g.zHttpsURL: g.zBaseURL);
770 Th_Store("home", g.zTop);
771 Th_Store("index_page", db_get("index-page","/home"));
772 if( local_zCurrentPage==0 ) style_set_current_page("%T", g.zPath);
773 Th_Store("current_page", local_zCurrentPage);
 
 
 
 
 
 
774 Th_Store("csrf_token", g.zCsrfToken);
775 Th_Store("release_version", RELEASE_VERSION);
776 Th_Store("manifest_version", MANIFEST_VERSION);
777 Th_Store("manifest_date", MANIFEST_DATE);
778 Th_Store("compiler_name", COMPILER_NAME);
@@ -1383,10 +1409,11 @@
1383 #if !defined(_WIN32)
1384 @ uid=%d(getuid()), gid=%d(getgid())<br />
1385 #endif
1386 @ g.zBaseURL = %h(g.zBaseURL)<br />
1387 @ g.zHttpsURL = %h(g.zHttpsURL)<br />
 
1388 @ g.zTop = %h(g.zTop)<br />
1389 @ g.zPath = %h(g.zPath)<br />
1390 @ g.userUid = %d(g.userUid)<br />
1391 @ g.zLogin = %h(g.zLogin)<br />
1392 @ g.isHuman = %d(g.isHuman)<br />
1393
--- src/style.c
+++ src/style.c
@@ -404,10 +404,30 @@
404 va_start(ap, zFormat);
405 local_zCurrentPage = vmprintf(zFormat, ap);
406 va_end(ap);
407 }
408 }
409
410 /* Use this for the $base_href_suffix variable if it is not NULL.
411 ** If it is NULL then use g.zUrlSuffix
412 */
413 static char *local_zBaseHrefSuffix = 0;
414
415 /*
416 ** Set the desired $base_href_suffix to something other than g.zUrlSuffix
417 */
418 void style_set_base_href_suffix(const char *zFormat, ...){
419 fossil_free(local_zBaseHrefSuffix);
420 if( zFormat==0 ){
421 local_zBaseHrefSuffix = 0;
422 }else{
423 va_list ap;
424 va_start(ap, zFormat);
425 local_zBaseHrefSuffix = vmprintf(zFormat, ap);
426 va_end(ap);
427 }
428 }
429
430 /*
431 ** Create a TH1 variable containing the URL for the stylesheet.
432 **
433 ** The name of the new variable will be "stylesheet_url".
@@ -647,11 +667,11 @@
667 ** prepended.
668 */
669 static const char zDfltHeader[] =
670 @ <html>
671 @ <head>
672 @ <base href="$baseurl/$base_href_suffix" />
673 @ <meta charset="UTF-8">
674 @ <meta http-equiv="Content-Security-Policy" content="$default_csp" />
675 @ <meta name="viewport" content="width=device-width, initial-scale=1.0">
676 @ <title>$<project_name>: $<title></title>
677 @ <link rel="alternate" type="application/rss+xml" title="RSS Feed" \
@@ -769,10 +789,16 @@
789 Th_Store("secureurl", fossil_wants_https(1)? g.zHttpsURL: g.zBaseURL);
790 Th_Store("home", g.zTop);
791 Th_Store("index_page", db_get("index-page","/home"));
792 if( local_zCurrentPage==0 ) style_set_current_page("%T", g.zPath);
793 Th_Store("current_page", local_zCurrentPage);
794 if( local_zBaseHrefSuffix==0 ){
795 style_set_base_href_suffix("%s",g.zUrlSuffix);
796 /* %s because g.zUrlSuffix is already encoded (FIXME: really so?) */
797 }
798 Th_Store("base_href_suffix", local_zBaseHrefSuffix);
799 Th_Store("requested_url_suffix", g.zUrlSuffix);
800 Th_Store("csrf_token", g.zCsrfToken);
801 Th_Store("release_version", RELEASE_VERSION);
802 Th_Store("manifest_version", MANIFEST_VERSION);
803 Th_Store("manifest_date", MANIFEST_DATE);
804 Th_Store("compiler_name", COMPILER_NAME);
@@ -1383,10 +1409,11 @@
1409 #if !defined(_WIN32)
1410 @ uid=%d(getuid()), gid=%d(getgid())<br />
1411 #endif
1412 @ g.zBaseURL = %h(g.zBaseURL)<br />
1413 @ g.zHttpsURL = %h(g.zHttpsURL)<br />
1414 @ g.zUrlSuffix = %h(g.zUrlSuffix)<br />
1415 @ g.zTop = %h(g.zTop)<br />
1416 @ g.zPath = %h(g.zPath)<br />
1417 @ g.userUid = %d(g.userUid)<br />
1418 @ g.zLogin = %h(g.zLogin)<br />
1419 @ g.isHuman = %d(g.isHuman)<br />
1420
+2
--- src/wiki.c
+++ src/wiki.c
@@ -597,10 +597,11 @@
597597
style_submenu_element("History", "%R/whistory?name=%T", zPageName);
598598
}
599599
}
600600
if( !isPopup ){
601601
style_set_current_page("%T?name=%T", g.zPath, zPageName);
602
+ style_set_base_href_suffix("%T?name=%T", g.zPath, zPageName);
602603
wiki_page_header(WIKITYPE_UNKNOWN, zPageName, "");
603604
if( !noSubmenu ){
604605
wiki_standard_submenu(submenuFlags);
605606
}
606607
}
@@ -1669,10 +1670,11 @@
16691670
manifest_destroy(pWiki);
16701671
cgi_redirectf("wiki?name=%T", zPageName);
16711672
return;
16721673
}
16731674
style_set_current_page("%T?name=%T", g.zPath, zPageName);
1675
+ style_set_base_href_suffix("%T?name=%T", g.zPath, zPageName);
16741676
style_set_current_feature("wiki");
16751677
style_header("Append Comment To: %s", zPageName);
16761678
if( !goodCaptcha ){
16771679
@ <p class="generalError">Error: Incorrect security code.</p>
16781680
}
16791681
--- src/wiki.c
+++ src/wiki.c
@@ -597,10 +597,11 @@
597 style_submenu_element("History", "%R/whistory?name=%T", zPageName);
598 }
599 }
600 if( !isPopup ){
601 style_set_current_page("%T?name=%T", g.zPath, zPageName);
 
602 wiki_page_header(WIKITYPE_UNKNOWN, zPageName, "");
603 if( !noSubmenu ){
604 wiki_standard_submenu(submenuFlags);
605 }
606 }
@@ -1669,10 +1670,11 @@
1669 manifest_destroy(pWiki);
1670 cgi_redirectf("wiki?name=%T", zPageName);
1671 return;
1672 }
1673 style_set_current_page("%T?name=%T", g.zPath, zPageName);
 
1674 style_set_current_feature("wiki");
1675 style_header("Append Comment To: %s", zPageName);
1676 if( !goodCaptcha ){
1677 @ <p class="generalError">Error: Incorrect security code.</p>
1678 }
1679
--- src/wiki.c
+++ src/wiki.c
@@ -597,10 +597,11 @@
597 style_submenu_element("History", "%R/whistory?name=%T", zPageName);
598 }
599 }
600 if( !isPopup ){
601 style_set_current_page("%T?name=%T", g.zPath, zPageName);
602 style_set_base_href_suffix("%T?name=%T", g.zPath, zPageName);
603 wiki_page_header(WIKITYPE_UNKNOWN, zPageName, "");
604 if( !noSubmenu ){
605 wiki_standard_submenu(submenuFlags);
606 }
607 }
@@ -1669,10 +1670,11 @@
1670 manifest_destroy(pWiki);
1671 cgi_redirectf("wiki?name=%T", zPageName);
1672 return;
1673 }
1674 style_set_current_page("%T?name=%T", g.zPath, zPageName);
1675 style_set_base_href_suffix("%T?name=%T", g.zPath, zPageName);
1676 style_set_current_feature("wiki");
1677 style_header("Append Comment To: %s", zPageName);
1678 if( !goodCaptcha ){
1679 @ <p class="generalError">Error: Incorrect security code.</p>
1680 }
1681

Keyboard Shortcuts

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