Fossil SCM

Add a Content-Disposition: header to the HTTP reply for the "Download" button.

drh 2020-05-21 23:56 trunk
Commit 34cb4766f1cabaad44c1b91c500539dff9888e49fe64480194d86e1ed51f2129
2 files changed +19 +32 -14
+19
--- src/cgi.c
+++ src/cgi.c
@@ -433,10 +433,29 @@
433433
va_list ap;
434434
va_start(ap, zFormat);
435435
cgi_redirect(vmprintf(zFormat, ap));
436436
va_end(ap);
437437
}
438
+
439
+/*
440
+** Add a "Content-disposition: attachment; filename=%s" header to the reply.
441
+*/
442
+void cgi_content_disposition_filename(const char *zFilename){
443
+ /* 0123456789 123456789 123456789 123456789 123456*/
444
+ char *z = mprintf("Content-Disposition: attachment; filename=\"%s\";\r\n",
445
+ zFilename);
446
+ int i;
447
+ int n = (int)strlen(z);
448
+ for(i=43; i<n-4; i++){
449
+ char c = z[i];
450
+ if( isalnum(c) ) continue;
451
+ if( c=='.' || c=='-' || c=='/' ) continue;
452
+ z[i] = '_';
453
+ }
454
+ cgi_append_header(z);
455
+ fossil_free(z);
456
+}
438457
439458
/*
440459
** Return the URL for the caller. This is obtained from either the
441460
** referer CGI parameter, if it exists, or the HTTP_REFERER HTTP parameter.
442461
** If neither exist, return zDefault.
443462
--- src/cgi.c
+++ src/cgi.c
@@ -433,10 +433,29 @@
433 va_list ap;
434 va_start(ap, zFormat);
435 cgi_redirect(vmprintf(zFormat, ap));
436 va_end(ap);
437 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
438
439 /*
440 ** Return the URL for the caller. This is obtained from either the
441 ** referer CGI parameter, if it exists, or the HTTP_REFERER HTTP parameter.
442 ** If neither exist, return zDefault.
443
--- src/cgi.c
+++ src/cgi.c
@@ -433,10 +433,29 @@
433 va_list ap;
434 va_start(ap, zFormat);
435 cgi_redirect(vmprintf(zFormat, ap));
436 va_end(ap);
437 }
438
439 /*
440 ** Add a "Content-disposition: attachment; filename=%s" header to the reply.
441 */
442 void cgi_content_disposition_filename(const char *zFilename){
443 /* 0123456789 123456789 123456789 123456789 123456*/
444 char *z = mprintf("Content-Disposition: attachment; filename=\"%s\";\r\n",
445 zFilename);
446 int i;
447 int n = (int)strlen(z);
448 for(i=43; i<n-4; i++){
449 char c = z[i];
450 if( isalnum(c) ) continue;
451 if( c=='.' || c=='-' || c=='/' ) continue;
452 z[i] = '_';
453 }
454 cgi_append_header(z);
455 fossil_free(z);
456 }
457
458 /*
459 ** Return the URL for the caller. This is obtained from either the
460 ** referer CGI parameter, if it exists, or the HTTP_REFERER HTTP parameter.
461 ** If neither exist, return zDefault.
462
+32 -14
--- src/info.c
+++ src/info.c
@@ -1754,13 +1754,18 @@
17541754
style_footer();
17551755
}
17561756
17571757
/*
17581758
** WEBPAGE: raw
1759
-** URL: /raw?name=ARTIFACTID&m=TYPE
1759
+** URL: /raw/ARTIFACTID
17601760
** URL: /raw?ci=BRANCH&filename=NAME
17611761
**
1762
+** Additional query parameters:
1763
+**
1764
+** m=MIMETYPE The mimetype is MIMETYPE
1765
+** at=FILENAME Content-disposition; attachment; filename=FILENAME;
1766
+**
17621767
** Return the uninterpreted content of an artifact. Used primarily
17631768
** to view artifacts that are images.
17641769
*/
17651770
void rawartifact_page(void){
17661771
int rid = 0;
@@ -1816,26 +1821,37 @@
18161821
** NULL, guess at the MIME-type based on the filename
18171822
** associated with the artifact.
18181823
*/
18191824
void deliver_artifact(int rid, const char *zMime){
18201825
Blob content;
1826
+ const char *zAttachName = P("at");
18211827
if( zMime==0 ){
1822
- char *zFName = db_text(0, "SELECT filename.name FROM mlink, filename"
1823
- " WHERE mlink.fid=%d"
1824
- " AND filename.fnid=mlink.fnid", rid);
1825
- if( !zFName ){
1828
+ char *zFN = (char*)zAttachName;
1829
+ if( zFN==0 ){
1830
+ zFN = db_text(0, "SELECT filename.name FROM mlink, filename"
1831
+ " WHERE mlink.fid=%d"
1832
+ " AND filename.fnid=mlink.fnid", rid);
1833
+ }
1834
+ if( zFN==0 ){
18261835
/* Look also at the attachment table */
1827
- zFName = db_text(0, "SELECT attachment.filename FROM attachment, blob"
1828
- " WHERE blob.rid=%d"
1829
- " AND attachment.src=blob.uuid", rid);
1836
+ zFN = db_text(0, "SELECT attachment.filename FROM attachment, blob"
1837
+ " WHERE blob.rid=%d"
1838
+ " AND attachment.src=blob.uuid", rid);
1839
+ }
1840
+ if( zFN ){
1841
+ zMime = mimetype_from_name(zFN);
18301842
}
1831
- if( zFName ) zMime = mimetype_from_name(zFName);
1832
- if( zMime==0 ) zMime = "application/x-fossil-artifact";
1843
+ if( zMime==0 ){
1844
+ zMime = "application/x-fossil-artifact";
1845
+ }
18331846
}
18341847
content_get(rid, &content);
18351848
fossil_free(style_csp(1));
18361849
cgi_set_content_type(zMime);
1850
+ if( zAttachName ){
1851
+ cgi_content_disposition_filename(zAttachName);
1852
+ }
18371853
cgi_set_content(&content);
18381854
}
18391855
18401856
/*
18411857
** Render a hex dump of a file.
@@ -1929,11 +1945,12 @@
19291945
@ :</h2>
19301946
}
19311947
blob_zero(&downloadName);
19321948
if( P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL;
19331949
object_description(rid, objdescFlags, 0, &downloadName);
1934
- style_submenu_element("Download", "%R/raw/%s", zUuid);
1950
+ style_submenu_element("Download", "%R/raw/%s?at=%T",
1951
+ zUuid, blob_str(&downloadName));
19351952
@ <hr />
19361953
content_get(rid, &content);
19371954
@ <blockquote><pre>
19381955
hexdump(&content);
19391956
@ </pre></blockquote>
@@ -2258,12 +2275,13 @@
22582275
if( asText ) objdescFlags &= ~OBJDESC_BASE;
22592276
objType = object_description(rid, objdescFlags,
22602277
(isFile?zName:0), &downloadName);
22612278
}
22622279
if( !descOnly && P("download")!=0 ){
2263
- cgi_redirectf("%R/raw/%s",
2264
- db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid));
2280
+ cgi_redirectf("%R/raw/%s?at=%T",
2281
+ db_text("x", "SELECT uuid FROM blob WHERE rid=%d", rid),
2282
+ blob_str(&downloadName));
22652283
/*NOTREACHED*/
22662284
}
22672285
if( g.perm.Admin ){
22682286
const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
22692287
if( db_exists("SELECT 1 FROM shun WHERE uuid=%Q", zUuid) ){
@@ -2304,11 +2322,11 @@
23042322
const char *zIp = db_column_text(&q,2);
23052323
@ <p>Received on %s(zDate) from %h(zUser) at %h(zIp).</p>
23062324
}
23072325
db_finalize(&q);
23082326
}
2309
- style_submenu_element("Download", "%R/raw/%s", zUuid);
2327
+ style_submenu_element("Download", "%R/raw/%s?at=%T", zUuid, zName);
23102328
if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){
23112329
style_submenu_element("Check-ins Using", "%R/timeline?n=200&uf=%s", zUuid);
23122330
}
23132331
zMime = mimetype_from_name(blob_str(&downloadName));
23142332
if( zMime ){
23152333
--- src/info.c
+++ src/info.c
@@ -1754,13 +1754,18 @@
1754 style_footer();
1755 }
1756
1757 /*
1758 ** WEBPAGE: raw
1759 ** URL: /raw?name=ARTIFACTID&m=TYPE
1760 ** URL: /raw?ci=BRANCH&filename=NAME
1761 **
 
 
 
 
 
1762 ** Return the uninterpreted content of an artifact. Used primarily
1763 ** to view artifacts that are images.
1764 */
1765 void rawartifact_page(void){
1766 int rid = 0;
@@ -1816,26 +1821,37 @@
1816 ** NULL, guess at the MIME-type based on the filename
1817 ** associated with the artifact.
1818 */
1819 void deliver_artifact(int rid, const char *zMime){
1820 Blob content;
 
1821 if( zMime==0 ){
1822 char *zFName = db_text(0, "SELECT filename.name FROM mlink, filename"
1823 " WHERE mlink.fid=%d"
1824 " AND filename.fnid=mlink.fnid", rid);
1825 if( !zFName ){
 
 
 
1826 /* Look also at the attachment table */
1827 zFName = db_text(0, "SELECT attachment.filename FROM attachment, blob"
1828 " WHERE blob.rid=%d"
1829 " AND attachment.src=blob.uuid", rid);
 
 
 
1830 }
1831 if( zFName ) zMime = mimetype_from_name(zFName);
1832 if( zMime==0 ) zMime = "application/x-fossil-artifact";
 
1833 }
1834 content_get(rid, &content);
1835 fossil_free(style_csp(1));
1836 cgi_set_content_type(zMime);
 
 
 
1837 cgi_set_content(&content);
1838 }
1839
1840 /*
1841 ** Render a hex dump of a file.
@@ -1929,11 +1945,12 @@
1929 @ :</h2>
1930 }
1931 blob_zero(&downloadName);
1932 if( P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL;
1933 object_description(rid, objdescFlags, 0, &downloadName);
1934 style_submenu_element("Download", "%R/raw/%s", zUuid);
 
1935 @ <hr />
1936 content_get(rid, &content);
1937 @ <blockquote><pre>
1938 hexdump(&content);
1939 @ </pre></blockquote>
@@ -2258,12 +2275,13 @@
2258 if( asText ) objdescFlags &= ~OBJDESC_BASE;
2259 objType = object_description(rid, objdescFlags,
2260 (isFile?zName:0), &downloadName);
2261 }
2262 if( !descOnly && P("download")!=0 ){
2263 cgi_redirectf("%R/raw/%s",
2264 db_text("?", "SELECT uuid FROM blob WHERE rid=%d", rid));
 
2265 /*NOTREACHED*/
2266 }
2267 if( g.perm.Admin ){
2268 const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
2269 if( db_exists("SELECT 1 FROM shun WHERE uuid=%Q", zUuid) ){
@@ -2304,11 +2322,11 @@
2304 const char *zIp = db_column_text(&q,2);
2305 @ <p>Received on %s(zDate) from %h(zUser) at %h(zIp).</p>
2306 }
2307 db_finalize(&q);
2308 }
2309 style_submenu_element("Download", "%R/raw/%s", zUuid);
2310 if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){
2311 style_submenu_element("Check-ins Using", "%R/timeline?n=200&uf=%s", zUuid);
2312 }
2313 zMime = mimetype_from_name(blob_str(&downloadName));
2314 if( zMime ){
2315
--- src/info.c
+++ src/info.c
@@ -1754,13 +1754,18 @@
1754 style_footer();
1755 }
1756
1757 /*
1758 ** WEBPAGE: raw
1759 ** URL: /raw/ARTIFACTID
1760 ** URL: /raw?ci=BRANCH&filename=NAME
1761 **
1762 ** Additional query parameters:
1763 **
1764 ** m=MIMETYPE The mimetype is MIMETYPE
1765 ** at=FILENAME Content-disposition; attachment; filename=FILENAME;
1766 **
1767 ** Return the uninterpreted content of an artifact. Used primarily
1768 ** to view artifacts that are images.
1769 */
1770 void rawartifact_page(void){
1771 int rid = 0;
@@ -1816,26 +1821,37 @@
1821 ** NULL, guess at the MIME-type based on the filename
1822 ** associated with the artifact.
1823 */
1824 void deliver_artifact(int rid, const char *zMime){
1825 Blob content;
1826 const char *zAttachName = P("at");
1827 if( zMime==0 ){
1828 char *zFN = (char*)zAttachName;
1829 if( zFN==0 ){
1830 zFN = db_text(0, "SELECT filename.name FROM mlink, filename"
1831 " WHERE mlink.fid=%d"
1832 " AND filename.fnid=mlink.fnid", rid);
1833 }
1834 if( zFN==0 ){
1835 /* Look also at the attachment table */
1836 zFN = db_text(0, "SELECT attachment.filename FROM attachment, blob"
1837 " WHERE blob.rid=%d"
1838 " AND attachment.src=blob.uuid", rid);
1839 }
1840 if( zFN ){
1841 zMime = mimetype_from_name(zFN);
1842 }
1843 if( zMime==0 ){
1844 zMime = "application/x-fossil-artifact";
1845 }
1846 }
1847 content_get(rid, &content);
1848 fossil_free(style_csp(1));
1849 cgi_set_content_type(zMime);
1850 if( zAttachName ){
1851 cgi_content_disposition_filename(zAttachName);
1852 }
1853 cgi_set_content(&content);
1854 }
1855
1856 /*
1857 ** Render a hex dump of a file.
@@ -1929,11 +1945,12 @@
1945 @ :</h2>
1946 }
1947 blob_zero(&downloadName);
1948 if( P("verbose")!=0 ) objdescFlags |= OBJDESC_DETAIL;
1949 object_description(rid, objdescFlags, 0, &downloadName);
1950 style_submenu_element("Download", "%R/raw/%s?at=%T",
1951 zUuid, blob_str(&downloadName));
1952 @ <hr />
1953 content_get(rid, &content);
1954 @ <blockquote><pre>
1955 hexdump(&content);
1956 @ </pre></blockquote>
@@ -2258,12 +2275,13 @@
2275 if( asText ) objdescFlags &= ~OBJDESC_BASE;
2276 objType = object_description(rid, objdescFlags,
2277 (isFile?zName:0), &downloadName);
2278 }
2279 if( !descOnly && P("download")!=0 ){
2280 cgi_redirectf("%R/raw/%s?at=%T",
2281 db_text("x", "SELECT uuid FROM blob WHERE rid=%d", rid),
2282 blob_str(&downloadName));
2283 /*NOTREACHED*/
2284 }
2285 if( g.perm.Admin ){
2286 const char *zUuid = db_text("", "SELECT uuid FROM blob WHERE rid=%d", rid);
2287 if( db_exists("SELECT 1 FROM shun WHERE uuid=%Q", zUuid) ){
@@ -2304,11 +2322,11 @@
2322 const char *zIp = db_column_text(&q,2);
2323 @ <p>Received on %s(zDate) from %h(zUser) at %h(zIp).</p>
2324 }
2325 db_finalize(&q);
2326 }
2327 style_submenu_element("Download", "%R/raw/%s?at=%T", zUuid, zName);
2328 if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){
2329 style_submenu_element("Check-ins Using", "%R/timeline?n=200&uf=%s", zUuid);
2330 }
2331 zMime = mimetype_from_name(blob_str(&downloadName));
2332 if( zMime ){
2333

Keyboard Shortcuts

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