Fossil SCM

If path given to /ext is a directory and it contains an index file (of the same names supported by the /doc path), render that index file.

stephan 2019-12-13 20:56 trunk
Commit f28cea2b4375507d262492db3575c54ccb43a2cbb5b489dda7446c5d49fb1330
2 files changed +61 -11 +8
+61 -11
--- src/doc.c
+++ src/doc.c
@@ -612,10 +612,64 @@
612612
cgi_set_content_type(zMime);
613613
cgi_set_content(pBody);
614614
}
615615
}
616616
617
+/*
618
+** Returns a list of possible index page names, in the order of their
619
+** priority, and writes the number of entries in the list to *pCount
620
+** (which must not be NULL). The returned memory is static but the
621
+** number of entries depends on compile-time options.
622
+*/
623
+const char * const * document_index_list( int * pCount ){
624
+ static const char *const azSuffix[] = {
625
+ "index.html", "index.wiki", "index.md"
626
+#ifdef FOSSIL_ENABLE_TH1_DOCS
627
+ , "index.th1"
628
+#endif
629
+ };
630
+ *pCount = (int)count(azSuffix);
631
+ return azSuffix;
632
+}
633
+
634
+/*
635
+** If the given NUL-terminated directory name contains one of the
636
+** index files defined by document_index_list(), the path to that file
637
+** is returned in the form zDirName/FILE_NAME, else NULL is
638
+** returned. Ownership of the returned memory is transfered to the
639
+** caller.
640
+**
641
+** If pNResult is not NULL and non-NULL is returned, the length of the
642
+** returned string is written to *pNResult, otherwise pNResult is not
643
+** dereferenced.
644
+*/
645
+char * document_dir_has_index(const char * zDirName, int * pNResult){
646
+ Blob bName = BLOB_INITIALIZER; /* File path */
647
+ int i; /* Loop counter */
648
+ int nIndex; /* Number of index entries. */
649
+ const char * const * azIndex = document_index_list(&nIndex);
650
+ unsigned int nDirName = strlen(zDirName)
651
+ /* Cursor for the end of the initial
652
+ path+separator part of bName */;
653
+ blob_appendf( &bName, "%s%s", zDirName,
654
+ zDirName[nDirName-1]=='/' ? "" : "/" );
655
+ nDirName = bName.nUsed;
656
+ for(i=0; i<nIndex; ++i){
657
+ bName.nUsed = nDirName;
658
+ blob_append(&bName, azIndex[i], strlen(azIndex[i]));
659
+ if(file_isfile(bName.aData, ExtFILE)!=0){
660
+ break;
661
+ }
662
+ }
663
+ if(i<nIndex){
664
+ if(pNResult) *pNResult = (int)bName.nUsed;
665
+ return bName.aData;
666
+ }else{
667
+ blob_reset(&bName);
668
+ return 0;
669
+ }
670
+}
617671
618672
/*
619673
** WEBPAGE: uv
620674
** WEBPAGE: doc
621675
** URL: /uv/FILE
@@ -674,23 +728,19 @@
674728
Blob filebody; /* Content of the documentation file */
675729
Blob title; /* Document title */
676730
int nMiss = (-1); /* Failed attempts to find the document */
677731
int isUV = g.zPath[0]=='u'; /* True for /uv. False for /doc */
678732
const char *zDfltTitle;
679
- static const char *const azSuffix[] = {
680
- "index.html", "index.wiki", "index.md"
681
-#ifdef FOSSIL_ENABLE_TH1_DOCS
682
- , "index.th1"
683
-#endif
684
- };
733
+ int nSuffix; /* Number of entries in azSuffix */
734
+ const char *const * azSuffix = document_index_list(&nSuffix);
685735
686736
login_check_credentials();
687737
if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
688738
blob_init(&title, 0, 0);
689739
zDfltTitle = isUV ? "" : "Documentation";
690740
db_begin_transaction();
691
- while( rid==0 && (++nMiss)<=count(azSuffix) ){
741
+ while( rid==0 && (++nMiss)<=nSuffix ){
692742
zName = P("name");
693743
if( isUV ){
694744
if( zName==0 ) zName = "index.wiki";
695745
i = 0;
696746
}else{
@@ -699,15 +749,15 @@
699749
zCheckin = mprintf("%.*s", i, zName);
700750
if( fossil_strcmp(zCheckin,"ckout")==0 && g.localOpen==0 ){
701751
zCheckin = "tip";
702752
}
703753
}
704
- if( nMiss==count(azSuffix) ){
754
+ if( nMiss==nSuffix ){
705755
zName = "404.md";
706756
zDfltTitle = "Not Found";
707757
}else if( zName[i]==0 ){
708
- assert( nMiss>=0 && nMiss<count(azSuffix) );
758
+ assert( nMiss>=0 && nMiss<nSuffix );
709759
zName = azSuffix[nMiss];
710760
}else if( !isUV ){
711761
zName += i;
712762
}
713763
while( zName[0]=='/' ){ zName++; }
@@ -717,11 +767,11 @@
717767
zPathSuffix = mprintf("%s/%s", zCheckin, zName);
718768
}
719769
if( nMiss==0 ) zOrigName = zName;
720770
if( !file_is_simple_pathname(zName, 1) ){
721771
if( sqlite3_strglob("*/", zName)==0 ){
722
- assert( nMiss>=0 && nMiss<count(azSuffix) );
772
+ assert( nMiss>=0 && nMiss<nSuffix );
723773
zName = mprintf("%s%s", zName, azSuffix[nMiss]);
724774
if( !file_is_simple_pathname(zName, 1) ){
725775
goto doc_not_found;
726776
}
727777
}else{
@@ -775,11 +825,11 @@
775825
" FROM blob WHERE rid=%d", vid));
776826
Th_Store("doc_date", db_text(0, "SELECT datetime(mtime) FROM event"
777827
" WHERE objid=%d AND type='ci'", vid));
778828
}
779829
document_render(&filebody, zMime, zDfltTitle, zName);
780
- if( nMiss>=count(azSuffix) ) cgi_set_status(404, "Not Found");
830
+ if( nMiss>=nSuffix ) cgi_set_status(404, "Not Found");
781831
db_end_transaction(0);
782832
return;
783833
784834
/* Jump here when unable to locate the document */
785835
doc_not_found:
786836
--- src/doc.c
+++ src/doc.c
@@ -612,10 +612,64 @@
612 cgi_set_content_type(zMime);
613 cgi_set_content(pBody);
614 }
615 }
616
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
617
618 /*
619 ** WEBPAGE: uv
620 ** WEBPAGE: doc
621 ** URL: /uv/FILE
@@ -674,23 +728,19 @@
674 Blob filebody; /* Content of the documentation file */
675 Blob title; /* Document title */
676 int nMiss = (-1); /* Failed attempts to find the document */
677 int isUV = g.zPath[0]=='u'; /* True for /uv. False for /doc */
678 const char *zDfltTitle;
679 static const char *const azSuffix[] = {
680 "index.html", "index.wiki", "index.md"
681 #ifdef FOSSIL_ENABLE_TH1_DOCS
682 , "index.th1"
683 #endif
684 };
685
686 login_check_credentials();
687 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
688 blob_init(&title, 0, 0);
689 zDfltTitle = isUV ? "" : "Documentation";
690 db_begin_transaction();
691 while( rid==0 && (++nMiss)<=count(azSuffix) ){
692 zName = P("name");
693 if( isUV ){
694 if( zName==0 ) zName = "index.wiki";
695 i = 0;
696 }else{
@@ -699,15 +749,15 @@
699 zCheckin = mprintf("%.*s", i, zName);
700 if( fossil_strcmp(zCheckin,"ckout")==0 && g.localOpen==0 ){
701 zCheckin = "tip";
702 }
703 }
704 if( nMiss==count(azSuffix) ){
705 zName = "404.md";
706 zDfltTitle = "Not Found";
707 }else if( zName[i]==0 ){
708 assert( nMiss>=0 && nMiss<count(azSuffix) );
709 zName = azSuffix[nMiss];
710 }else if( !isUV ){
711 zName += i;
712 }
713 while( zName[0]=='/' ){ zName++; }
@@ -717,11 +767,11 @@
717 zPathSuffix = mprintf("%s/%s", zCheckin, zName);
718 }
719 if( nMiss==0 ) zOrigName = zName;
720 if( !file_is_simple_pathname(zName, 1) ){
721 if( sqlite3_strglob("*/", zName)==0 ){
722 assert( nMiss>=0 && nMiss<count(azSuffix) );
723 zName = mprintf("%s%s", zName, azSuffix[nMiss]);
724 if( !file_is_simple_pathname(zName, 1) ){
725 goto doc_not_found;
726 }
727 }else{
@@ -775,11 +825,11 @@
775 " FROM blob WHERE rid=%d", vid));
776 Th_Store("doc_date", db_text(0, "SELECT datetime(mtime) FROM event"
777 " WHERE objid=%d AND type='ci'", vid));
778 }
779 document_render(&filebody, zMime, zDfltTitle, zName);
780 if( nMiss>=count(azSuffix) ) cgi_set_status(404, "Not Found");
781 db_end_transaction(0);
782 return;
783
784 /* Jump here when unable to locate the document */
785 doc_not_found:
786
--- src/doc.c
+++ src/doc.c
@@ -612,10 +612,64 @@
612 cgi_set_content_type(zMime);
613 cgi_set_content(pBody);
614 }
615 }
616
617 /*
618 ** Returns a list of possible index page names, in the order of their
619 ** priority, and writes the number of entries in the list to *pCount
620 ** (which must not be NULL). The returned memory is static but the
621 ** number of entries depends on compile-time options.
622 */
623 const char * const * document_index_list( int * pCount ){
624 static const char *const azSuffix[] = {
625 "index.html", "index.wiki", "index.md"
626 #ifdef FOSSIL_ENABLE_TH1_DOCS
627 , "index.th1"
628 #endif
629 };
630 *pCount = (int)count(azSuffix);
631 return azSuffix;
632 }
633
634 /*
635 ** If the given NUL-terminated directory name contains one of the
636 ** index files defined by document_index_list(), the path to that file
637 ** is returned in the form zDirName/FILE_NAME, else NULL is
638 ** returned. Ownership of the returned memory is transfered to the
639 ** caller.
640 **
641 ** If pNResult is not NULL and non-NULL is returned, the length of the
642 ** returned string is written to *pNResult, otherwise pNResult is not
643 ** dereferenced.
644 */
645 char * document_dir_has_index(const char * zDirName, int * pNResult){
646 Blob bName = BLOB_INITIALIZER; /* File path */
647 int i; /* Loop counter */
648 int nIndex; /* Number of index entries. */
649 const char * const * azIndex = document_index_list(&nIndex);
650 unsigned int nDirName = strlen(zDirName)
651 /* Cursor for the end of the initial
652 path+separator part of bName */;
653 blob_appendf( &bName, "%s%s", zDirName,
654 zDirName[nDirName-1]=='/' ? "" : "/" );
655 nDirName = bName.nUsed;
656 for(i=0; i<nIndex; ++i){
657 bName.nUsed = nDirName;
658 blob_append(&bName, azIndex[i], strlen(azIndex[i]));
659 if(file_isfile(bName.aData, ExtFILE)!=0){
660 break;
661 }
662 }
663 if(i<nIndex){
664 if(pNResult) *pNResult = (int)bName.nUsed;
665 return bName.aData;
666 }else{
667 blob_reset(&bName);
668 return 0;
669 }
670 }
671
672 /*
673 ** WEBPAGE: uv
674 ** WEBPAGE: doc
675 ** URL: /uv/FILE
@@ -674,23 +728,19 @@
728 Blob filebody; /* Content of the documentation file */
729 Blob title; /* Document title */
730 int nMiss = (-1); /* Failed attempts to find the document */
731 int isUV = g.zPath[0]=='u'; /* True for /uv. False for /doc */
732 const char *zDfltTitle;
733 int nSuffix; /* Number of entries in azSuffix */
734 const char *const * azSuffix = document_index_list(&nSuffix);
 
 
 
 
735
736 login_check_credentials();
737 if( !g.perm.Read ){ login_needed(g.anon.Read); return; }
738 blob_init(&title, 0, 0);
739 zDfltTitle = isUV ? "" : "Documentation";
740 db_begin_transaction();
741 while( rid==0 && (++nMiss)<=nSuffix ){
742 zName = P("name");
743 if( isUV ){
744 if( zName==0 ) zName = "index.wiki";
745 i = 0;
746 }else{
@@ -699,15 +749,15 @@
749 zCheckin = mprintf("%.*s", i, zName);
750 if( fossil_strcmp(zCheckin,"ckout")==0 && g.localOpen==0 ){
751 zCheckin = "tip";
752 }
753 }
754 if( nMiss==nSuffix ){
755 zName = "404.md";
756 zDfltTitle = "Not Found";
757 }else if( zName[i]==0 ){
758 assert( nMiss>=0 && nMiss<nSuffix );
759 zName = azSuffix[nMiss];
760 }else if( !isUV ){
761 zName += i;
762 }
763 while( zName[0]=='/' ){ zName++; }
@@ -717,11 +767,11 @@
767 zPathSuffix = mprintf("%s/%s", zCheckin, zName);
768 }
769 if( nMiss==0 ) zOrigName = zName;
770 if( !file_is_simple_pathname(zName, 1) ){
771 if( sqlite3_strglob("*/", zName)==0 ){
772 assert( nMiss>=0 && nMiss<nSuffix );
773 zName = mprintf("%s%s", zName, azSuffix[nMiss]);
774 if( !file_is_simple_pathname(zName, 1) ){
775 goto doc_not_found;
776 }
777 }else{
@@ -775,11 +825,11 @@
825 " FROM blob WHERE rid=%d", vid));
826 Th_Store("doc_date", db_text(0, "SELECT datetime(mtime) FROM event"
827 " WHERE objid=%d AND type='ci'", vid));
828 }
829 document_render(&filebody, zMime, zDfltTitle, zName);
830 if( nMiss>=nSuffix ) cgi_set_status(404, "Not Found");
831 db_end_transaction(0);
832 return;
833
834 /* Jump here when unable to locate the document */
835 doc_not_found:
836
--- src/extcgi.c
+++ src/extcgi.c
@@ -188,10 +188,16 @@
188188
break;
189189
}
190190
}
191191
}
192192
}
193
+
194
+ if( nScript==0 && file_isdir(zPath,ExtFILE)==1 ){
195
+ /* Check for an index.* file */
196
+ zScript = document_dir_has_index(zPath, &nScript);
197
+ }
198
+
193199
if( nScript==0 ){
194200
zFailReason = "path does not match any file or script";
195201
goto ext_not_found;
196202
}
197203
assert( nScript>=nRoot+1 );
@@ -204,10 +210,11 @@
204210
if( zPath[nScript]!=0 ){
205211
zFailReason = "extra path elements after filename";
206212
goto ext_not_found;
207213
}
208214
blob_read_from_file(&reply, zScript, ExtFILE);
215
+ fossil_free(zScript);
209216
document_render(&reply, zMime, zName, zName);
210217
return;
211218
}
212219
213220
/* If we reach this point, that means we are dealing with an executable
@@ -238,10 +245,11 @@
238245
const char *zVal = P(azCgiEnv[i]);
239246
if( zVal ) fossil_setenv(azCgiEnv[i], zVal);
240247
}
241248
fossil_setenv("HTTP_ACCEPT_ENCODING","");
242249
rc = popen2(zScript, &fdFromChild, &toChild, &pidChild, 1);
250
+ fossil_free(zScript);
243251
if( rc ){
244252
zFailReason = "cannot exec CGI child process";
245253
goto ext_not_found;
246254
}
247255
fromChild = fdopen(fdFromChild, "rb");
248256
--- src/extcgi.c
+++ src/extcgi.c
@@ -188,10 +188,16 @@
188 break;
189 }
190 }
191 }
192 }
 
 
 
 
 
 
193 if( nScript==0 ){
194 zFailReason = "path does not match any file or script";
195 goto ext_not_found;
196 }
197 assert( nScript>=nRoot+1 );
@@ -204,10 +210,11 @@
204 if( zPath[nScript]!=0 ){
205 zFailReason = "extra path elements after filename";
206 goto ext_not_found;
207 }
208 blob_read_from_file(&reply, zScript, ExtFILE);
 
209 document_render(&reply, zMime, zName, zName);
210 return;
211 }
212
213 /* If we reach this point, that means we are dealing with an executable
@@ -238,10 +245,11 @@
238 const char *zVal = P(azCgiEnv[i]);
239 if( zVal ) fossil_setenv(azCgiEnv[i], zVal);
240 }
241 fossil_setenv("HTTP_ACCEPT_ENCODING","");
242 rc = popen2(zScript, &fdFromChild, &toChild, &pidChild, 1);
 
243 if( rc ){
244 zFailReason = "cannot exec CGI child process";
245 goto ext_not_found;
246 }
247 fromChild = fdopen(fdFromChild, "rb");
248
--- src/extcgi.c
+++ src/extcgi.c
@@ -188,10 +188,16 @@
188 break;
189 }
190 }
191 }
192 }
193
194 if( nScript==0 && file_isdir(zPath,ExtFILE)==1 ){
195 /* Check for an index.* file */
196 zScript = document_dir_has_index(zPath, &nScript);
197 }
198
199 if( nScript==0 ){
200 zFailReason = "path does not match any file or script";
201 goto ext_not_found;
202 }
203 assert( nScript>=nRoot+1 );
@@ -204,10 +210,11 @@
210 if( zPath[nScript]!=0 ){
211 zFailReason = "extra path elements after filename";
212 goto ext_not_found;
213 }
214 blob_read_from_file(&reply, zScript, ExtFILE);
215 fossil_free(zScript);
216 document_render(&reply, zMime, zName, zName);
217 return;
218 }
219
220 /* If we reach this point, that means we are dealing with an executable
@@ -238,10 +245,11 @@
245 const char *zVal = P(azCgiEnv[i]);
246 if( zVal ) fossil_setenv(azCgiEnv[i], zVal);
247 }
248 fossil_setenv("HTTP_ACCEPT_ENCODING","");
249 rc = popen2(zScript, &fdFromChild, &toChild, &pidChild, 1);
250 fossil_free(zScript);
251 if( rc ){
252 zFailReason = "cannot exec CGI child process";
253 goto ext_not_found;
254 }
255 fromChild = fdopen(fdFromChild, "rb");
256

Keyboard Shortcuts

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