Fossil SCM
Add the subpath field to the UrlData object. If that field is non-NULL, then the http_exchange() routine will build the request header using subpath rather than path. This allows the path for ssh: and file: to be distinct from the HTTP request path. Enhance the test-httpmsg command to work with file: and ssh: URLs as long as the new --subpath option is provided.
Commit
9abda297348385e9f6f7e389e4a418e16bb63db2f4e0147b880a0f26e362e16e
Parent
3c639f742096eea…
2 files changed
+19
-4
+3
+19
-4
| --- src/http.c | ||
| +++ src/http.c | ||
| @@ -141,15 +141,22 @@ | ||
| 141 | 141 | Blob *pHdr, /* construct the header here */ |
| 142 | 142 | Blob *pLogin, /* Login card header value or NULL */ |
| 143 | 143 | const char *zAltMimetype /* Alternative mimetype */ |
| 144 | 144 | ){ |
| 145 | 145 | int nPayload = pPayload ? blob_size(pPayload) : 0; |
| 146 | + const char *zPath; | |
| 146 | 147 | |
| 147 | 148 | blob_zero(pHdr); |
| 149 | + if( g.url.subpath ){ | |
| 150 | + zPath = g.url.subpath; | |
| 151 | + }else if( g.url.path==0 || g.url.path[0]==0 ){ | |
| 152 | + zPath = "/"; | |
| 153 | + }else{ | |
| 154 | + zPath = g.url.path; | |
| 155 | + } | |
| 148 | 156 | blob_appendf(pHdr, "%s %s HTTP/1.0\r\n", |
| 149 | - nPayload>0 ? "POST" : "GET", | |
| 150 | - (g.url.path && g.url.path[0]) ? g.url.path : "/"); | |
| 157 | + nPayload>0 ? "POST" : "GET", zPath); | |
| 151 | 158 | if( g.url.proxyAuth ){ |
| 152 | 159 | blob_appendf(pHdr, "Proxy-Authorization: %s\r\n", g.url.proxyAuth); |
| 153 | 160 | } |
| 154 | 161 | if( g.zHttpAuth && g.zHttpAuth[0] ){ |
| 155 | 162 | const char *zCredentials = g.zHttpAuth; |
| @@ -459,10 +466,11 @@ | ||
| 459 | 466 | /* Activate the PATH= auxiliary argument to the ssh command if that |
| 460 | 467 | ** is called for. |
| 461 | 468 | */ |
| 462 | 469 | if( g.url.isSsh |
| 463 | 470 | && (g.url.flags & URL_SSH_RETRY)==0 |
| 471 | + && g.db!=0 | |
| 464 | 472 | && ssh_needs_path_argument(g.url.hostname, -1) |
| 465 | 473 | ){ |
| 466 | 474 | g.url.flags |= URL_SSH_PATH; |
| 467 | 475 | } |
| 468 | 476 | |
| @@ -686,11 +694,11 @@ | ||
| 686 | 694 | g.url.hostname, |
| 687 | 695 | (g.url.flags & URL_SSH_PATH)!=0 ? "without" : "with" |
| 688 | 696 | ); |
| 689 | 697 | g.url.flags ^= URL_SSH_PATH|URL_SSH_RETRY; |
| 690 | 698 | rc = http_exchange(pSend,pReply,mHttpFlags,0,zAltMimetype); |
| 691 | - if( rc==0 ){ | |
| 699 | + if( rc==0 && g.db!=0 ){ | |
| 692 | 700 | (void)ssh_needs_path_argument(g.url.hostname, |
| 693 | 701 | (g.url.flags & URL_SSH_PATH)!=0); |
| 694 | 702 | } |
| 695 | 703 | return rc; |
| 696 | 704 | }else{ |
| @@ -808,17 +816,19 @@ | ||
| 808 | 816 | ** Options: |
| 809 | 817 | ** --compress Use ZLIB compression on the payload |
| 810 | 818 | ** --mimetype TYPE Mimetype of the payload |
| 811 | 819 | ** --no-cert-verify Disable TLS cert verification |
| 812 | 820 | ** --out FILE Store the reply in FILE |
| 821 | +** --subpath PATH HTTP request path for ssh: and file: URLs | |
| 813 | 822 | ** -v Verbose output |
| 814 | 823 | ** --xfer PAYLOAD in a Fossil xfer protocol message |
| 815 | 824 | */ |
| 816 | 825 | void test_httpmsg_command(void){ |
| 817 | 826 | const char *zMimetype; |
| 818 | 827 | const char *zInFile; |
| 819 | 828 | const char *zOutFile; |
| 829 | + const char *zSubpath; | |
| 820 | 830 | Blob in, out; |
| 821 | 831 | unsigned int mHttpFlags = HTTP_GENERIC|HTTP_NOCOMPRESS; |
| 822 | 832 | |
| 823 | 833 | zMimetype = find_option("mimetype",0,1); |
| 824 | 834 | zOutFile = find_option("out","o",1); |
| @@ -832,10 +842,11 @@ | ||
| 832 | 842 | if( find_option("xfer",0,0)!=0 ){ |
| 833 | 843 | mHttpFlags |= HTTP_USE_LOGIN; |
| 834 | 844 | mHttpFlags &= ~HTTP_GENERIC; |
| 835 | 845 | } |
| 836 | 846 | if( find_option("ipv4",0,0) ) g.fIPv4 = 1; |
| 847 | + zSubpath = find_option("subpath",0,1); | |
| 837 | 848 | verify_all_options(); |
| 838 | 849 | if( g.argc<3 || g.argc>5 ){ |
| 839 | 850 | usage("URL ?PAYLOAD? ?OUTPUT?"); |
| 840 | 851 | } |
| 841 | 852 | zInFile = g.argc>=4 ? g.argv[3] : 0; |
| @@ -846,11 +857,15 @@ | ||
| 846 | 857 | } |
| 847 | 858 | zOutFile = g.argv[4]; |
| 848 | 859 | } |
| 849 | 860 | url_parse(g.argv[2], 0); |
| 850 | 861 | if( g.url.protocol[0]!='h' ){ |
| 851 | - fossil_fatal("the %s command supports only http: and https:", g.argv[1]); | |
| 862 | + if( zSubpath==0 ){ | |
| 863 | + fossil_fatal("the --subpath option is required for %s://",g.url.protocol); | |
| 864 | + }else{ | |
| 865 | + g.url.subpath = fossil_strdup(zSubpath); | |
| 866 | + } | |
| 852 | 867 | } |
| 853 | 868 | if( zInFile ){ |
| 854 | 869 | blob_read_from_file(&in, zInFile, ExtFILE); |
| 855 | 870 | if( zMimetype==0 && (mHttpFlags & HTTP_GENERIC)!=0 ){ |
| 856 | 871 | if( fossil_strcmp(zInFile,"-")==0 ){ |
| 857 | 872 |
| --- src/http.c | |
| +++ src/http.c | |
| @@ -141,15 +141,22 @@ | |
| 141 | Blob *pHdr, /* construct the header here */ |
| 142 | Blob *pLogin, /* Login card header value or NULL */ |
| 143 | const char *zAltMimetype /* Alternative mimetype */ |
| 144 | ){ |
| 145 | int nPayload = pPayload ? blob_size(pPayload) : 0; |
| 146 | |
| 147 | blob_zero(pHdr); |
| 148 | blob_appendf(pHdr, "%s %s HTTP/1.0\r\n", |
| 149 | nPayload>0 ? "POST" : "GET", |
| 150 | (g.url.path && g.url.path[0]) ? g.url.path : "/"); |
| 151 | if( g.url.proxyAuth ){ |
| 152 | blob_appendf(pHdr, "Proxy-Authorization: %s\r\n", g.url.proxyAuth); |
| 153 | } |
| 154 | if( g.zHttpAuth && g.zHttpAuth[0] ){ |
| 155 | const char *zCredentials = g.zHttpAuth; |
| @@ -459,10 +466,11 @@ | |
| 459 | /* Activate the PATH= auxiliary argument to the ssh command if that |
| 460 | ** is called for. |
| 461 | */ |
| 462 | if( g.url.isSsh |
| 463 | && (g.url.flags & URL_SSH_RETRY)==0 |
| 464 | && ssh_needs_path_argument(g.url.hostname, -1) |
| 465 | ){ |
| 466 | g.url.flags |= URL_SSH_PATH; |
| 467 | } |
| 468 | |
| @@ -686,11 +694,11 @@ | |
| 686 | g.url.hostname, |
| 687 | (g.url.flags & URL_SSH_PATH)!=0 ? "without" : "with" |
| 688 | ); |
| 689 | g.url.flags ^= URL_SSH_PATH|URL_SSH_RETRY; |
| 690 | rc = http_exchange(pSend,pReply,mHttpFlags,0,zAltMimetype); |
| 691 | if( rc==0 ){ |
| 692 | (void)ssh_needs_path_argument(g.url.hostname, |
| 693 | (g.url.flags & URL_SSH_PATH)!=0); |
| 694 | } |
| 695 | return rc; |
| 696 | }else{ |
| @@ -808,17 +816,19 @@ | |
| 808 | ** Options: |
| 809 | ** --compress Use ZLIB compression on the payload |
| 810 | ** --mimetype TYPE Mimetype of the payload |
| 811 | ** --no-cert-verify Disable TLS cert verification |
| 812 | ** --out FILE Store the reply in FILE |
| 813 | ** -v Verbose output |
| 814 | ** --xfer PAYLOAD in a Fossil xfer protocol message |
| 815 | */ |
| 816 | void test_httpmsg_command(void){ |
| 817 | const char *zMimetype; |
| 818 | const char *zInFile; |
| 819 | const char *zOutFile; |
| 820 | Blob in, out; |
| 821 | unsigned int mHttpFlags = HTTP_GENERIC|HTTP_NOCOMPRESS; |
| 822 | |
| 823 | zMimetype = find_option("mimetype",0,1); |
| 824 | zOutFile = find_option("out","o",1); |
| @@ -832,10 +842,11 @@ | |
| 832 | if( find_option("xfer",0,0)!=0 ){ |
| 833 | mHttpFlags |= HTTP_USE_LOGIN; |
| 834 | mHttpFlags &= ~HTTP_GENERIC; |
| 835 | } |
| 836 | if( find_option("ipv4",0,0) ) g.fIPv4 = 1; |
| 837 | verify_all_options(); |
| 838 | if( g.argc<3 || g.argc>5 ){ |
| 839 | usage("URL ?PAYLOAD? ?OUTPUT?"); |
| 840 | } |
| 841 | zInFile = g.argc>=4 ? g.argv[3] : 0; |
| @@ -846,11 +857,15 @@ | |
| 846 | } |
| 847 | zOutFile = g.argv[4]; |
| 848 | } |
| 849 | url_parse(g.argv[2], 0); |
| 850 | if( g.url.protocol[0]!='h' ){ |
| 851 | fossil_fatal("the %s command supports only http: and https:", g.argv[1]); |
| 852 | } |
| 853 | if( zInFile ){ |
| 854 | blob_read_from_file(&in, zInFile, ExtFILE); |
| 855 | if( zMimetype==0 && (mHttpFlags & HTTP_GENERIC)!=0 ){ |
| 856 | if( fossil_strcmp(zInFile,"-")==0 ){ |
| 857 |
| --- src/http.c | |
| +++ src/http.c | |
| @@ -141,15 +141,22 @@ | |
| 141 | Blob *pHdr, /* construct the header here */ |
| 142 | Blob *pLogin, /* Login card header value or NULL */ |
| 143 | const char *zAltMimetype /* Alternative mimetype */ |
| 144 | ){ |
| 145 | int nPayload = pPayload ? blob_size(pPayload) : 0; |
| 146 | const char *zPath; |
| 147 | |
| 148 | blob_zero(pHdr); |
| 149 | if( g.url.subpath ){ |
| 150 | zPath = g.url.subpath; |
| 151 | }else if( g.url.path==0 || g.url.path[0]==0 ){ |
| 152 | zPath = "/"; |
| 153 | }else{ |
| 154 | zPath = g.url.path; |
| 155 | } |
| 156 | blob_appendf(pHdr, "%s %s HTTP/1.0\r\n", |
| 157 | nPayload>0 ? "POST" : "GET", zPath); |
| 158 | if( g.url.proxyAuth ){ |
| 159 | blob_appendf(pHdr, "Proxy-Authorization: %s\r\n", g.url.proxyAuth); |
| 160 | } |
| 161 | if( g.zHttpAuth && g.zHttpAuth[0] ){ |
| 162 | const char *zCredentials = g.zHttpAuth; |
| @@ -459,10 +466,11 @@ | |
| 466 | /* Activate the PATH= auxiliary argument to the ssh command if that |
| 467 | ** is called for. |
| 468 | */ |
| 469 | if( g.url.isSsh |
| 470 | && (g.url.flags & URL_SSH_RETRY)==0 |
| 471 | && g.db!=0 |
| 472 | && ssh_needs_path_argument(g.url.hostname, -1) |
| 473 | ){ |
| 474 | g.url.flags |= URL_SSH_PATH; |
| 475 | } |
| 476 | |
| @@ -686,11 +694,11 @@ | |
| 694 | g.url.hostname, |
| 695 | (g.url.flags & URL_SSH_PATH)!=0 ? "without" : "with" |
| 696 | ); |
| 697 | g.url.flags ^= URL_SSH_PATH|URL_SSH_RETRY; |
| 698 | rc = http_exchange(pSend,pReply,mHttpFlags,0,zAltMimetype); |
| 699 | if( rc==0 && g.db!=0 ){ |
| 700 | (void)ssh_needs_path_argument(g.url.hostname, |
| 701 | (g.url.flags & URL_SSH_PATH)!=0); |
| 702 | } |
| 703 | return rc; |
| 704 | }else{ |
| @@ -808,17 +816,19 @@ | |
| 816 | ** Options: |
| 817 | ** --compress Use ZLIB compression on the payload |
| 818 | ** --mimetype TYPE Mimetype of the payload |
| 819 | ** --no-cert-verify Disable TLS cert verification |
| 820 | ** --out FILE Store the reply in FILE |
| 821 | ** --subpath PATH HTTP request path for ssh: and file: URLs |
| 822 | ** -v Verbose output |
| 823 | ** --xfer PAYLOAD in a Fossil xfer protocol message |
| 824 | */ |
| 825 | void test_httpmsg_command(void){ |
| 826 | const char *zMimetype; |
| 827 | const char *zInFile; |
| 828 | const char *zOutFile; |
| 829 | const char *zSubpath; |
| 830 | Blob in, out; |
| 831 | unsigned int mHttpFlags = HTTP_GENERIC|HTTP_NOCOMPRESS; |
| 832 | |
| 833 | zMimetype = find_option("mimetype",0,1); |
| 834 | zOutFile = find_option("out","o",1); |
| @@ -832,10 +842,11 @@ | |
| 842 | if( find_option("xfer",0,0)!=0 ){ |
| 843 | mHttpFlags |= HTTP_USE_LOGIN; |
| 844 | mHttpFlags &= ~HTTP_GENERIC; |
| 845 | } |
| 846 | if( find_option("ipv4",0,0) ) g.fIPv4 = 1; |
| 847 | zSubpath = find_option("subpath",0,1); |
| 848 | verify_all_options(); |
| 849 | if( g.argc<3 || g.argc>5 ){ |
| 850 | usage("URL ?PAYLOAD? ?OUTPUT?"); |
| 851 | } |
| 852 | zInFile = g.argc>=4 ? g.argv[3] : 0; |
| @@ -846,11 +857,15 @@ | |
| 857 | } |
| 858 | zOutFile = g.argv[4]; |
| 859 | } |
| 860 | url_parse(g.argv[2], 0); |
| 861 | if( g.url.protocol[0]!='h' ){ |
| 862 | if( zSubpath==0 ){ |
| 863 | fossil_fatal("the --subpath option is required for %s://",g.url.protocol); |
| 864 | }else{ |
| 865 | g.url.subpath = fossil_strdup(zSubpath); |
| 866 | } |
| 867 | } |
| 868 | if( zInFile ){ |
| 869 | blob_read_from_file(&in, zInFile, ExtFILE); |
| 870 | if( zMimetype==0 && (mHttpFlags & HTTP_GENERIC)!=0 ){ |
| 871 | if( fossil_strcmp(zInFile,"-")==0 ){ |
| 872 |
+3
| --- src/url.c | ||
| +++ src/url.c | ||
| @@ -58,10 +58,11 @@ | ||
| 58 | 58 | char *user; /* User id for http: */ |
| 59 | 59 | char *passwd; /* Password for http: */ |
| 60 | 60 | char *canonical; /* Canonical representation of the URL */ |
| 61 | 61 | char *proxyAuth; /* Proxy-Authorizer: string */ |
| 62 | 62 | char *fossil; /* The fossil query parameter on ssh: */ |
| 63 | + char *subpath; /* Secondary HTTP request path for ssh: and file: */ | |
| 63 | 64 | char *pwConfig; /* CONFIG table entry that gave us the password */ |
| 64 | 65 | unsigned flags; /* Boolean flags controlling URL processing */ |
| 65 | 66 | int useProxy; /* Used to remember that a proxy is in use */ |
| 66 | 67 | int proxyOrigPort; /* Tunneled port number for https through proxy */ |
| 67 | 68 | char *proxyUrlPath; /* Remember path when proxy is use */ |
| @@ -406,10 +407,11 @@ | ||
| 406 | 407 | fossil_free(p->name); |
| 407 | 408 | fossil_free(p->path); |
| 408 | 409 | fossil_free(p->user); |
| 409 | 410 | fossil_free(p->passwd); |
| 410 | 411 | fossil_free(p->fossil); |
| 412 | + fossil_free(p->subpath); | |
| 411 | 413 | fossil_free(p->pwConfig); |
| 412 | 414 | memset(p, 0, sizeof(*p)); |
| 413 | 415 | } |
| 414 | 416 | |
| 415 | 417 | /* |
| @@ -483,10 +485,11 @@ | ||
| 483 | 485 | fossil_print("g.url.passwd = ************\n"); |
| 484 | 486 | } |
| 485 | 487 | fossil_print("g.url.pwConfig = %s\n", g.url.pwConfig); |
| 486 | 488 | fossil_print("g.url.canonical = %s\n", g.url.canonical); |
| 487 | 489 | fossil_print("g.url.fossil = %s\n", g.url.fossil); |
| 490 | + fossil_print("g.url.subpath = %s\n", g.url.subpath); | |
| 488 | 491 | fossil_print("g.url.flags = 0x%04x\n", g.url.flags); |
| 489 | 492 | fossil_print("url_full(g.url) = %z\n", url_full(&g.url)); |
| 490 | 493 | } |
| 491 | 494 | |
| 492 | 495 | /* |
| 493 | 496 |
| --- src/url.c | |
| +++ src/url.c | |
| @@ -58,10 +58,11 @@ | |
| 58 | char *user; /* User id for http: */ |
| 59 | char *passwd; /* Password for http: */ |
| 60 | char *canonical; /* Canonical representation of the URL */ |
| 61 | char *proxyAuth; /* Proxy-Authorizer: string */ |
| 62 | char *fossil; /* The fossil query parameter on ssh: */ |
| 63 | char *pwConfig; /* CONFIG table entry that gave us the password */ |
| 64 | unsigned flags; /* Boolean flags controlling URL processing */ |
| 65 | int useProxy; /* Used to remember that a proxy is in use */ |
| 66 | int proxyOrigPort; /* Tunneled port number for https through proxy */ |
| 67 | char *proxyUrlPath; /* Remember path when proxy is use */ |
| @@ -406,10 +407,11 @@ | |
| 406 | fossil_free(p->name); |
| 407 | fossil_free(p->path); |
| 408 | fossil_free(p->user); |
| 409 | fossil_free(p->passwd); |
| 410 | fossil_free(p->fossil); |
| 411 | fossil_free(p->pwConfig); |
| 412 | memset(p, 0, sizeof(*p)); |
| 413 | } |
| 414 | |
| 415 | /* |
| @@ -483,10 +485,11 @@ | |
| 483 | fossil_print("g.url.passwd = ************\n"); |
| 484 | } |
| 485 | fossil_print("g.url.pwConfig = %s\n", g.url.pwConfig); |
| 486 | fossil_print("g.url.canonical = %s\n", g.url.canonical); |
| 487 | fossil_print("g.url.fossil = %s\n", g.url.fossil); |
| 488 | fossil_print("g.url.flags = 0x%04x\n", g.url.flags); |
| 489 | fossil_print("url_full(g.url) = %z\n", url_full(&g.url)); |
| 490 | } |
| 491 | |
| 492 | /* |
| 493 |
| --- src/url.c | |
| +++ src/url.c | |
| @@ -58,10 +58,11 @@ | |
| 58 | char *user; /* User id for http: */ |
| 59 | char *passwd; /* Password for http: */ |
| 60 | char *canonical; /* Canonical representation of the URL */ |
| 61 | char *proxyAuth; /* Proxy-Authorizer: string */ |
| 62 | char *fossil; /* The fossil query parameter on ssh: */ |
| 63 | char *subpath; /* Secondary HTTP request path for ssh: and file: */ |
| 64 | char *pwConfig; /* CONFIG table entry that gave us the password */ |
| 65 | unsigned flags; /* Boolean flags controlling URL processing */ |
| 66 | int useProxy; /* Used to remember that a proxy is in use */ |
| 67 | int proxyOrigPort; /* Tunneled port number for https through proxy */ |
| 68 | char *proxyUrlPath; /* Remember path when proxy is use */ |
| @@ -406,10 +407,11 @@ | |
| 407 | fossil_free(p->name); |
| 408 | fossil_free(p->path); |
| 409 | fossil_free(p->user); |
| 410 | fossil_free(p->passwd); |
| 411 | fossil_free(p->fossil); |
| 412 | fossil_free(p->subpath); |
| 413 | fossil_free(p->pwConfig); |
| 414 | memset(p, 0, sizeof(*p)); |
| 415 | } |
| 416 | |
| 417 | /* |
| @@ -483,10 +485,11 @@ | |
| 485 | fossil_print("g.url.passwd = ************\n"); |
| 486 | } |
| 487 | fossil_print("g.url.pwConfig = %s\n", g.url.pwConfig); |
| 488 | fossil_print("g.url.canonical = %s\n", g.url.canonical); |
| 489 | fossil_print("g.url.fossil = %s\n", g.url.fossil); |
| 490 | fossil_print("g.url.subpath = %s\n", g.url.subpath); |
| 491 | fossil_print("g.url.flags = 0x%04x\n", g.url.flags); |
| 492 | fossil_print("url_full(g.url) = %z\n", url_full(&g.url)); |
| 493 | } |
| 494 | |
| 495 | /* |
| 496 |