Fossil SCM
Fix blob leaks in the http TH1 command. Also, reorganize it to prepare for future enhancements.
Commit
0db184fc8e750cde398862632628fd1ba1dfdd77
Parent
20306eef8c6632f…
1 file changed
+70
-52
+70
-52
| --- src/th_main.c | ||
| +++ src/th_main.c | ||
| @@ -830,47 +830,46 @@ | ||
| 830 | 830 | re_free(pRe); |
| 831 | 831 | return rc; |
| 832 | 832 | } |
| 833 | 833 | |
| 834 | 834 | /* |
| 835 | -** TH command: http -asynchronous url ?payload? | |
| 835 | +** TH command: http ?-asynchronous? ?--? url ?payload? | |
| 836 | 836 | ** |
| 837 | 837 | ** Perform an HTTP or HTTPS request for the specified URL. If a |
| 838 | 838 | ** payload is present, it will be interpreted as text/plain and |
| 839 | 839 | ** the POST method will be used; otherwise, the GET method will |
| 840 | -** be used. Currently, all requests must be asynchronous. | |
| 840 | +** be used. Upon success, if the -asynchronous option is used, an | |
| 841 | +** empty string is returned as the result; otherwise, the response | |
| 842 | +** from the server is returned as the result. Synchronous requests | |
| 843 | +** are not currently implemented. | |
| 841 | 844 | */ |
| 845 | +#define HTTP_WRONGNUMARGS "http ?-asynchronous? ?--? url ?payload?" | |
| 842 | 846 | static int httpCmd( |
| 843 | 847 | Th_Interp *interp, |
| 844 | 848 | void *p, |
| 845 | 849 | int argc, |
| 846 | 850 | const char **argv, |
| 847 | 851 | int *argl |
| 848 | 852 | ){ |
| 849 | - const char *zSep, *zType, *zRegexp, *zParams; | |
| 850 | - Blob hdr, payload; | |
| 853 | + int nArg = 1; | |
| 854 | + int fAsynchronous = 0; | |
| 855 | + const char *zType, *zRegexp; | |
| 856 | + Blob payload; | |
| 851 | 857 | ReCompiled *pRe = 0; |
| 852 | 858 | UrlData urlData; |
| 853 | 859 | |
| 854 | - if( argc<2 || fossil_strnicmp(argv[1], "-asynchronous", argl[1]) ){ | |
| 855 | - Th_ErrorMessage(interp, | |
| 856 | - "synchronous http requests not yet implemented", 0, 0); | |
| 857 | - return TH_ERROR; | |
| 858 | - } | |
| 859 | - --argc; ++argv; ++argl; /* advance to next argument */ | |
| 860 | - blob_zero(&payload); | |
| 861 | - if( argc!=2 ){ | |
| 862 | - if( argc != 3 ){ | |
| 863 | - return Th_WrongNumArgs(interp, "http -asynchronous url ?payload?"); | |
| 864 | - } | |
| 865 | - blob_append(&payload, argv[2], argl[2]); | |
| 866 | - zType = "POST"; | |
| 867 | - }else{ | |
| 868 | - zType = "GET"; | |
| 869 | - } | |
| 870 | - zParams = strrchr(argv[1], '?'); | |
| 871 | - url_parse_local(argv[1], 0, &urlData); | |
| 860 | + if( argc<2 || argc>5 ){ | |
| 861 | + return Th_WrongNumArgs(interp, HTTP_WRONGNUMARGS); | |
| 862 | + } | |
| 863 | + if( fossil_strnicmp(argv[nArg], "-asynchronous", argl[nArg])==0 ){ | |
| 864 | + fAsynchronous = 1; nArg++; | |
| 865 | + } | |
| 866 | + if( fossil_strcmp(argv[nArg], "--")==0 ) nArg++; | |
| 867 | + if( nArg+1!=argc && nArg+2!=argc ){ | |
| 868 | + return Th_WrongNumArgs(interp, REGEXP_WRONGNUMARGS); | |
| 869 | + } | |
| 870 | + url_parse_local(argv[nArg], 0, &urlData); | |
| 872 | 871 | if( urlData.isSsh || urlData.isFile ){ |
| 873 | 872 | Th_ErrorMessage(interp, "url must be http:// or https://", 0, 0); |
| 874 | 873 | return TH_ERROR; |
| 875 | 874 | } |
| 876 | 875 | zRegexp = db_get("th1-uri-regexp", 0); |
| @@ -885,42 +884,61 @@ | ||
| 885 | 884 | Th_SetResult(interp, "url not allowed", -1); |
| 886 | 885 | re_free(pRe); |
| 887 | 886 | return TH_ERROR; |
| 888 | 887 | } |
| 889 | 888 | re_free(pRe); |
| 890 | - if( transport_open(&urlData) ){ | |
| 891 | - Th_ErrorMessage(interp, transport_errmsg(&urlData), 0, 0); | |
| 889 | + blob_zero(&payload); | |
| 890 | + if( nArg+2==argc ){ | |
| 891 | + blob_append(&payload, argv[nArg+1], argl[nArg+1]); | |
| 892 | + zType = "POST"; | |
| 893 | + }else{ | |
| 894 | + zType = "GET"; | |
| 895 | + } | |
| 896 | + if( fAsynchronous ){ | |
| 897 | + const char *zSep, *zParams; | |
| 898 | + Blob hdr; | |
| 899 | + zParams = strrchr(argv[nArg], '?'); | |
| 900 | + if( strlen(urlData.path)>0 && zParams!=argv[nArg] ){ | |
| 901 | + zSep = ""; | |
| 902 | + }else{ | |
| 903 | + zSep = "/"; | |
| 904 | + } | |
| 905 | + blob_zero(&hdr); | |
| 906 | + blob_appendf(&hdr, "%s %s%s%s HTTP/1.0\r\n", | |
| 907 | + zType, zSep, urlData.path, zParams ? zParams : ""); | |
| 908 | + if( urlData.proxyAuth ){ | |
| 909 | + blob_appendf(&hdr, "Proxy-Authorization: %s\r\n", urlData.proxyAuth); | |
| 910 | + } | |
| 911 | + if( urlData.passwd && urlData.user && urlData.passwd[0]=='#' ){ | |
| 912 | + char *zCredentials = mprintf("%s:%s", urlData.user, &urlData.passwd[1]); | |
| 913 | + char *zEncoded = encode64(zCredentials, -1); | |
| 914 | + blob_appendf(&hdr, "Authorization: Basic %s\r\n", zEncoded); | |
| 915 | + fossil_free(zEncoded); | |
| 916 | + fossil_free(zCredentials); | |
| 917 | + } | |
| 918 | + blob_appendf(&hdr, "Host: %s\r\n", urlData.hostname); | |
| 919 | + blob_appendf(&hdr, "User-Agent: Fossil/" RELEASE_VERSION | |
| 920 | + " (" MANIFEST_DATE " " MANIFEST_VERSION ")\r\n"); | |
| 921 | + blob_appendf(&hdr, "Content-Type: text/plain\r\n"); | |
| 922 | + blob_appendf(&hdr, "Content-Length: %d\r\n\r\n", blob_size(&payload)); | |
| 923 | + if( transport_open(&urlData) ){ | |
| 924 | + Th_ErrorMessage(interp, transport_errmsg(&urlData), 0, 0); | |
| 925 | + return TH_ERROR; | |
| 926 | + } | |
| 927 | + transport_send(&urlData, &hdr); | |
| 928 | + transport_send(&urlData, &payload); | |
| 929 | + blob_reset(&hdr); | |
| 930 | + blob_reset(&payload); | |
| 931 | + transport_close(&urlData); | |
| 932 | + Th_SetResult(interp, 0, 0); /* NOTE: Asynchronous, no results. */ | |
| 933 | + return TH_OK; | |
| 934 | + }else{ | |
| 935 | + blob_reset(&payload); | |
| 936 | + Th_ErrorMessage(interp, | |
| 937 | + "synchronous requests are not yet implemented", 0, 0); | |
| 892 | 938 | return TH_ERROR; |
| 893 | 939 | } |
| 894 | - blob_zero(&hdr); | |
| 895 | - if( strlen(urlData.path)>0 && zParams!=argv[1] ){ | |
| 896 | - zSep = ""; | |
| 897 | - }else{ | |
| 898 | - zSep = "/"; | |
| 899 | - } | |
| 900 | - blob_appendf(&hdr, "%s %s%s%s HTTP/1.0\r\n", | |
| 901 | - zType, zSep, urlData.path, zParams ? zParams : ""); | |
| 902 | - if( urlData.proxyAuth ){ | |
| 903 | - blob_appendf(&hdr, "Proxy-Authorization: %s\r\n", urlData.proxyAuth); | |
| 904 | - } | |
| 905 | - if( urlData.passwd && urlData.user && urlData.passwd[0]=='#' ){ | |
| 906 | - char *zCredentials = mprintf("%s:%s", urlData.user, &urlData.passwd[1]); | |
| 907 | - char *zEncoded = encode64(zCredentials, -1); | |
| 908 | - blob_appendf(&hdr, "Authorization: Basic %s\r\n", zEncoded); | |
| 909 | - fossil_free(zEncoded); | |
| 910 | - fossil_free(zCredentials); | |
| 911 | - } | |
| 912 | - blob_appendf(&hdr, "Host: %s\r\n", urlData.hostname); | |
| 913 | - blob_appendf(&hdr, "User-Agent: Fossil/" RELEASE_VERSION | |
| 914 | - " (" MANIFEST_DATE " " MANIFEST_VERSION ")\r\n"); | |
| 915 | - blob_appendf(&hdr, "Content-Type: text/plain\r\n"); | |
| 916 | - blob_appendf(&hdr, "Content-Length: %d\r\n\r\n", blob_size(&payload)); | |
| 917 | - transport_send(&urlData, &hdr); | |
| 918 | - transport_send(&urlData, &payload); | |
| 919 | - transport_close(&urlData); | |
| 920 | - Th_SetResult(interp, 0, 0); /* NOTE: Asynchronous, no results yet. */ | |
| 921 | - return TH_OK; | |
| 922 | 940 | } |
| 923 | 941 | |
| 924 | 942 | /* |
| 925 | 943 | ** Make sure the interpreter has been initialized. Initialize it if |
| 926 | 944 | ** it has not been already. |
| 927 | 945 |
| --- src/th_main.c | |
| +++ src/th_main.c | |
| @@ -830,47 +830,46 @@ | |
| 830 | re_free(pRe); |
| 831 | return rc; |
| 832 | } |
| 833 | |
| 834 | /* |
| 835 | ** TH command: http -asynchronous url ?payload? |
| 836 | ** |
| 837 | ** Perform an HTTP or HTTPS request for the specified URL. If a |
| 838 | ** payload is present, it will be interpreted as text/plain and |
| 839 | ** the POST method will be used; otherwise, the GET method will |
| 840 | ** be used. Currently, all requests must be asynchronous. |
| 841 | */ |
| 842 | static int httpCmd( |
| 843 | Th_Interp *interp, |
| 844 | void *p, |
| 845 | int argc, |
| 846 | const char **argv, |
| 847 | int *argl |
| 848 | ){ |
| 849 | const char *zSep, *zType, *zRegexp, *zParams; |
| 850 | Blob hdr, payload; |
| 851 | ReCompiled *pRe = 0; |
| 852 | UrlData urlData; |
| 853 | |
| 854 | if( argc<2 || fossil_strnicmp(argv[1], "-asynchronous", argl[1]) ){ |
| 855 | Th_ErrorMessage(interp, |
| 856 | "synchronous http requests not yet implemented", 0, 0); |
| 857 | return TH_ERROR; |
| 858 | } |
| 859 | --argc; ++argv; ++argl; /* advance to next argument */ |
| 860 | blob_zero(&payload); |
| 861 | if( argc!=2 ){ |
| 862 | if( argc != 3 ){ |
| 863 | return Th_WrongNumArgs(interp, "http -asynchronous url ?payload?"); |
| 864 | } |
| 865 | blob_append(&payload, argv[2], argl[2]); |
| 866 | zType = "POST"; |
| 867 | }else{ |
| 868 | zType = "GET"; |
| 869 | } |
| 870 | zParams = strrchr(argv[1], '?'); |
| 871 | url_parse_local(argv[1], 0, &urlData); |
| 872 | if( urlData.isSsh || urlData.isFile ){ |
| 873 | Th_ErrorMessage(interp, "url must be http:// or https://", 0, 0); |
| 874 | return TH_ERROR; |
| 875 | } |
| 876 | zRegexp = db_get("th1-uri-regexp", 0); |
| @@ -885,42 +884,61 @@ | |
| 885 | Th_SetResult(interp, "url not allowed", -1); |
| 886 | re_free(pRe); |
| 887 | return TH_ERROR; |
| 888 | } |
| 889 | re_free(pRe); |
| 890 | if( transport_open(&urlData) ){ |
| 891 | Th_ErrorMessage(interp, transport_errmsg(&urlData), 0, 0); |
| 892 | return TH_ERROR; |
| 893 | } |
| 894 | blob_zero(&hdr); |
| 895 | if( strlen(urlData.path)>0 && zParams!=argv[1] ){ |
| 896 | zSep = ""; |
| 897 | }else{ |
| 898 | zSep = "/"; |
| 899 | } |
| 900 | blob_appendf(&hdr, "%s %s%s%s HTTP/1.0\r\n", |
| 901 | zType, zSep, urlData.path, zParams ? zParams : ""); |
| 902 | if( urlData.proxyAuth ){ |
| 903 | blob_appendf(&hdr, "Proxy-Authorization: %s\r\n", urlData.proxyAuth); |
| 904 | } |
| 905 | if( urlData.passwd && urlData.user && urlData.passwd[0]=='#' ){ |
| 906 | char *zCredentials = mprintf("%s:%s", urlData.user, &urlData.passwd[1]); |
| 907 | char *zEncoded = encode64(zCredentials, -1); |
| 908 | blob_appendf(&hdr, "Authorization: Basic %s\r\n", zEncoded); |
| 909 | fossil_free(zEncoded); |
| 910 | fossil_free(zCredentials); |
| 911 | } |
| 912 | blob_appendf(&hdr, "Host: %s\r\n", urlData.hostname); |
| 913 | blob_appendf(&hdr, "User-Agent: Fossil/" RELEASE_VERSION |
| 914 | " (" MANIFEST_DATE " " MANIFEST_VERSION ")\r\n"); |
| 915 | blob_appendf(&hdr, "Content-Type: text/plain\r\n"); |
| 916 | blob_appendf(&hdr, "Content-Length: %d\r\n\r\n", blob_size(&payload)); |
| 917 | transport_send(&urlData, &hdr); |
| 918 | transport_send(&urlData, &payload); |
| 919 | transport_close(&urlData); |
| 920 | Th_SetResult(interp, 0, 0); /* NOTE: Asynchronous, no results yet. */ |
| 921 | return TH_OK; |
| 922 | } |
| 923 | |
| 924 | /* |
| 925 | ** Make sure the interpreter has been initialized. Initialize it if |
| 926 | ** it has not been already. |
| 927 |
| --- src/th_main.c | |
| +++ src/th_main.c | |
| @@ -830,47 +830,46 @@ | |
| 830 | re_free(pRe); |
| 831 | return rc; |
| 832 | } |
| 833 | |
| 834 | /* |
| 835 | ** TH command: http ?-asynchronous? ?--? url ?payload? |
| 836 | ** |
| 837 | ** Perform an HTTP or HTTPS request for the specified URL. If a |
| 838 | ** payload is present, it will be interpreted as text/plain and |
| 839 | ** the POST method will be used; otherwise, the GET method will |
| 840 | ** be used. Upon success, if the -asynchronous option is used, an |
| 841 | ** empty string is returned as the result; otherwise, the response |
| 842 | ** from the server is returned as the result. Synchronous requests |
| 843 | ** are not currently implemented. |
| 844 | */ |
| 845 | #define HTTP_WRONGNUMARGS "http ?-asynchronous? ?--? url ?payload?" |
| 846 | static int httpCmd( |
| 847 | Th_Interp *interp, |
| 848 | void *p, |
| 849 | int argc, |
| 850 | const char **argv, |
| 851 | int *argl |
| 852 | ){ |
| 853 | int nArg = 1; |
| 854 | int fAsynchronous = 0; |
| 855 | const char *zType, *zRegexp; |
| 856 | Blob payload; |
| 857 | ReCompiled *pRe = 0; |
| 858 | UrlData urlData; |
| 859 | |
| 860 | if( argc<2 || argc>5 ){ |
| 861 | return Th_WrongNumArgs(interp, HTTP_WRONGNUMARGS); |
| 862 | } |
| 863 | if( fossil_strnicmp(argv[nArg], "-asynchronous", argl[nArg])==0 ){ |
| 864 | fAsynchronous = 1; nArg++; |
| 865 | } |
| 866 | if( fossil_strcmp(argv[nArg], "--")==0 ) nArg++; |
| 867 | if( nArg+1!=argc && nArg+2!=argc ){ |
| 868 | return Th_WrongNumArgs(interp, REGEXP_WRONGNUMARGS); |
| 869 | } |
| 870 | url_parse_local(argv[nArg], 0, &urlData); |
| 871 | if( urlData.isSsh || urlData.isFile ){ |
| 872 | Th_ErrorMessage(interp, "url must be http:// or https://", 0, 0); |
| 873 | return TH_ERROR; |
| 874 | } |
| 875 | zRegexp = db_get("th1-uri-regexp", 0); |
| @@ -885,42 +884,61 @@ | |
| 884 | Th_SetResult(interp, "url not allowed", -1); |
| 885 | re_free(pRe); |
| 886 | return TH_ERROR; |
| 887 | } |
| 888 | re_free(pRe); |
| 889 | blob_zero(&payload); |
| 890 | if( nArg+2==argc ){ |
| 891 | blob_append(&payload, argv[nArg+1], argl[nArg+1]); |
| 892 | zType = "POST"; |
| 893 | }else{ |
| 894 | zType = "GET"; |
| 895 | } |
| 896 | if( fAsynchronous ){ |
| 897 | const char *zSep, *zParams; |
| 898 | Blob hdr; |
| 899 | zParams = strrchr(argv[nArg], '?'); |
| 900 | if( strlen(urlData.path)>0 && zParams!=argv[nArg] ){ |
| 901 | zSep = ""; |
| 902 | }else{ |
| 903 | zSep = "/"; |
| 904 | } |
| 905 | blob_zero(&hdr); |
| 906 | blob_appendf(&hdr, "%s %s%s%s HTTP/1.0\r\n", |
| 907 | zType, zSep, urlData.path, zParams ? zParams : ""); |
| 908 | if( urlData.proxyAuth ){ |
| 909 | blob_appendf(&hdr, "Proxy-Authorization: %s\r\n", urlData.proxyAuth); |
| 910 | } |
| 911 | if( urlData.passwd && urlData.user && urlData.passwd[0]=='#' ){ |
| 912 | char *zCredentials = mprintf("%s:%s", urlData.user, &urlData.passwd[1]); |
| 913 | char *zEncoded = encode64(zCredentials, -1); |
| 914 | blob_appendf(&hdr, "Authorization: Basic %s\r\n", zEncoded); |
| 915 | fossil_free(zEncoded); |
| 916 | fossil_free(zCredentials); |
| 917 | } |
| 918 | blob_appendf(&hdr, "Host: %s\r\n", urlData.hostname); |
| 919 | blob_appendf(&hdr, "User-Agent: Fossil/" RELEASE_VERSION |
| 920 | " (" MANIFEST_DATE " " MANIFEST_VERSION ")\r\n"); |
| 921 | blob_appendf(&hdr, "Content-Type: text/plain\r\n"); |
| 922 | blob_appendf(&hdr, "Content-Length: %d\r\n\r\n", blob_size(&payload)); |
| 923 | if( transport_open(&urlData) ){ |
| 924 | Th_ErrorMessage(interp, transport_errmsg(&urlData), 0, 0); |
| 925 | return TH_ERROR; |
| 926 | } |
| 927 | transport_send(&urlData, &hdr); |
| 928 | transport_send(&urlData, &payload); |
| 929 | blob_reset(&hdr); |
| 930 | blob_reset(&payload); |
| 931 | transport_close(&urlData); |
| 932 | Th_SetResult(interp, 0, 0); /* NOTE: Asynchronous, no results. */ |
| 933 | return TH_OK; |
| 934 | }else{ |
| 935 | blob_reset(&payload); |
| 936 | Th_ErrorMessage(interp, |
| 937 | "synchronous requests are not yet implemented", 0, 0); |
| 938 | return TH_ERROR; |
| 939 | } |
| 940 | } |
| 941 | |
| 942 | /* |
| 943 | ** Make sure the interpreter has been initialized. Initialize it if |
| 944 | ** it has not been already. |
| 945 |