Fossil SCM

The --share-links option on "fossil sync" and similar causes the server to reply with "pragma link" lines that identify other repositories with which the server has interacted within the past month. Those links are recorded in "link:URL" entries of the CONFIG table on the client.

drh 2021-12-21 19:50 trunk
Commit 12d2f70bdff55411e8a0df1a62d50215185e1ab3200aa350ce78959b3d8c133a
2 files changed +7 +107 -25
+7
--- src/sync.c
+++ src/sync.c
@@ -232,10 +232,15 @@
232232
*pSyncFlags |= SYNC_NOHTTPCOMPRESS;
233233
}
234234
if( find_option("all",0,0)!=0 ){
235235
*pSyncFlags |= SYNC_ALLURL;
236236
}
237
+ if( ((*pSyncFlags) & SYNC_PULL)!=0
238
+ && find_option("share-links",0,0)!=0
239
+ ){
240
+ *pSyncFlags |= SYNC_SHARE_LINKS;
241
+ }
237242
url_proxy_options();
238243
clone_ssh_find_options();
239244
if( !uvOnly ) db_find_and_open_repository(0, 0);
240245
db_open_config(0, 1);
241246
if( g.argc==2 ){
@@ -294,10 +299,11 @@
294299
** --once Do not remember URL for subsequent syncs
295300
** --private Pull private branches too
296301
** --project-code CODE Use CODE as the project code
297302
** --proxy PROXY Use the specified HTTP proxy
298303
** -R|--repository REPO Local repository to pull into
304
+** --share-links Share links to mirror repos
299305
** --ssl-identity FILE Local SSL credentials, if requested by remote
300306
** --ssh-command SSH Use SSH as the "ssh" command
301307
** -v|--verbose Additional (debugging) output
302308
** --verily Exchange extra information with the remote
303309
** to ensure no content is overlooked
@@ -392,10 +398,11 @@
392398
** --no-http-compression Do not compress HTTP traffic
393399
** --once Do not remember URL for subsequent syncs
394400
** --proxy PROXY Use the specified HTTP proxy
395401
** --private Sync private branches too
396402
** -R|--repository REPO Local repository to sync with
403
+** --share-links Share links to mirror repos
397404
** --ssl-identity FILE Local SSL credentials, if requested by remote
398405
** --ssh-command SSH Use SSH as the "ssh" command
399406
** -u|--unversioned Also sync unversioned content
400407
** -v|--verbose Additional (debugging) output
401408
** --verily Exchange extra information with the remote
402409
--- src/sync.c
+++ src/sync.c
@@ -232,10 +232,15 @@
232 *pSyncFlags |= SYNC_NOHTTPCOMPRESS;
233 }
234 if( find_option("all",0,0)!=0 ){
235 *pSyncFlags |= SYNC_ALLURL;
236 }
 
 
 
 
 
237 url_proxy_options();
238 clone_ssh_find_options();
239 if( !uvOnly ) db_find_and_open_repository(0, 0);
240 db_open_config(0, 1);
241 if( g.argc==2 ){
@@ -294,10 +299,11 @@
294 ** --once Do not remember URL for subsequent syncs
295 ** --private Pull private branches too
296 ** --project-code CODE Use CODE as the project code
297 ** --proxy PROXY Use the specified HTTP proxy
298 ** -R|--repository REPO Local repository to pull into
 
299 ** --ssl-identity FILE Local SSL credentials, if requested by remote
300 ** --ssh-command SSH Use SSH as the "ssh" command
301 ** -v|--verbose Additional (debugging) output
302 ** --verily Exchange extra information with the remote
303 ** to ensure no content is overlooked
@@ -392,10 +398,11 @@
392 ** --no-http-compression Do not compress HTTP traffic
393 ** --once Do not remember URL for subsequent syncs
394 ** --proxy PROXY Use the specified HTTP proxy
395 ** --private Sync private branches too
396 ** -R|--repository REPO Local repository to sync with
 
397 ** --ssl-identity FILE Local SSL credentials, if requested by remote
398 ** --ssh-command SSH Use SSH as the "ssh" command
399 ** -u|--unversioned Also sync unversioned content
400 ** -v|--verbose Additional (debugging) output
401 ** --verily Exchange extra information with the remote
402
--- src/sync.c
+++ src/sync.c
@@ -232,10 +232,15 @@
232 *pSyncFlags |= SYNC_NOHTTPCOMPRESS;
233 }
234 if( find_option("all",0,0)!=0 ){
235 *pSyncFlags |= SYNC_ALLURL;
236 }
237 if( ((*pSyncFlags) & SYNC_PULL)!=0
238 && find_option("share-links",0,0)!=0
239 ){
240 *pSyncFlags |= SYNC_SHARE_LINKS;
241 }
242 url_proxy_options();
243 clone_ssh_find_options();
244 if( !uvOnly ) db_find_and_open_repository(0, 0);
245 db_open_config(0, 1);
246 if( g.argc==2 ){
@@ -294,10 +299,11 @@
299 ** --once Do not remember URL for subsequent syncs
300 ** --private Pull private branches too
301 ** --project-code CODE Use CODE as the project code
302 ** --proxy PROXY Use the specified HTTP proxy
303 ** -R|--repository REPO Local repository to pull into
304 ** --share-links Share links to mirror repos
305 ** --ssl-identity FILE Local SSL credentials, if requested by remote
306 ** --ssh-command SSH Use SSH as the "ssh" command
307 ** -v|--verbose Additional (debugging) output
308 ** --verily Exchange extra information with the remote
309 ** to ensure no content is overlooked
@@ -392,10 +398,11 @@
398 ** --no-http-compression Do not compress HTTP traffic
399 ** --once Do not remember URL for subsequent syncs
400 ** --proxy PROXY Use the specified HTTP proxy
401 ** --private Sync private branches too
402 ** -R|--repository REPO Local repository to sync with
403 ** --share-links Share links to mirror repos
404 ** --ssl-identity FILE Local SSL credentials, if requested by remote
405 ** --ssh-command SSH Use SSH as the "ssh" command
406 ** -u|--unversioned Also sync unversioned content
407 ** -v|--verbose Additional (debugging) output
408 ** --verily Exchange extra information with the remote
409
+107 -25
--- src/xfer.c
+++ src/xfer.c
@@ -1209,10 +1209,11 @@
12091209
char *zUuidList = 0;
12101210
int nUuidList = 0;
12111211
char **pzUuidList = 0;
12121212
int *pnUuidList = 0;
12131213
int uvCatalogSent = 0;
1214
+ int bSendLinks = 0;
12141215
12151216
if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){
12161217
fossil_redirect_home();
12171218
}
12181219
g.zLogin = "anonymous";
@@ -1599,21 +1600,21 @@
15991600
if( !g.perm.Private ){
16001601
server_private_xfer_not_authorized();
16011602
}else{
16021603
xfer.syncPrivate = 1;
16031604
}
1604
- }
1605
+ }else
16051606
16061607
/* pragma send-catalog
16071608
**
16081609
** The client wants to see igot cards for all known artifacts.
16091610
** This is used as part of "sync --verily" to help ensure that
16101611
** no artifacts have been missed on prior syncs.
16111612
*/
16121613
if( blob_eq(&xfer.aToken[1], "send-catalog") ){
16131614
xfer.resync = 0x7fffffff;
1614
- }
1615
+ }else
16151616
16161617
/* pragma client-version VERSION ?DATE? ?TIME?
16171618
**
16181619
** The client announces to the server what version of Fossil it
16191620
** is running. The DATE and TIME are a pure numeric ISO8601 time
@@ -1625,11 +1626,11 @@
16251626
xfer.remoteDate = atoi(blob_str(&xfer.aToken[3]));
16261627
xfer.remoteTime = atoi(blob_str(&xfer.aToken[4]));
16271628
@ pragma server-version %d(RELEASE_VERSION_NUMBER) \
16281629
@ %d(MANIFEST_NUMERIC_DATE) %d(MANIFEST_NUMERIC_TIME)
16291630
}
1630
- }
1631
+ }else
16311632
16321633
/* pragma uv-hash HASH
16331634
**
16341635
** The client wants to make sure that unversioned files are all synced.
16351636
** If the HASH does not match, send a complete catalog of
@@ -1648,11 +1649,11 @@
16481649
@ pragma uv-pull-only
16491650
}
16501651
send_unversioned_catalog(&xfer);
16511652
}
16521653
uvCatalogSent = 1;
1653
- }
1654
+ }else
16541655
16551656
/* pragma ci-lock CHECKIN-HASH CLIENT-ID
16561657
**
16571658
** The client wants to make non-branch commit against the check-in
16581659
** identified by CHECKIN-HASH. The server will remember this and
@@ -1708,11 +1709,11 @@
17081709
db_protect_pop();
17091710
}
17101711
if( db_get_boolean("forbid-delta-manifests",0) ){
17111712
@ pragma avoid-delta-manifests
17121713
}
1713
- }
1714
+ }else
17141715
17151716
/* pragma ci-unlock CLIENT-ID
17161717
**
17171718
** Remove any locks previously held by CLIENT-ID. Clients send this
17181719
** pragma with their own ID whenever they know that they no longer
@@ -1728,11 +1729,11 @@
17281729
" WHERE name GLOB 'ci-lock-*'"
17291730
" AND json_extract(value,'$.clientid')=%Q",
17301731
blob_str(&xfer.aToken[2])
17311732
);
17321733
db_protect_pop();
1733
- }
1734
+ }else
17341735
17351736
/* pragma client-url URL
17361737
**
17371738
** This pragma is an informational notification to the server that
17381739
** their relationship could, in theory, be inverted by having the
@@ -1741,10 +1742,19 @@
17411742
if( blob_eq(&xfer.aToken[1], "client-url")
17421743
&& xfer.nToken==3
17431744
&& g.perm.Write
17441745
){
17451746
xfer_syncwith(blob_str(&xfer.aToken[2]), 1);
1747
+ }else
1748
+
1749
+ /* pragma req-links
1750
+ **
1751
+ ** The client sends this message to the server to ask the server
1752
+ ** to tell it about alternative repositories in the reply.
1753
+ */
1754
+ if( blob_eq(&xfer.aToken[1], "req-links") ){
1755
+ bSendLinks = 1;
17461756
}
17471757
17481758
}else
17491759
17501760
/* Unknown message
@@ -1786,10 +1796,45 @@
17861796
if( xfer.syncPrivate ) send_private(&xfer);
17871797
}
17881798
hook_expecting_more_artifacts(xfer.nGimmeSent?60:0);
17891799
db_multi_exec("DROP TABLE onremote; DROP TABLE unk;");
17901800
manifest_crosslink_end(MC_PERMIT_HOOKS);
1801
+
1802
+ /* Send URLs for alternative repositories for the same project,
1803
+ ** if requested by the client. */
1804
+ if( bSendLinks && g.zBaseURL ){
1805
+ Stmt q;
1806
+ db_prepare(&q,
1807
+ "WITH remote(mtime, url, arg) AS (\n"
1808
+ " SELECT mtime, substr(name,10), '{}' FROM config\n"
1809
+ " WHERE name GLOB 'syncwith:http*'\n"
1810
+ " UNION ALL\n"
1811
+ " SELECT mtime, substr(name,10), '{}' FROM config\n"
1812
+ " WHERE name GLOB 'syncfrom:http*'\n"
1813
+ " UNION ALL\n"
1814
+ " SELECT mtime, substr(name,9), '{\"type\":\"git\"}' FROM config\n"
1815
+ " WHERE name GLOB 'gitpush:*'\n"
1816
+ ")\n"
1817
+ "SELECT url, json_insert(arg,'$.src',%Q), max(mtime)\n"
1818
+ " FROM remote WHERE mtime>unixepoch('now','-1 month')\n"
1819
+ " GROUP BY url;",
1820
+ g.zBaseURL
1821
+ );
1822
+ while( db_step(&q)==SQLITE_ROW ){
1823
+ UrlData x;
1824
+ const char *zUrl = db_column_text(&q, 0);
1825
+ const char *zArg = db_column_text(&q, 1);
1826
+ i64 iMtime = db_column_int64(&q, 2);
1827
+ memset(&x, 0, sizeof(x));
1828
+ url_parse_local(zUrl, URL_OMIT_USER, &x);
1829
+ if( x.name!=0 && sqlite3_strlike("%localhost%", x.name, 0)!=0 ){
1830
+ @ pragma link %F(x.canonical) %F(zArg) %lld(iMtime)
1831
+ }
1832
+ url_unparse(&x);
1833
+ }
1834
+ db_finalize(&q);
1835
+ }
17911836
17921837
/* Send the server timestamp last, in case prior processing happened
17931838
** to use up a significant fraction of our time window.
17941839
*/
17951840
zNow = db_text(0, "SELECT strftime('%%Y-%%m-%%dT%%H:%%M:%%S', 'now')");
@@ -1842,25 +1887,26 @@
18421887
18431888
#if INTERFACE
18441889
/*
18451890
** Flag options for controlling client_sync()
18461891
*/
1847
-#define SYNC_PUSH 0x0001 /* push content client to server */
1848
-#define SYNC_PULL 0x0002 /* pull content server to client */
1849
-#define SYNC_CLONE 0x0004 /* clone the repository */
1850
-#define SYNC_PRIVATE 0x0008 /* Also transfer private content */
1851
-#define SYNC_VERBOSE 0x0010 /* Extra diagnostics */
1852
-#define SYNC_RESYNC 0x0020 /* --verily */
1853
-#define SYNC_FROMPARENT 0x0040 /* Pull from the parent project */
1854
-#define SYNC_UNVERSIONED 0x0100 /* Sync unversioned content */
1855
-#define SYNC_UV_REVERT 0x0200 /* Copy server unversioned to client */
1856
-#define SYNC_UV_TRACE 0x0400 /* Describe UV activities */
1857
-#define SYNC_UV_DRYRUN 0x0800 /* Do not actually exchange files */
1858
-#define SYNC_IFABLE 0x1000 /* Inability to sync is not fatal */
1859
-#define SYNC_CKIN_LOCK 0x2000 /* Lock the current check-in */
1860
-#define SYNC_NOHTTPCOMPRESS 0x4000 /* Do not compression HTTP messages */
1861
-#define SYNC_ALLURL 0x8000 /* The --all flag - sync to all URLs */
1892
+#define SYNC_PUSH 0x00001 /* push content client to server */
1893
+#define SYNC_PULL 0x00002 /* pull content server to client */
1894
+#define SYNC_CLONE 0x00004 /* clone the repository */
1895
+#define SYNC_PRIVATE 0x00008 /* Also transfer private content */
1896
+#define SYNC_VERBOSE 0x00010 /* Extra diagnostics */
1897
+#define SYNC_RESYNC 0x00020 /* --verily */
1898
+#define SYNC_FROMPARENT 0x00040 /* Pull from the parent project */
1899
+#define SYNC_UNVERSIONED 0x00100 /* Sync unversioned content */
1900
+#define SYNC_UV_REVERT 0x00200 /* Copy server unversioned to client */
1901
+#define SYNC_UV_TRACE 0x00400 /* Describe UV activities */
1902
+#define SYNC_UV_DRYRUN 0x00800 /* Do not actually exchange files */
1903
+#define SYNC_IFABLE 0x01000 /* Inability to sync is not fatal */
1904
+#define SYNC_CKIN_LOCK 0x02000 /* Lock the current check-in */
1905
+#define SYNC_NOHTTPCOMPRESS 0x04000 /* Do not compression HTTP messages */
1906
+#define SYNC_ALLURL 0x08000 /* The --all flag - sync to all URLs */
1907
+#define SYNC_SHARE_LINKS 0x10000 /* Request alternate repo links */
18621908
#endif
18631909
18641910
/*
18651911
** Floating-point absolute value
18661912
*/
@@ -2052,14 +2098,14 @@
20522098
if( zSelfUrl ){
20532099
blob_appendf(&send, "pragma client-url %s\n", zSelfUrl);
20542100
}
20552101
}
20562102
2057
- /* Request names of alternative repositories
2103
+ /* Request URLs of alternative repositories
20582104
*/
2059
- if( zAltPCode==0 ){
2060
- blob_appendf(&send, "pragma req-alt-repo\n");
2105
+ if( zAltPCode==0 && (syncFlags & SYNC_SHARE_LINKS)!=0 ){
2106
+ blob_appendf(&send, "pragma req-links\n");
20612107
}
20622108
20632109
while( go ){
20642110
int newPhantom = 0;
20652111
char *zRandomness;
@@ -2590,11 +2636,11 @@
25902636
** this client lacks the necessary permissions) then it sends a
25912637
** "uv-pull-only" pragma so that the client will know not to waste
25922638
** bandwidth trying to upload unversioned content. If the server
25932639
** does accept new unversioned content, it sends "uv-push-ok".
25942640
*/
2595
- if( syncFlags & SYNC_UNVERSIONED ){
2641
+ else if( syncFlags & SYNC_UNVERSIONED ){
25962642
if( blob_eq(&xfer.aToken[1], "uv-pull-only") ){
25972643
uvPullOnly = 1;
25982644
if( syncFlags & SYNC_UV_REVERT ) uvDoPush = 1;
25992645
}else if( blob_eq(&xfer.aToken[1], "uv-push-ok") ){
26002646
uvDoPush = 1;
@@ -2630,10 +2676,46 @@
26302676
** this pragma when its forbid-delta-manifests setting is true.
26312677
*/
26322678
else if( blob_eq(&xfer.aToken[1], "avoid-delta-manifests") ){
26332679
g.bAvoidDeltaManifests = 1;
26342680
}
2681
+
2682
+ /* pragma link URL ARG MTIME
2683
+ **
2684
+ ** The server has sent the URL for a link to another repository.
2685
+ ** Record this as a link:URL entry in the config table.
2686
+ */
2687
+ else if( blob_eq(&xfer.aToken[1], "link")
2688
+ && xfer.nToken==5
2689
+ && (syncFlags & SYNC_SHARE_LINKS)!=0
2690
+ ){
2691
+ UrlData x;
2692
+ char *zUrl = blob_str(&xfer.aToken[2]);
2693
+ char *zArg = blob_str(&xfer.aToken[3]);
2694
+ i64 iTime = strtoll(blob_str(&xfer.aToken[4]),0,0);
2695
+ memset(&x, 0, sizeof(x));
2696
+ defossilize(zUrl);
2697
+ defossilize(zArg);
2698
+ url_parse_local(zUrl, URL_OMIT_USER, &x);
2699
+ if( x.protocol
2700
+ && strncmp(x.protocol,"http",4)==0
2701
+ && iTime>0
2702
+ ){
2703
+ db_unprotect(PROTECT_CONFIG);
2704
+ db_multi_exec(
2705
+ "INSERT INTO config(name,value,mtime)\n"
2706
+ " VALUES('link:%q',%Q,%lld)\n"
2707
+ " ON CONFLICT DO UPDATE\n"
2708
+ " SET value=excluded.value, mtime=excluded.mtime\n"
2709
+ " WHERE mtime<excluded.mtime;",
2710
+ zUrl, zArg, iTime
2711
+ );
2712
+ db_protect_pop();
2713
+ }
2714
+ url_unparse(&x);
2715
+ }
2716
+
26352717
}else
26362718
26372719
/* error MESSAGE
26382720
**
26392721
** The server is reporting an error. The client will abandon
26402722
--- src/xfer.c
+++ src/xfer.c
@@ -1209,10 +1209,11 @@
1209 char *zUuidList = 0;
1210 int nUuidList = 0;
1211 char **pzUuidList = 0;
1212 int *pnUuidList = 0;
1213 int uvCatalogSent = 0;
 
1214
1215 if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){
1216 fossil_redirect_home();
1217 }
1218 g.zLogin = "anonymous";
@@ -1599,21 +1600,21 @@
1599 if( !g.perm.Private ){
1600 server_private_xfer_not_authorized();
1601 }else{
1602 xfer.syncPrivate = 1;
1603 }
1604 }
1605
1606 /* pragma send-catalog
1607 **
1608 ** The client wants to see igot cards for all known artifacts.
1609 ** This is used as part of "sync --verily" to help ensure that
1610 ** no artifacts have been missed on prior syncs.
1611 */
1612 if( blob_eq(&xfer.aToken[1], "send-catalog") ){
1613 xfer.resync = 0x7fffffff;
1614 }
1615
1616 /* pragma client-version VERSION ?DATE? ?TIME?
1617 **
1618 ** The client announces to the server what version of Fossil it
1619 ** is running. The DATE and TIME are a pure numeric ISO8601 time
@@ -1625,11 +1626,11 @@
1625 xfer.remoteDate = atoi(blob_str(&xfer.aToken[3]));
1626 xfer.remoteTime = atoi(blob_str(&xfer.aToken[4]));
1627 @ pragma server-version %d(RELEASE_VERSION_NUMBER) \
1628 @ %d(MANIFEST_NUMERIC_DATE) %d(MANIFEST_NUMERIC_TIME)
1629 }
1630 }
1631
1632 /* pragma uv-hash HASH
1633 **
1634 ** The client wants to make sure that unversioned files are all synced.
1635 ** If the HASH does not match, send a complete catalog of
@@ -1648,11 +1649,11 @@
1648 @ pragma uv-pull-only
1649 }
1650 send_unversioned_catalog(&xfer);
1651 }
1652 uvCatalogSent = 1;
1653 }
1654
1655 /* pragma ci-lock CHECKIN-HASH CLIENT-ID
1656 **
1657 ** The client wants to make non-branch commit against the check-in
1658 ** identified by CHECKIN-HASH. The server will remember this and
@@ -1708,11 +1709,11 @@
1708 db_protect_pop();
1709 }
1710 if( db_get_boolean("forbid-delta-manifests",0) ){
1711 @ pragma avoid-delta-manifests
1712 }
1713 }
1714
1715 /* pragma ci-unlock CLIENT-ID
1716 **
1717 ** Remove any locks previously held by CLIENT-ID. Clients send this
1718 ** pragma with their own ID whenever they know that they no longer
@@ -1728,11 +1729,11 @@
1728 " WHERE name GLOB 'ci-lock-*'"
1729 " AND json_extract(value,'$.clientid')=%Q",
1730 blob_str(&xfer.aToken[2])
1731 );
1732 db_protect_pop();
1733 }
1734
1735 /* pragma client-url URL
1736 **
1737 ** This pragma is an informational notification to the server that
1738 ** their relationship could, in theory, be inverted by having the
@@ -1741,10 +1742,19 @@
1741 if( blob_eq(&xfer.aToken[1], "client-url")
1742 && xfer.nToken==3
1743 && g.perm.Write
1744 ){
1745 xfer_syncwith(blob_str(&xfer.aToken[2]), 1);
 
 
 
 
 
 
 
 
 
1746 }
1747
1748 }else
1749
1750 /* Unknown message
@@ -1786,10 +1796,45 @@
1786 if( xfer.syncPrivate ) send_private(&xfer);
1787 }
1788 hook_expecting_more_artifacts(xfer.nGimmeSent?60:0);
1789 db_multi_exec("DROP TABLE onremote; DROP TABLE unk;");
1790 manifest_crosslink_end(MC_PERMIT_HOOKS);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1791
1792 /* Send the server timestamp last, in case prior processing happened
1793 ** to use up a significant fraction of our time window.
1794 */
1795 zNow = db_text(0, "SELECT strftime('%%Y-%%m-%%dT%%H:%%M:%%S', 'now')");
@@ -1842,25 +1887,26 @@
1842
1843 #if INTERFACE
1844 /*
1845 ** Flag options for controlling client_sync()
1846 */
1847 #define SYNC_PUSH 0x0001 /* push content client to server */
1848 #define SYNC_PULL 0x0002 /* pull content server to client */
1849 #define SYNC_CLONE 0x0004 /* clone the repository */
1850 #define SYNC_PRIVATE 0x0008 /* Also transfer private content */
1851 #define SYNC_VERBOSE 0x0010 /* Extra diagnostics */
1852 #define SYNC_RESYNC 0x0020 /* --verily */
1853 #define SYNC_FROMPARENT 0x0040 /* Pull from the parent project */
1854 #define SYNC_UNVERSIONED 0x0100 /* Sync unversioned content */
1855 #define SYNC_UV_REVERT 0x0200 /* Copy server unversioned to client */
1856 #define SYNC_UV_TRACE 0x0400 /* Describe UV activities */
1857 #define SYNC_UV_DRYRUN 0x0800 /* Do not actually exchange files */
1858 #define SYNC_IFABLE 0x1000 /* Inability to sync is not fatal */
1859 #define SYNC_CKIN_LOCK 0x2000 /* Lock the current check-in */
1860 #define SYNC_NOHTTPCOMPRESS 0x4000 /* Do not compression HTTP messages */
1861 #define SYNC_ALLURL 0x8000 /* The --all flag - sync to all URLs */
 
1862 #endif
1863
1864 /*
1865 ** Floating-point absolute value
1866 */
@@ -2052,14 +2098,14 @@
2052 if( zSelfUrl ){
2053 blob_appendf(&send, "pragma client-url %s\n", zSelfUrl);
2054 }
2055 }
2056
2057 /* Request names of alternative repositories
2058 */
2059 if( zAltPCode==0 ){
2060 blob_appendf(&send, "pragma req-alt-repo\n");
2061 }
2062
2063 while( go ){
2064 int newPhantom = 0;
2065 char *zRandomness;
@@ -2590,11 +2636,11 @@
2590 ** this client lacks the necessary permissions) then it sends a
2591 ** "uv-pull-only" pragma so that the client will know not to waste
2592 ** bandwidth trying to upload unversioned content. If the server
2593 ** does accept new unversioned content, it sends "uv-push-ok".
2594 */
2595 if( syncFlags & SYNC_UNVERSIONED ){
2596 if( blob_eq(&xfer.aToken[1], "uv-pull-only") ){
2597 uvPullOnly = 1;
2598 if( syncFlags & SYNC_UV_REVERT ) uvDoPush = 1;
2599 }else if( blob_eq(&xfer.aToken[1], "uv-push-ok") ){
2600 uvDoPush = 1;
@@ -2630,10 +2676,46 @@
2630 ** this pragma when its forbid-delta-manifests setting is true.
2631 */
2632 else if( blob_eq(&xfer.aToken[1], "avoid-delta-manifests") ){
2633 g.bAvoidDeltaManifests = 1;
2634 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2635 }else
2636
2637 /* error MESSAGE
2638 **
2639 ** The server is reporting an error. The client will abandon
2640
--- src/xfer.c
+++ src/xfer.c
@@ -1209,10 +1209,11 @@
1209 char *zUuidList = 0;
1210 int nUuidList = 0;
1211 char **pzUuidList = 0;
1212 int *pnUuidList = 0;
1213 int uvCatalogSent = 0;
1214 int bSendLinks = 0;
1215
1216 if( fossil_strcmp(PD("REQUEST_METHOD","POST"),"POST") ){
1217 fossil_redirect_home();
1218 }
1219 g.zLogin = "anonymous";
@@ -1599,21 +1600,21 @@
1600 if( !g.perm.Private ){
1601 server_private_xfer_not_authorized();
1602 }else{
1603 xfer.syncPrivate = 1;
1604 }
1605 }else
1606
1607 /* pragma send-catalog
1608 **
1609 ** The client wants to see igot cards for all known artifacts.
1610 ** This is used as part of "sync --verily" to help ensure that
1611 ** no artifacts have been missed on prior syncs.
1612 */
1613 if( blob_eq(&xfer.aToken[1], "send-catalog") ){
1614 xfer.resync = 0x7fffffff;
1615 }else
1616
1617 /* pragma client-version VERSION ?DATE? ?TIME?
1618 **
1619 ** The client announces to the server what version of Fossil it
1620 ** is running. The DATE and TIME are a pure numeric ISO8601 time
@@ -1625,11 +1626,11 @@
1626 xfer.remoteDate = atoi(blob_str(&xfer.aToken[3]));
1627 xfer.remoteTime = atoi(blob_str(&xfer.aToken[4]));
1628 @ pragma server-version %d(RELEASE_VERSION_NUMBER) \
1629 @ %d(MANIFEST_NUMERIC_DATE) %d(MANIFEST_NUMERIC_TIME)
1630 }
1631 }else
1632
1633 /* pragma uv-hash HASH
1634 **
1635 ** The client wants to make sure that unversioned files are all synced.
1636 ** If the HASH does not match, send a complete catalog of
@@ -1648,11 +1649,11 @@
1649 @ pragma uv-pull-only
1650 }
1651 send_unversioned_catalog(&xfer);
1652 }
1653 uvCatalogSent = 1;
1654 }else
1655
1656 /* pragma ci-lock CHECKIN-HASH CLIENT-ID
1657 **
1658 ** The client wants to make non-branch commit against the check-in
1659 ** identified by CHECKIN-HASH. The server will remember this and
@@ -1708,11 +1709,11 @@
1709 db_protect_pop();
1710 }
1711 if( db_get_boolean("forbid-delta-manifests",0) ){
1712 @ pragma avoid-delta-manifests
1713 }
1714 }else
1715
1716 /* pragma ci-unlock CLIENT-ID
1717 **
1718 ** Remove any locks previously held by CLIENT-ID. Clients send this
1719 ** pragma with their own ID whenever they know that they no longer
@@ -1728,11 +1729,11 @@
1729 " WHERE name GLOB 'ci-lock-*'"
1730 " AND json_extract(value,'$.clientid')=%Q",
1731 blob_str(&xfer.aToken[2])
1732 );
1733 db_protect_pop();
1734 }else
1735
1736 /* pragma client-url URL
1737 **
1738 ** This pragma is an informational notification to the server that
1739 ** their relationship could, in theory, be inverted by having the
@@ -1741,10 +1742,19 @@
1742 if( blob_eq(&xfer.aToken[1], "client-url")
1743 && xfer.nToken==3
1744 && g.perm.Write
1745 ){
1746 xfer_syncwith(blob_str(&xfer.aToken[2]), 1);
1747 }else
1748
1749 /* pragma req-links
1750 **
1751 ** The client sends this message to the server to ask the server
1752 ** to tell it about alternative repositories in the reply.
1753 */
1754 if( blob_eq(&xfer.aToken[1], "req-links") ){
1755 bSendLinks = 1;
1756 }
1757
1758 }else
1759
1760 /* Unknown message
@@ -1786,10 +1796,45 @@
1796 if( xfer.syncPrivate ) send_private(&xfer);
1797 }
1798 hook_expecting_more_artifacts(xfer.nGimmeSent?60:0);
1799 db_multi_exec("DROP TABLE onremote; DROP TABLE unk;");
1800 manifest_crosslink_end(MC_PERMIT_HOOKS);
1801
1802 /* Send URLs for alternative repositories for the same project,
1803 ** if requested by the client. */
1804 if( bSendLinks && g.zBaseURL ){
1805 Stmt q;
1806 db_prepare(&q,
1807 "WITH remote(mtime, url, arg) AS (\n"
1808 " SELECT mtime, substr(name,10), '{}' FROM config\n"
1809 " WHERE name GLOB 'syncwith:http*'\n"
1810 " UNION ALL\n"
1811 " SELECT mtime, substr(name,10), '{}' FROM config\n"
1812 " WHERE name GLOB 'syncfrom:http*'\n"
1813 " UNION ALL\n"
1814 " SELECT mtime, substr(name,9), '{\"type\":\"git\"}' FROM config\n"
1815 " WHERE name GLOB 'gitpush:*'\n"
1816 ")\n"
1817 "SELECT url, json_insert(arg,'$.src',%Q), max(mtime)\n"
1818 " FROM remote WHERE mtime>unixepoch('now','-1 month')\n"
1819 " GROUP BY url;",
1820 g.zBaseURL
1821 );
1822 while( db_step(&q)==SQLITE_ROW ){
1823 UrlData x;
1824 const char *zUrl = db_column_text(&q, 0);
1825 const char *zArg = db_column_text(&q, 1);
1826 i64 iMtime = db_column_int64(&q, 2);
1827 memset(&x, 0, sizeof(x));
1828 url_parse_local(zUrl, URL_OMIT_USER, &x);
1829 if( x.name!=0 && sqlite3_strlike("%localhost%", x.name, 0)!=0 ){
1830 @ pragma link %F(x.canonical) %F(zArg) %lld(iMtime)
1831 }
1832 url_unparse(&x);
1833 }
1834 db_finalize(&q);
1835 }
1836
1837 /* Send the server timestamp last, in case prior processing happened
1838 ** to use up a significant fraction of our time window.
1839 */
1840 zNow = db_text(0, "SELECT strftime('%%Y-%%m-%%dT%%H:%%M:%%S', 'now')");
@@ -1842,25 +1887,26 @@
1887
1888 #if INTERFACE
1889 /*
1890 ** Flag options for controlling client_sync()
1891 */
1892 #define SYNC_PUSH 0x00001 /* push content client to server */
1893 #define SYNC_PULL 0x00002 /* pull content server to client */
1894 #define SYNC_CLONE 0x00004 /* clone the repository */
1895 #define SYNC_PRIVATE 0x00008 /* Also transfer private content */
1896 #define SYNC_VERBOSE 0x00010 /* Extra diagnostics */
1897 #define SYNC_RESYNC 0x00020 /* --verily */
1898 #define SYNC_FROMPARENT 0x00040 /* Pull from the parent project */
1899 #define SYNC_UNVERSIONED 0x00100 /* Sync unversioned content */
1900 #define SYNC_UV_REVERT 0x00200 /* Copy server unversioned to client */
1901 #define SYNC_UV_TRACE 0x00400 /* Describe UV activities */
1902 #define SYNC_UV_DRYRUN 0x00800 /* Do not actually exchange files */
1903 #define SYNC_IFABLE 0x01000 /* Inability to sync is not fatal */
1904 #define SYNC_CKIN_LOCK 0x02000 /* Lock the current check-in */
1905 #define SYNC_NOHTTPCOMPRESS 0x04000 /* Do not compression HTTP messages */
1906 #define SYNC_ALLURL 0x08000 /* The --all flag - sync to all URLs */
1907 #define SYNC_SHARE_LINKS 0x10000 /* Request alternate repo links */
1908 #endif
1909
1910 /*
1911 ** Floating-point absolute value
1912 */
@@ -2052,14 +2098,14 @@
2098 if( zSelfUrl ){
2099 blob_appendf(&send, "pragma client-url %s\n", zSelfUrl);
2100 }
2101 }
2102
2103 /* Request URLs of alternative repositories
2104 */
2105 if( zAltPCode==0 && (syncFlags & SYNC_SHARE_LINKS)!=0 ){
2106 blob_appendf(&send, "pragma req-links\n");
2107 }
2108
2109 while( go ){
2110 int newPhantom = 0;
2111 char *zRandomness;
@@ -2590,11 +2636,11 @@
2636 ** this client lacks the necessary permissions) then it sends a
2637 ** "uv-pull-only" pragma so that the client will know not to waste
2638 ** bandwidth trying to upload unversioned content. If the server
2639 ** does accept new unversioned content, it sends "uv-push-ok".
2640 */
2641 else if( syncFlags & SYNC_UNVERSIONED ){
2642 if( blob_eq(&xfer.aToken[1], "uv-pull-only") ){
2643 uvPullOnly = 1;
2644 if( syncFlags & SYNC_UV_REVERT ) uvDoPush = 1;
2645 }else if( blob_eq(&xfer.aToken[1], "uv-push-ok") ){
2646 uvDoPush = 1;
@@ -2630,10 +2676,46 @@
2676 ** this pragma when its forbid-delta-manifests setting is true.
2677 */
2678 else if( blob_eq(&xfer.aToken[1], "avoid-delta-manifests") ){
2679 g.bAvoidDeltaManifests = 1;
2680 }
2681
2682 /* pragma link URL ARG MTIME
2683 **
2684 ** The server has sent the URL for a link to another repository.
2685 ** Record this as a link:URL entry in the config table.
2686 */
2687 else if( blob_eq(&xfer.aToken[1], "link")
2688 && xfer.nToken==5
2689 && (syncFlags & SYNC_SHARE_LINKS)!=0
2690 ){
2691 UrlData x;
2692 char *zUrl = blob_str(&xfer.aToken[2]);
2693 char *zArg = blob_str(&xfer.aToken[3]);
2694 i64 iTime = strtoll(blob_str(&xfer.aToken[4]),0,0);
2695 memset(&x, 0, sizeof(x));
2696 defossilize(zUrl);
2697 defossilize(zArg);
2698 url_parse_local(zUrl, URL_OMIT_USER, &x);
2699 if( x.protocol
2700 && strncmp(x.protocol,"http",4)==0
2701 && iTime>0
2702 ){
2703 db_unprotect(PROTECT_CONFIG);
2704 db_multi_exec(
2705 "INSERT INTO config(name,value,mtime)\n"
2706 " VALUES('link:%q',%Q,%lld)\n"
2707 " ON CONFLICT DO UPDATE\n"
2708 " SET value=excluded.value, mtime=excluded.mtime\n"
2709 " WHERE mtime<excluded.mtime;",
2710 zUrl, zArg, iTime
2711 );
2712 db_protect_pop();
2713 }
2714 url_unparse(&x);
2715 }
2716
2717 }else
2718
2719 /* error MESSAGE
2720 **
2721 ** The server is reporting an error. The client will abandon
2722

Keyboard Shortcuts

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