Fossil SCM

Enhance the /tarball, /zip, and /sqlar pages so that the checkin name to be downloaded can be expressed as part of the URI, and without the need for query parameters.

drh 2018-04-06 12:01 trunk
Commit 3e94c7ed74a0774134fbd96d672ee70cd55160213bfa1373303edb6f894bf0e8
4 files changed +4 -2 +3 -3 +45 -4 +11 -1
+4 -2
--- src/clone.c
+++ src/clone.c
@@ -317,14 +317,16 @@
317317
@ you "Download Zip" privileges.
318318
}
319319
}else{
320320
const char *zDLTag = db_get("download-tag","trunk");
321321
const char *zNm = db_get("short-project-name","download");
322
- char *zUrl = href("%R/zip/%t.zip?uuid=%t", zNm, zDLTag);
322
+ char *zUrl = href("%R/zip/%t/%t.zip", zDLTag, zNm);
323323
@ <p>ZIP Archive: %z(zUrl)%h(zNm).zip</a>
324
- zUrl = href("%R/tarball/%t.tar.gz?uuid=%t", zNm, zDLTag);
324
+ zUrl = href("%R/tarball/%t/%t.tar.gz", zDLTag, zNm);
325325
@ <p>Tarball: %z(zUrl)%h(zNm).tar.gz</a>
326
+ zUrl = href("%R/sqlar/%t/%t.sqlar", zDLTag, zNm);
327
+ @ <p>SQLite Archive: %z(zUrl)%h(zNm).sqlar</a>
326328
}
327329
if( !g.perm.Clone ){
328330
@ <p>You are not authorized to clone this repository.
329331
if( g.zLogin==0 || g.zLogin[0]==0 ){
330332
@ Maybe you would be able to clone if you
331333
--- src/clone.c
+++ src/clone.c
@@ -317,14 +317,16 @@
317 @ you "Download Zip" privileges.
318 }
319 }else{
320 const char *zDLTag = db_get("download-tag","trunk");
321 const char *zNm = db_get("short-project-name","download");
322 char *zUrl = href("%R/zip/%t.zip?uuid=%t", zNm, zDLTag);
323 @ <p>ZIP Archive: %z(zUrl)%h(zNm).zip</a>
324 zUrl = href("%R/tarball/%t.tar.gz?uuid=%t", zNm, zDLTag);
325 @ <p>Tarball: %z(zUrl)%h(zNm).tar.gz</a>
 
 
326 }
327 if( !g.perm.Clone ){
328 @ <p>You are not authorized to clone this repository.
329 if( g.zLogin==0 || g.zLogin[0]==0 ){
330 @ Maybe you would be able to clone if you
331
--- src/clone.c
+++ src/clone.c
@@ -317,14 +317,16 @@
317 @ you "Download Zip" privileges.
318 }
319 }else{
320 const char *zDLTag = db_get("download-tag","trunk");
321 const char *zNm = db_get("short-project-name","download");
322 char *zUrl = href("%R/zip/%t/%t.zip", zDLTag, zNm);
323 @ <p>ZIP Archive: %z(zUrl)%h(zNm).zip</a>
324 zUrl = href("%R/tarball/%t/%t.tar.gz", zDLTag, zNm);
325 @ <p>Tarball: %z(zUrl)%h(zNm).tar.gz</a>
326 zUrl = href("%R/sqlar/%t/%t.sqlar", zDLTag, zNm);
327 @ <p>SQLite Archive: %z(zUrl)%h(zNm).sqlar</a>
328 }
329 if( !g.perm.Clone ){
330 @ <p>You are not authorized to clone this repository.
331 if( g.zLogin==0 || g.zLogin[0]==0 ){
332 @ Maybe you would be able to clone if you
333
+3 -3
--- src/info.c
+++ src/info.c
@@ -714,15 +714,15 @@
714714
for(jj=0; zPJ[jj]; jj++){
715715
if( (zPJ[jj]>0 && zPJ[jj]<' ') || strchr("\"*/:<>?\\|", zPJ[jj]) ){
716716
zPJ[jj] = '_';
717717
}
718718
}
719
- zUrl = mprintf("%R/tarball/%t-%S.tar.gz?r=%s", zPJ, zUuid, zUuid);
719
+ zUrl = mprintf("%R/tarball/%S/%t-%S.tar.gz", zUuid, zPJ, zUuid);
720720
@ <tr><th>Downloads:</th><td>
721721
@ %z(href("%s",zUrl))Tarball</a>
722
- @ | %z(href("%R/zip/%t-%S.zip?r=%!S",zPJ,zUuid,zUuid))ZIP archive</a>
723
- @ | %z(href("%R/sqlar/%t-%S.sqlar?r=%!S",zPJ,zUuid,zUuid))\
722
+ @ | %z(href("%R/zip/%S/%t-%S.zip",zUuid, zPJ,zUuid))ZIP archive</a>
723
+ @ | %z(href("%R/sqlar/%S/%t-%S.sqlar",zUuid,zPJ,zUuid))\
724724
@ SQL archive</a></td></tr>
725725
fossil_free(zUrl);
726726
blob_reset(&projName);
727727
}
728728
729729
--- src/info.c
+++ src/info.c
@@ -714,15 +714,15 @@
714 for(jj=0; zPJ[jj]; jj++){
715 if( (zPJ[jj]>0 && zPJ[jj]<' ') || strchr("\"*/:<>?\\|", zPJ[jj]) ){
716 zPJ[jj] = '_';
717 }
718 }
719 zUrl = mprintf("%R/tarball/%t-%S.tar.gz?r=%s", zPJ, zUuid, zUuid);
720 @ <tr><th>Downloads:</th><td>
721 @ %z(href("%s",zUrl))Tarball</a>
722 @ | %z(href("%R/zip/%t-%S.zip?r=%!S",zPJ,zUuid,zUuid))ZIP archive</a>
723 @ | %z(href("%R/sqlar/%t-%S.sqlar?r=%!S",zPJ,zUuid,zUuid))\
724 @ SQL archive</a></td></tr>
725 fossil_free(zUrl);
726 blob_reset(&projName);
727 }
728
729
--- src/info.c
+++ src/info.c
@@ -714,15 +714,15 @@
714 for(jj=0; zPJ[jj]; jj++){
715 if( (zPJ[jj]>0 && zPJ[jj]<' ') || strchr("\"*/:<>?\\|", zPJ[jj]) ){
716 zPJ[jj] = '_';
717 }
718 }
719 zUrl = mprintf("%R/tarball/%S/%t-%S.tar.gz", zUuid, zPJ, zUuid);
720 @ <tr><th>Downloads:</th><td>
721 @ %z(href("%s",zUrl))Tarball</a>
722 @ | %z(href("%R/zip/%S/%t-%S.zip",zUuid, zPJ,zUuid))ZIP archive</a>
723 @ | %z(href("%R/sqlar/%S/%t-%S.sqlar",zUuid,zPJ,zUuid))\
724 @ SQL archive</a></td></tr>
725 fossil_free(zUrl);
726 blob_reset(&projName);
727 }
728
729
+45 -4
--- src/tar.c
+++ src/tar.c
@@ -646,18 +646,55 @@
646646
glob_free(pInclude);
647647
glob_free(pExclude);
648648
blob_write_to_file(&tarball, g.argv[3]);
649649
blob_reset(&tarball);
650650
}
651
+
652
+/*
653
+** Check to see if the input string is of the form:
654
+**
655
+** checkin-name/filename.ext
656
+**
657
+** In other words, check to see if the input contains a single '/'
658
+** character that separates a valid check-in name from a filename.
659
+**
660
+** If the condition is true, return the check-in name and set the
661
+** input string to be the filename.
662
+**
663
+** If the condition is false, return NULL
664
+*/
665
+char *tar_uuid_from_name(char **pzName){
666
+ char *zName = *pzName;
667
+ int i, n;
668
+ for(i=n=0; zName[i]; i++){
669
+ if( zName[i]=='/' ){
670
+ if( n==0 ) n = i;
671
+ else return 0;
672
+ }
673
+ }
674
+ if( n==0 ) return 0;
675
+ if( zName[n+1]==0 ) return 0;
676
+ zName[n] = 0;
677
+ *pzName = fossil_strdup(&zName[n+1]);
678
+ return zName;
679
+}
651680
652681
/*
653682
** WEBPAGE: tarball
654683
** URL: /tarball
655684
**
656685
** Generate a compressed tarball for the check-in specified by the "r"
657686
** query parameter. Return that compressed tarball as the HTTP reply
658687
** content.
688
+**
689
+** The r= and name= query parameters can be specified as extensions to the
690
+** URI. Example, the following URIs are all equivalent:
691
+**
692
+** /tarball/release/xyz.tar.gz
693
+** /tarball?r=release&name=xyz.tar.gz
694
+** /tarball/xyz.tar.gz?r=release
695
+** /tarball?name=release/xyz.tar.gz
659696
**
660697
** Query parameters:
661698
**
662699
** name=NAME[.tar.gz] The base name of the output file. The default
663700
** value is a configuration parameter in the project
@@ -665,12 +702,15 @@
665702
** extension, is used as the top-most directory name.
666703
**
667704
** r=TAG The check-in that is turned into a compressed tarball.
668705
** Defaults to "trunk". This query parameter used to
669706
** be called "uuid" and "uuid" is still accepted for
670
-** backwards compatibility. If omitted, the default
671
-** check-in name is "trunk".
707
+** backwards compatibility. If the name= query parameter
708
+** contains one "/" character then the part before the /
709
+** is the TAG and the part after the / is the true name.
710
+** If no TAG is specified by any of the above means, then
711
+** "trunk" is used as the default.
672712
**
673713
** in=PATTERN Only include files that match the comma-separate
674714
** list of GLOB patterns in PATTERN, as with ex=
675715
**
676716
** ex=PATTERN Omit any file that match PATTERN. PATTERN is a
@@ -691,21 +731,22 @@
691731
const char *z;
692732
693733
login_check_credentials();
694734
if( !g.perm.Zip ){ login_needed(g.anon.Zip); return; }
695735
load_control();
696
- zName = mprintf("%s", PD("name",""));
697
- nName = strlen(zName);
736
+ zName = fossil_strdup(PD("name",""));
698737
z = P("r");
699738
if( z==0 ) z = P("uuid");
739
+ if( z==0 ) z = tar_uuid_from_name(&zName);
700740
if( z==0 ) z = "trunk";
701741
g.zOpenRevision = zRid = fossil_strdup(z);
702742
nRid = strlen(zRid);
703743
zInclude = P("in");
704744
if( zInclude ) pInclude = glob_create(zInclude);
705745
zExclude = P("ex");
706746
if( zExclude ) pExclude = glob_create(zExclude);
747
+ nName = strlen(zName);
707748
if( nName>7 && fossil_strcmp(&zName[nName-7], ".tar.gz")==0 ){
708749
/* Special case: Remove the ".tar.gz" suffix. */
709750
nName -= 7;
710751
zName[nName] = 0;
711752
}else{
712753
--- src/tar.c
+++ src/tar.c
@@ -646,18 +646,55 @@
646 glob_free(pInclude);
647 glob_free(pExclude);
648 blob_write_to_file(&tarball, g.argv[3]);
649 blob_reset(&tarball);
650 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
651
652 /*
653 ** WEBPAGE: tarball
654 ** URL: /tarball
655 **
656 ** Generate a compressed tarball for the check-in specified by the "r"
657 ** query parameter. Return that compressed tarball as the HTTP reply
658 ** content.
 
 
 
 
 
 
 
 
659 **
660 ** Query parameters:
661 **
662 ** name=NAME[.tar.gz] The base name of the output file. The default
663 ** value is a configuration parameter in the project
@@ -665,12 +702,15 @@
665 ** extension, is used as the top-most directory name.
666 **
667 ** r=TAG The check-in that is turned into a compressed tarball.
668 ** Defaults to "trunk". This query parameter used to
669 ** be called "uuid" and "uuid" is still accepted for
670 ** backwards compatibility. If omitted, the default
671 ** check-in name is "trunk".
 
 
 
672 **
673 ** in=PATTERN Only include files that match the comma-separate
674 ** list of GLOB patterns in PATTERN, as with ex=
675 **
676 ** ex=PATTERN Omit any file that match PATTERN. PATTERN is a
@@ -691,21 +731,22 @@
691 const char *z;
692
693 login_check_credentials();
694 if( !g.perm.Zip ){ login_needed(g.anon.Zip); return; }
695 load_control();
696 zName = mprintf("%s", PD("name",""));
697 nName = strlen(zName);
698 z = P("r");
699 if( z==0 ) z = P("uuid");
 
700 if( z==0 ) z = "trunk";
701 g.zOpenRevision = zRid = fossil_strdup(z);
702 nRid = strlen(zRid);
703 zInclude = P("in");
704 if( zInclude ) pInclude = glob_create(zInclude);
705 zExclude = P("ex");
706 if( zExclude ) pExclude = glob_create(zExclude);
 
707 if( nName>7 && fossil_strcmp(&zName[nName-7], ".tar.gz")==0 ){
708 /* Special case: Remove the ".tar.gz" suffix. */
709 nName -= 7;
710 zName[nName] = 0;
711 }else{
712
--- src/tar.c
+++ src/tar.c
@@ -646,18 +646,55 @@
646 glob_free(pInclude);
647 glob_free(pExclude);
648 blob_write_to_file(&tarball, g.argv[3]);
649 blob_reset(&tarball);
650 }
651
652 /*
653 ** Check to see if the input string is of the form:
654 **
655 ** checkin-name/filename.ext
656 **
657 ** In other words, check to see if the input contains a single '/'
658 ** character that separates a valid check-in name from a filename.
659 **
660 ** If the condition is true, return the check-in name and set the
661 ** input string to be the filename.
662 **
663 ** If the condition is false, return NULL
664 */
665 char *tar_uuid_from_name(char **pzName){
666 char *zName = *pzName;
667 int i, n;
668 for(i=n=0; zName[i]; i++){
669 if( zName[i]=='/' ){
670 if( n==0 ) n = i;
671 else return 0;
672 }
673 }
674 if( n==0 ) return 0;
675 if( zName[n+1]==0 ) return 0;
676 zName[n] = 0;
677 *pzName = fossil_strdup(&zName[n+1]);
678 return zName;
679 }
680
681 /*
682 ** WEBPAGE: tarball
683 ** URL: /tarball
684 **
685 ** Generate a compressed tarball for the check-in specified by the "r"
686 ** query parameter. Return that compressed tarball as the HTTP reply
687 ** content.
688 **
689 ** The r= and name= query parameters can be specified as extensions to the
690 ** URI. Example, the following URIs are all equivalent:
691 **
692 ** /tarball/release/xyz.tar.gz
693 ** /tarball?r=release&name=xyz.tar.gz
694 ** /tarball/xyz.tar.gz?r=release
695 ** /tarball?name=release/xyz.tar.gz
696 **
697 ** Query parameters:
698 **
699 ** name=NAME[.tar.gz] The base name of the output file. The default
700 ** value is a configuration parameter in the project
@@ -665,12 +702,15 @@
702 ** extension, is used as the top-most directory name.
703 **
704 ** r=TAG The check-in that is turned into a compressed tarball.
705 ** Defaults to "trunk". This query parameter used to
706 ** be called "uuid" and "uuid" is still accepted for
707 ** backwards compatibility. If the name= query parameter
708 ** contains one "/" character then the part before the /
709 ** is the TAG and the part after the / is the true name.
710 ** If no TAG is specified by any of the above means, then
711 ** "trunk" is used as the default.
712 **
713 ** in=PATTERN Only include files that match the comma-separate
714 ** list of GLOB patterns in PATTERN, as with ex=
715 **
716 ** ex=PATTERN Omit any file that match PATTERN. PATTERN is a
@@ -691,21 +731,22 @@
731 const char *z;
732
733 login_check_credentials();
734 if( !g.perm.Zip ){ login_needed(g.anon.Zip); return; }
735 load_control();
736 zName = fossil_strdup(PD("name",""));
 
737 z = P("r");
738 if( z==0 ) z = P("uuid");
739 if( z==0 ) z = tar_uuid_from_name(&zName);
740 if( z==0 ) z = "trunk";
741 g.zOpenRevision = zRid = fossil_strdup(z);
742 nRid = strlen(zRid);
743 zInclude = P("in");
744 if( zInclude ) pInclude = glob_create(zInclude);
745 zExclude = P("ex");
746 if( zExclude ) pExclude = glob_create(zExclude);
747 nName = strlen(zName);
748 if( nName>7 && fossil_strcmp(&zName[nName-7], ".tar.gz")==0 ){
749 /* Special case: Remove the ".tar.gz" suffix. */
750 nName -= 7;
751 zName[nName] = 0;
752 }else{
753
+11 -1
--- src/zip.c
+++ src/zip.c
@@ -836,10 +836,19 @@
836836
** WEBPAGE: zip
837837
**
838838
** Generate a ZIP or SQL archive for the check-in specified by the "r"
839839
** query parameter. Return the archive as the HTTP reply content.
840840
**
841
+** If the NAME contains one "/" then the part before the "/" is taken
842
+** as the TAG and the part after the "/" becomes the true name. Hence,
843
+** the following URLs are all equivalent:
844
+**
845
+** /sqlar/508c42a6398f8/download.sqlar
846
+** /sqlar?r=508c42a6398f8&name=download.sqlar
847
+** /sqlar/download.sqlar?r=508c42a6398f8
848
+** /sqlar?name=508c42a6398f8/download.sqlar
849
+**
841850
** Query parameters:
842851
**
843852
** name=NAME The base name of the output file. The default
844853
** value is a configuration parameter in the project
845854
** settings. A prefix of the name, omitting the
@@ -883,14 +892,15 @@
883892
eType = ARCHIVE_ZIP;
884893
zType = "ZIP";
885894
}
886895
load_control();
887896
zName = mprintf("%s", PD("name",""));
888
- nName = strlen(zName);
889897
z = P("r");
890898
if( z==0 ) z = P("uuid");
899
+ if( z==0 ) z = tar_uuid_from_name(&zName);
891900
if( z==0 ) z = "trunk";
901
+ nName = strlen(zName);
892902
g.zOpenRevision = zRid = fossil_strdup(z);
893903
nRid = strlen(zRid);
894904
zInclude = P("in");
895905
if( zInclude ) pInclude = glob_create(zInclude);
896906
zExclude = P("ex");
897907
--- src/zip.c
+++ src/zip.c
@@ -836,10 +836,19 @@
836 ** WEBPAGE: zip
837 **
838 ** Generate a ZIP or SQL archive for the check-in specified by the "r"
839 ** query parameter. Return the archive as the HTTP reply content.
840 **
 
 
 
 
 
 
 
 
 
841 ** Query parameters:
842 **
843 ** name=NAME The base name of the output file. The default
844 ** value is a configuration parameter in the project
845 ** settings. A prefix of the name, omitting the
@@ -883,14 +892,15 @@
883 eType = ARCHIVE_ZIP;
884 zType = "ZIP";
885 }
886 load_control();
887 zName = mprintf("%s", PD("name",""));
888 nName = strlen(zName);
889 z = P("r");
890 if( z==0 ) z = P("uuid");
 
891 if( z==0 ) z = "trunk";
 
892 g.zOpenRevision = zRid = fossil_strdup(z);
893 nRid = strlen(zRid);
894 zInclude = P("in");
895 if( zInclude ) pInclude = glob_create(zInclude);
896 zExclude = P("ex");
897
--- src/zip.c
+++ src/zip.c
@@ -836,10 +836,19 @@
836 ** WEBPAGE: zip
837 **
838 ** Generate a ZIP or SQL archive for the check-in specified by the "r"
839 ** query parameter. Return the archive as the HTTP reply content.
840 **
841 ** If the NAME contains one "/" then the part before the "/" is taken
842 ** as the TAG and the part after the "/" becomes the true name. Hence,
843 ** the following URLs are all equivalent:
844 **
845 ** /sqlar/508c42a6398f8/download.sqlar
846 ** /sqlar?r=508c42a6398f8&name=download.sqlar
847 ** /sqlar/download.sqlar?r=508c42a6398f8
848 ** /sqlar?name=508c42a6398f8/download.sqlar
849 **
850 ** Query parameters:
851 **
852 ** name=NAME The base name of the output file. The default
853 ** value is a configuration parameter in the project
854 ** settings. A prefix of the name, omitting the
@@ -883,14 +892,15 @@
892 eType = ARCHIVE_ZIP;
893 zType = "ZIP";
894 }
895 load_control();
896 zName = mprintf("%s", PD("name",""));
 
897 z = P("r");
898 if( z==0 ) z = P("uuid");
899 if( z==0 ) z = tar_uuid_from_name(&zName);
900 if( z==0 ) z = "trunk";
901 nName = strlen(zName);
902 g.zOpenRevision = zRid = fossil_strdup(z);
903 nRid = strlen(zRid);
904 zInclude = P("in");
905 if( zInclude ) pInclude = glob_create(zInclude);
906 zExclude = P("ex");
907

Keyboard Shortcuts

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