Fossil SCM

Add preliminary support for URL aliasing. Create aliases by visiting the "URL Aliases" subscreen under the Setup menu.

drh 2017-09-20 03:27 trunk
Commit 8131f1c5d9079af90532cd2d901b923fdd230ef6f067c48320acad7d35795fd1
--- src/dispatch.c
+++ src/dispatch.c
@@ -123,10 +123,77 @@
123123
return 0; /* Prefix match */
124124
}
125125
}
126126
return 1; /* Not found */
127127
}
128
+
129
+/*
130
+** zName is the name of a webpage (eType==CMDFLAGS_WEBPAGE) that does not
131
+** exist in the dispatch table. Check to see if this webpage name exists
132
+** as an alias in the CONFIG table of the repository. If it is, then make
133
+** appropriate changes to the CGI environment and set *ppCmd to point to the
134
+** alised command.
135
+**
136
+** Return 0 if the command is successfully aliased. Return 1 if there
137
+** is not alias for zName. Any kind of error in the alias value causes a
138
+** error to be thrown.
139
+**
140
+** Alias entries in the CONFIG table have a "name" value of "walise:NAME"
141
+** where NAME is the input page name. The value is a string of the form
142
+** "NEWNAME?QUERYPARAMS". The ?QUERYPARAMS is optional. If present (and it
143
+** usually is, then all query parameters are added to the CGI environment.
144
+** Except, query parameters of the form "X!" cause any CGI X variable to be
145
+** removed.
146
+*/
147
+int dispatch_alias(const char *zName, const CmdOrPage **ppCmd){
148
+ char *z;
149
+ char *zQ;
150
+ int i, j;
151
+ char c;
152
+
153
+ z = db_text(0, "SELECT value FROM config WHERE name='walias:%q'",zName);
154
+ if( z==0 ) return 1;
155
+ for(i=0; z[i] && z[i]!='?'; i++){}
156
+ if( z[i]=='?' ){
157
+ z[i] = 0;
158
+ zQ = &z[i+1];
159
+ }else{
160
+ zQ = &z[i];
161
+ }
162
+ if( dispatch_name_search(z, CMDFLAG_WEBPAGE, ppCmd) ){
163
+ fossil_fatal("\"%s\" aliased to \"%s\" but \"%s\" does not exist",
164
+ zName, z, z);
165
+ }
166
+ z = zQ;
167
+ while( *z ){
168
+ char *zName = z;
169
+ char *zValue;
170
+ while( *z && *z!='=' && *z!='&' && *z!='!' ){ z++; }
171
+ if( *z=='=' ){
172
+ *z = 0;
173
+ z++;
174
+ zValue = z;
175
+ while( *z && *z!='&' ){ z++; }
176
+ if( *z ){
177
+ *z = 0;
178
+ z++;
179
+ }
180
+ dehttpize(zValue);
181
+ }else if( *z=='!' ){
182
+ *(z++) = 0;
183
+ cgi_delete_query_parameter(zName);
184
+ zName = "";
185
+ }else{
186
+ if( *z ){ *z++ = 0; }
187
+ zValue = "";
188
+ }
189
+ if( fossil_islower(zName[0]) ){
190
+ cgi_replace_query_parameter(zName, zValue);
191
+ }
192
+ }
193
+ return 0;
194
+}
128195
129196
/*
130197
** Fill Blob with a space-separated list of all command names that
131198
** match the prefix zPrefix.
132199
*/
133200
--- src/dispatch.c
+++ src/dispatch.c
@@ -123,10 +123,77 @@
123 return 0; /* Prefix match */
124 }
125 }
126 return 1; /* Not found */
127 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
129 /*
130 ** Fill Blob with a space-separated list of all command names that
131 ** match the prefix zPrefix.
132 */
133
--- src/dispatch.c
+++ src/dispatch.c
@@ -123,10 +123,77 @@
123 return 0; /* Prefix match */
124 }
125 }
126 return 1; /* Not found */
127 }
128
129 /*
130 ** zName is the name of a webpage (eType==CMDFLAGS_WEBPAGE) that does not
131 ** exist in the dispatch table. Check to see if this webpage name exists
132 ** as an alias in the CONFIG table of the repository. If it is, then make
133 ** appropriate changes to the CGI environment and set *ppCmd to point to the
134 ** alised command.
135 **
136 ** Return 0 if the command is successfully aliased. Return 1 if there
137 ** is not alias for zName. Any kind of error in the alias value causes a
138 ** error to be thrown.
139 **
140 ** Alias entries in the CONFIG table have a "name" value of "walise:NAME"
141 ** where NAME is the input page name. The value is a string of the form
142 ** "NEWNAME?QUERYPARAMS". The ?QUERYPARAMS is optional. If present (and it
143 ** usually is, then all query parameters are added to the CGI environment.
144 ** Except, query parameters of the form "X!" cause any CGI X variable to be
145 ** removed.
146 */
147 int dispatch_alias(const char *zName, const CmdOrPage **ppCmd){
148 char *z;
149 char *zQ;
150 int i, j;
151 char c;
152
153 z = db_text(0, "SELECT value FROM config WHERE name='walias:%q'",zName);
154 if( z==0 ) return 1;
155 for(i=0; z[i] && z[i]!='?'; i++){}
156 if( z[i]=='?' ){
157 z[i] = 0;
158 zQ = &z[i+1];
159 }else{
160 zQ = &z[i];
161 }
162 if( dispatch_name_search(z, CMDFLAG_WEBPAGE, ppCmd) ){
163 fossil_fatal("\"%s\" aliased to \"%s\" but \"%s\" does not exist",
164 zName, z, z);
165 }
166 z = zQ;
167 while( *z ){
168 char *zName = z;
169 char *zValue;
170 while( *z && *z!='=' && *z!='&' && *z!='!' ){ z++; }
171 if( *z=='=' ){
172 *z = 0;
173 z++;
174 zValue = z;
175 while( *z && *z!='&' ){ z++; }
176 if( *z ){
177 *z = 0;
178 z++;
179 }
180 dehttpize(zValue);
181 }else if( *z=='!' ){
182 *(z++) = 0;
183 cgi_delete_query_parameter(zName);
184 zName = "";
185 }else{
186 if( *z ){ *z++ = 0; }
187 zValue = "";
188 }
189 if( fossil_islower(zName[0]) ){
190 cgi_replace_query_parameter(zName, zValue);
191 }
192 }
193 return 0;
194 }
195
196 /*
197 ** Fill Blob with a space-separated list of all command names that
198 ** match the prefix zPrefix.
199 */
200
+3 -1
--- src/main.c
+++ src/main.c
@@ -1616,11 +1616,13 @@
16161616
}
16171617
16181618
/* Locate the method specified by the path and execute the function
16191619
** that implements that method.
16201620
*/
1621
- if( dispatch_name_search(g.zPath-1, CMDFLAG_WEBPAGE, &pCmd) ){
1621
+ if( dispatch_name_search(g.zPath-1, CMDFLAG_WEBPAGE, &pCmd)
1622
+ && dispatch_alias(g.zPath-1, &pCmd)
1623
+ ){
16221624
#ifdef FOSSIL_ENABLE_JSON
16231625
if(g.json.isJsonMode){
16241626
json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,0);
16251627
}else
16261628
#endif
16271629
--- src/main.c
+++ src/main.c
@@ -1616,11 +1616,13 @@
1616 }
1617
1618 /* Locate the method specified by the path and execute the function
1619 ** that implements that method.
1620 */
1621 if( dispatch_name_search(g.zPath-1, CMDFLAG_WEBPAGE, &pCmd) ){
 
 
1622 #ifdef FOSSIL_ENABLE_JSON
1623 if(g.json.isJsonMode){
1624 json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,0);
1625 }else
1626 #endif
1627
--- src/main.c
+++ src/main.c
@@ -1616,11 +1616,13 @@
1616 }
1617
1618 /* Locate the method specified by the path and execute the function
1619 ** that implements that method.
1620 */
1621 if( dispatch_name_search(g.zPath-1, CMDFLAG_WEBPAGE, &pCmd)
1622 && dispatch_alias(g.zPath-1, &pCmd)
1623 ){
1624 #ifdef FOSSIL_ENABLE_JSON
1625 if(g.json.isJsonMode){
1626 json_err(FSL_JSON_E_RESOURCE_NOT_FOUND,NULL,0);
1627 }else
1628 #endif
1629
+117
--- src/setup.c
+++ src/setup.c
@@ -96,10 +96,12 @@
9696
" on the same server");
9797
setup_menu_entry("Tickets", "tktsetup",
9898
"Configure the trouble-ticketing system for this repository");
9999
setup_menu_entry("Search","srchsetup",
100100
"Configure the built-in search engine");
101
+ setup_menu_entry("URL Aliases", "waliassetup",
102
+ "Configure URL aliases");
101103
setup_menu_entry("Transfers", "xfersetup",
102104
"Configure the transfer system for this repository");
103105
setup_menu_entry("Skins", "setup_skin",
104106
"Select and/or modify the web interface \"skins\"");
105107
setup_menu_entry("Moderation", "setup_modreq",
@@ -2307,5 +2309,120 @@
23072309
@ <p><input type="submit" name="fts1" value="Create A Full-Text Index">
23082310
}
23092311
@ </div></form>
23102312
style_footer();
23112313
}
2314
+
2315
+/*
2316
+** A URL Alias originally called zOldName is now zNewName/zValue.
2317
+** Write SQL to make this change into pSql.
2318
+**
2319
+** If zNewName or zValue is an empty string, then delete the entry.
2320
+**
2321
+** If zOldName is an empty string, create a new entry.
2322
+*/
2323
+static void setup_update_url_alias(
2324
+ Blob *pSql,
2325
+ const char *zOldName,
2326
+ const char *zNewName,
2327
+ const char *zValue
2328
+){
2329
+ if( zNewName[0]==0 || zValue[0]==0 ){
2330
+ if( zOldName[0] ){
2331
+ blob_append_sql(pSql,
2332
+ "DELETE FROM config WHERE name='walias:%q';\n",
2333
+ zOldName);
2334
+ }
2335
+ return;
2336
+ }
2337
+ if( zOldName[0]==0 ){
2338
+ blob_append_sql(pSql,
2339
+ "INSERT INTO config(name,value,mtime) VALUES('walias:%q',%Q,now());\n",
2340
+ zNewName, zValue);
2341
+ return;
2342
+ }
2343
+ if( strcmp(zOldName, zNewName)!=0 ){
2344
+ blob_append_sql(pSql,
2345
+ "UPDATE config SET name='walias:%q', value=%Q, mtime=now()"
2346
+ " WHERE name='walias:%q';\n",
2347
+ zNewName, zValue, zOldName);
2348
+ }else{
2349
+ blob_append_sql(pSql,
2350
+ "UPDATE config SET value=%Q, mtime=now()"
2351
+ " WHERE name='walias:%q' AND value<>%Q;\n",
2352
+ zValue, zOldName, zValue);
2353
+ }
2354
+}
2355
+
2356
+/*
2357
+** WEBPAGE: waliassetup
2358
+**
2359
+** Configure the URL aliases
2360
+*/
2361
+void page_waliassetup(){
2362
+ Stmt q;
2363
+ int cnt = 0;
2364
+ Blob namelist;
2365
+ login_check_credentials();
2366
+ if( !g.perm.Setup && !g.perm.Admin ){
2367
+ login_needed(0);
2368
+ return;
2369
+ }
2370
+ style_header("URL ALias Configuration");
2371
+ if( P("submit")!=0 ){
2372
+ Blob token;
2373
+ Blob sql;
2374
+ const char *zNewName;
2375
+ const char *zValue;
2376
+ char zCnt[10];
2377
+ login_verify_csrf_secret();
2378
+ blob_init(&namelist, PD("namelist",""), -1);
2379
+ blob_init(&sql, 0, 0);
2380
+ while( blob_token(&namelist, &token) ){
2381
+ const char *zOldName = blob_str(&token);
2382
+ sqlite3_snprintf(sizeof(zCnt), zCnt, "n%d", cnt);
2383
+ zNewName = PD(zCnt, "");
2384
+ sqlite3_snprintf(sizeof(zCnt), zCnt, "v%d", cnt);
2385
+ zValue = PD(zCnt, "");
2386
+ setup_update_url_alias(&sql, zOldName, zNewName, zValue);
2387
+ cnt++;
2388
+ blob_reset(&token);
2389
+ }
2390
+ sqlite3_snprintf(sizeof(zCnt), zCnt, "n%d", cnt);
2391
+ zNewName = PD(zCnt,"");
2392
+ sqlite3_snprintf(sizeof(zCnt), zCnt, "v%d", cnt);
2393
+ zValue = PD(zCnt,"");
2394
+ setup_update_url_alias(&sql, "", zNewName, zValue);
2395
+ db_multi_exec("%s", blob_sql_text(&sql));
2396
+ blob_reset(&sql);
2397
+ blob_reset(&namelist);
2398
+ cnt = 0;
2399
+ }
2400
+ db_prepare(&q,
2401
+ "SELECT substr(name,8), value FROM config WHERE name GLOB 'walias:/*'"
2402
+ " UNION ALL SELECT '', ''"
2403
+ );
2404
+ @ <form action="%s(g.zTop)/waliassetup" method="post"><div>
2405
+ login_insert_csrf_secret();
2406
+ @ <table border=0 cellpadding=5>
2407
+ @ <tr><th>Alias<th>URI That The Alias Maps Into
2408
+ blob_init(&namelist, 0, 0);
2409
+ while( db_step(&q)==SQLITE_ROW ){
2410
+ const char *zName = db_column_text(&q, 0);
2411
+ const char *zValue = db_column_text(&q, 1);
2412
+ @ <tr><td>
2413
+ @ <input type='text' size='20' value='%h(zName)' name='n%d(cnt)'>
2414
+ @ </td><td>
2415
+ @ <input type='text' size='80' value='%h(zValue)' name='v%d(cnt)'>
2416
+ @ </td></tr>
2417
+ cnt++;
2418
+ if( blob_size(&namelist)>0 ) blob_append(&namelist, " ", 1);
2419
+ blob_append(&namelist, zName, -1);
2420
+ }
2421
+ db_finalize(&q);
2422
+ @ <tr><td>
2423
+ @ <input type='hidden' name='namelist' value='%h(blob_str(&namelist))'>
2424
+ @ <input type='submit' name='submit' value="Apply Changes">
2425
+ @ </td><td></td></tr>
2426
+ @ </table></form>
2427
+ style_footer();
2428
+}
23122429
--- src/setup.c
+++ src/setup.c
@@ -96,10 +96,12 @@
96 " on the same server");
97 setup_menu_entry("Tickets", "tktsetup",
98 "Configure the trouble-ticketing system for this repository");
99 setup_menu_entry("Search","srchsetup",
100 "Configure the built-in search engine");
 
 
101 setup_menu_entry("Transfers", "xfersetup",
102 "Configure the transfer system for this repository");
103 setup_menu_entry("Skins", "setup_skin",
104 "Select and/or modify the web interface \"skins\"");
105 setup_menu_entry("Moderation", "setup_modreq",
@@ -2307,5 +2309,120 @@
2307 @ <p><input type="submit" name="fts1" value="Create A Full-Text Index">
2308 }
2309 @ </div></form>
2310 style_footer();
2311 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2312
--- src/setup.c
+++ src/setup.c
@@ -96,10 +96,12 @@
96 " on the same server");
97 setup_menu_entry("Tickets", "tktsetup",
98 "Configure the trouble-ticketing system for this repository");
99 setup_menu_entry("Search","srchsetup",
100 "Configure the built-in search engine");
101 setup_menu_entry("URL Aliases", "waliassetup",
102 "Configure URL aliases");
103 setup_menu_entry("Transfers", "xfersetup",
104 "Configure the transfer system for this repository");
105 setup_menu_entry("Skins", "setup_skin",
106 "Select and/or modify the web interface \"skins\"");
107 setup_menu_entry("Moderation", "setup_modreq",
@@ -2307,5 +2309,120 @@
2309 @ <p><input type="submit" name="fts1" value="Create A Full-Text Index">
2310 }
2311 @ </div></form>
2312 style_footer();
2313 }
2314
2315 /*
2316 ** A URL Alias originally called zOldName is now zNewName/zValue.
2317 ** Write SQL to make this change into pSql.
2318 **
2319 ** If zNewName or zValue is an empty string, then delete the entry.
2320 **
2321 ** If zOldName is an empty string, create a new entry.
2322 */
2323 static void setup_update_url_alias(
2324 Blob *pSql,
2325 const char *zOldName,
2326 const char *zNewName,
2327 const char *zValue
2328 ){
2329 if( zNewName[0]==0 || zValue[0]==0 ){
2330 if( zOldName[0] ){
2331 blob_append_sql(pSql,
2332 "DELETE FROM config WHERE name='walias:%q';\n",
2333 zOldName);
2334 }
2335 return;
2336 }
2337 if( zOldName[0]==0 ){
2338 blob_append_sql(pSql,
2339 "INSERT INTO config(name,value,mtime) VALUES('walias:%q',%Q,now());\n",
2340 zNewName, zValue);
2341 return;
2342 }
2343 if( strcmp(zOldName, zNewName)!=0 ){
2344 blob_append_sql(pSql,
2345 "UPDATE config SET name='walias:%q', value=%Q, mtime=now()"
2346 " WHERE name='walias:%q';\n",
2347 zNewName, zValue, zOldName);
2348 }else{
2349 blob_append_sql(pSql,
2350 "UPDATE config SET value=%Q, mtime=now()"
2351 " WHERE name='walias:%q' AND value<>%Q;\n",
2352 zValue, zOldName, zValue);
2353 }
2354 }
2355
2356 /*
2357 ** WEBPAGE: waliassetup
2358 **
2359 ** Configure the URL aliases
2360 */
2361 void page_waliassetup(){
2362 Stmt q;
2363 int cnt = 0;
2364 Blob namelist;
2365 login_check_credentials();
2366 if( !g.perm.Setup && !g.perm.Admin ){
2367 login_needed(0);
2368 return;
2369 }
2370 style_header("URL ALias Configuration");
2371 if( P("submit")!=0 ){
2372 Blob token;
2373 Blob sql;
2374 const char *zNewName;
2375 const char *zValue;
2376 char zCnt[10];
2377 login_verify_csrf_secret();
2378 blob_init(&namelist, PD("namelist",""), -1);
2379 blob_init(&sql, 0, 0);
2380 while( blob_token(&namelist, &token) ){
2381 const char *zOldName = blob_str(&token);
2382 sqlite3_snprintf(sizeof(zCnt), zCnt, "n%d", cnt);
2383 zNewName = PD(zCnt, "");
2384 sqlite3_snprintf(sizeof(zCnt), zCnt, "v%d", cnt);
2385 zValue = PD(zCnt, "");
2386 setup_update_url_alias(&sql, zOldName, zNewName, zValue);
2387 cnt++;
2388 blob_reset(&token);
2389 }
2390 sqlite3_snprintf(sizeof(zCnt), zCnt, "n%d", cnt);
2391 zNewName = PD(zCnt,"");
2392 sqlite3_snprintf(sizeof(zCnt), zCnt, "v%d", cnt);
2393 zValue = PD(zCnt,"");
2394 setup_update_url_alias(&sql, "", zNewName, zValue);
2395 db_multi_exec("%s", blob_sql_text(&sql));
2396 blob_reset(&sql);
2397 blob_reset(&namelist);
2398 cnt = 0;
2399 }
2400 db_prepare(&q,
2401 "SELECT substr(name,8), value FROM config WHERE name GLOB 'walias:/*'"
2402 " UNION ALL SELECT '', ''"
2403 );
2404 @ <form action="%s(g.zTop)/waliassetup" method="post"><div>
2405 login_insert_csrf_secret();
2406 @ <table border=0 cellpadding=5>
2407 @ <tr><th>Alias<th>URI That The Alias Maps Into
2408 blob_init(&namelist, 0, 0);
2409 while( db_step(&q)==SQLITE_ROW ){
2410 const char *zName = db_column_text(&q, 0);
2411 const char *zValue = db_column_text(&q, 1);
2412 @ <tr><td>
2413 @ <input type='text' size='20' value='%h(zName)' name='n%d(cnt)'>
2414 @ </td><td>
2415 @ <input type='text' size='80' value='%h(zValue)' name='v%d(cnt)'>
2416 @ </td></tr>
2417 cnt++;
2418 if( blob_size(&namelist)>0 ) blob_append(&namelist, " ", 1);
2419 blob_append(&namelist, zName, -1);
2420 }
2421 db_finalize(&q);
2422 @ <tr><td>
2423 @ <input type='hidden' name='namelist' value='%h(blob_str(&namelist))'>
2424 @ <input type='submit' name='submit' value="Apply Changes">
2425 @ </td><td></td></tr>
2426 @ </table></form>
2427 style_footer();
2428 }
2429

Keyboard Shortcuts

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