pastebin - collaborative debugging tool
nrubsig.kpaste.net RSS


URL parameter work backup 2024-07-08
Posted by Anonymous on Mon 8th Jul 2024 17:43
raw | new post

  1. diff --git a/cygwin/utils/mount_sshnfs/mount_sshnfs.ksh b/cygwin/utils/mount_sshnfs/mount_sshnfs.ksh
  2. index c1dc4b5..be96ec0 100644
  3. --- a/cygwin/utils/mount_sshnfs/mount_sshnfs.ksh
  4. +++ b/cygwin/utils/mount_sshnfs/mount_sshnfs.ksh
  5. @@ -240,6 +240,16 @@ function netstat_find_next_free_local_tcp_port
  6.  }
  7.  
  8.  
  9. +function urldecodestr
  10. +{
  11. +       nameref out=$1
  12. +       typeset s="$2"
  13. +       s="${s//$'\\'/$'\\\\'}"
  14. +       s="${s//+/ }"
  15. +       out="${ printf "${s//~(E)(?:%([[:xdigit:]][[:xdigit:]]))/\\x}" ; }"
  16. +       return 0
  17. +}
  18. +
  19.  #
  20.  # parse_rfc1738_url - parse RFC 1838 URLs
  21.  #
  22. @@ -253,6 +263,7 @@ function parse_rfc1738_url
  23.         typeset url="$2"
  24.         typeset leftover
  25.         nameref data="$1" # output compound variable
  26. +       typeset url_param_str
  27.  
  28.         # ~(E) is POSIX extended regular expression matching (instead
  29.         # of shell pattern), "x" means "multiline", "l" means "left
  30. @@ -271,7 +282,9 @@ function parse_rfc1738_url
  31.                                 (?::([[:digit:]]+))? # port (optional)
  32.                         )
  33.                 )
  34. -               (?:\/(.*?))?/X}"                # path (optional)
  35. +               (?:\/(.*?))?                    # path (optional)
  36. +               (?:\?(.*?))?                    # URL parameters (optional)
  37. +               /X}"
  38.  
  39.         # All parsed data should be captured via eregex in .sh.match - if
  40.         # there is anything left (except the 'X') then the input string did
  41. @@ -291,8 +304,34 @@ function parse_rfc1738_url
  42.         [[ "${.sh.match[7]-}" != '' ]] && integer data.port="${.sh.match[7]}"
  43.         [[ "${.sh.match[8]-}" != '' ]] && data.uripath="${.sh.match[8]}"
  44.  
  45. +       if [[ "${.sh.match[9]-}" != '' ]] ; then
  46. +               compound -a data.parameters
  47. +
  48. +               url_param_str="${.sh.match[9]-}"
  49. +
  50. +               while [[ "$url_param_str" != '' ]] ; do
  51. +                       leftover="${url_param_str/~(Elrx)(?:(.+?)(?:=(.+?))?)(?:&(.*))?/X}"
  52. +
  53. +                       # save matches because urldecodestr uses .sh.match, too
  54. +                       typeset dp_name
  55. +                       typeset dp_value
  56. +                       typeset dp_next="${.sh.match[3]-}"
  57. +
  58. +                       urldecodestr dp_name "${.sh.match[1]-}"
  59. +                       urldecodestr dp_value "${.sh.match[1]-}"
  60. +
  61. +                       data.parameters+=(
  62. +                               name="${dp_name}"
  63. +                               value="${dp_value}"
  64. +                               )
  65. +
  66. +                       # next parameter
  67. +                       url_param_str="${dp_next}"
  68. +               done
  69. +       fi
  70. +
  71.         if [[ -v data.uripath ]] ; then
  72. -               data.path="${ printf "${data.uripath//~(E)(?:%([[:xdigit:]][[:xdigit:]]))/\\x}" ; }"
  73. +               urldecodestr data.path "${data.uripath}"
  74.         fi
  75.  
  76.         return 0
  77. @@ -367,7 +406,7 @@ function cmd_mount
  78.  
  79.         # fixme: Need better text layout for $ mount_sshnfs mount --man #
  80.         typeset -r mount_sshnfs_cmdmount_usage=$'+
  81. -       [-?\n@(#)\$Id: mount_sshnfs mount (Roland Mainz) 2024-01-31 \$\n]
  82. +       [-?\n@(#)\$Id: mount_sshnfs mount (Roland Mainz) 2024-07-08 \$\n]
  83.         [-author?Roland Mainz <roland.mainz@nrubsig.org>]
  84.         [+NAME?mount_sshnfs mount - mount NFSv4 filesystem through ssh
  85.                 tunnel]
  86. @@ -733,7 +772,7 @@ function cmd_umount
  87.         typeset mydebug=false # fixme: should be "bool" for ksh93v
  88.         # fixme: Need better text layout for $ mount_sshnfs mount --man #
  89.         typeset -r mount_sshnfs_cmdumount_usage=$'+
  90. -       [-?\n@(#)\$Id: mount_sshnfs umount (Roland Mainz) 2024-01-31 \$\n]
  91. +       [-?\n@(#)\$Id: mount_sshnfs umount (Roland Mainz) 2024-07-08 \$\n]
  92.         [-author?Roland Mainz <roland.mainz@nrubsig.org>]
  93.         [+NAME?mount_sshnfs umount - unmount NFSv4 filesystem mounted
  94.                 via mount_sshnfs mount]
  95. @@ -837,7 +876,7 @@ function main
  96.  
  97.         # fixme: Need better text layout for $ mount_sshnfs --man #
  98.         typeset -r mount_sshnfs_usage=$'+
  99. -       [-?\n@(#)\$Id: mount_sshnfs (Roland Mainz) 2024-01-31 \$\n]
  100. +       [-?\n@(#)\$Id: mount_sshnfs (Roland Mainz) 2024-07-08 \$\n]
  101.         [-author?Roland Mainz <roland.mainz@nrubsig.org>]
  102.         [+NAME?mount_sshnfs - mount/umount NFSv4 filesystem via ssh
  103.                 tunnel]
  104. diff --git a/cygwin/utils/nfsurlconv/nfsurlconv.ksh b/cygwin/utils/nfsurlconv/nfsurlconv.ksh
  105. index 97db401..1a28bfe 100644
  106. --- a/cygwin/utils/nfsurlconv/nfsurlconv.ksh
  107. +++ b/cygwin/utils/nfsurlconv/nfsurlconv.ksh
  108. @@ -38,6 +38,16 @@ function usage
  109.         return 2
  110.  }
  111.  
  112. +function urldecodestr
  113. +{
  114. +       nameref out=$1
  115. +       typeset s="$2"
  116. +       s="${s//$'\\'/$'\\\\'}"
  117. +       s="${s//+/ }"
  118. +       out="${ printf "${s//~(E)(?:%([[:xdigit:]][[:xdigit:]]))/\\x}" ; }"
  119. +       return 0
  120. +}
  121. +
  122.  #
  123.  # parse_rfc1738_url - parse RFC 1838 URLs
  124.  #
  125. @@ -51,6 +61,7 @@ function parse_rfc1738_url
  126.         typeset url="$2"
  127.         typeset leftover
  128.         nameref data="$1" # output compound variable
  129. +       typeset url_param_str
  130.  
  131.         # ~(E) is POSIX extended regular expression matching (instead
  132.         # of shell pattern), "x" means "multiline", "l" means "left
  133. @@ -69,7 +80,9 @@ function parse_rfc1738_url
  134.                                 (?::([[:digit:]]+))? # port (optional)
  135.                         )
  136.                 )
  137. -               (?:\/(.*?))?/X}"                # path (optional)
  138. +               (?:\/(.*?))?                    # path (optional)
  139. +               (?:\?(.*?))?                    # URL parameters (optional)
  140. +               /X}"
  141.  
  142.         # All parsed data should be captured via eregex in .sh.match - if
  143.         # there is anything left (except the 'X') then the input string did
  144. @@ -89,8 +102,34 @@ function parse_rfc1738_url
  145.         [[ "${.sh.match[7]-}" != '' ]] && integer data.port="${.sh.match[7]}"
  146.         [[ "${.sh.match[8]-}" != '' ]] && data.uripath="${.sh.match[8]}"
  147.  
  148. +       if [[ "${.sh.match[9]-}" != '' ]] ; then
  149. +               compound -a data.parameters
  150. +
  151. +               url_param_str="${.sh.match[9]-}"
  152. +
  153. +               while [[ "$url_param_str" != '' ]] ; do
  154. +                       leftover="${url_param_str/~(Elrx)(?:(.+?)(?:=(.+?))?)(?:&(.*))?/X}"
  155. +
  156. +                       # save matches because urldecodestr uses .sh.match, too
  157. +                       typeset dp_name
  158. +                       typeset dp_value
  159. +                       typeset dp_next="${.sh.match[3]-}"
  160. +
  161. +                       urldecodestr dp_name "${.sh.match[1]-}"
  162. +                       urldecodestr dp_value "${.sh.match[1]-}"
  163. +
  164. +                       data.parameters+=(
  165. +                               name="${dp_name}"
  166. +                               value="${dp_value}"
  167. +                               )
  168. +
  169. +                       # next parameter
  170. +                       url_param_str="${dp_next}"
  171. +               done
  172. +       fi
  173. +
  174.         if [[ -v data.uripath ]] ; then
  175. -               data.path="${ printf "${data.uripath//~(E)(?:%([[:xdigit:]][[:xdigit:]]))/\\x}" ; }"
  176. +               urldecodestr data.path "${data.uripath}"
  177.         fi
  178.  
  179.         return 0
  180. @@ -207,7 +246,7 @@ function main
  181.  
  182.         # fixme: Need better text layout for $ nfsurlconv --man #
  183.         typeset -r nfsurlconv_usage=$'+
  184. -       [-?\n@(#)\$Id: nfsurlconv (Roland Mainz) 2024-01-31 \$\n]
  185. +       [-?\n@(#)\$Id: nfsurlconv (Roland Mainz) 2024-07-08 \$\n]
  186.         [-author?Roland Mainz <roland.mainz@nrubsig.org>]
  187.         [+NAME?nfsurlconv - convert hostname,port,path from/to a nfs://-URL]
  188.         [+DESCRIPTION?\bnfsurlconv\b convert { hostname, port, path } from/to a nfs://-URL.]
  189. @@ -238,6 +277,14 @@ path=/a/b/c
  190.  hostport=bbb
  191.  path=/a/b/c
  192.  ]
  193. +}
  194. +               [+?Example 4:][+?Convert URL nfs://bbb:12049//a/b/c?param1=pvalue1&param2=pvalue2 to ( hostport=, path=, urlparameter= )]{
  195. +[+\n$ nfsurlconv.ksh url2hostportpath "nfs:://bbb::12049//a/b/c??param1=pvalue1&param2=pvalue2"
  196. +hostport=bbb::12049
  197. +path=/a/b/c
  198. +urlparameter=( name=param1 value=pvalue1 )
  199. +urlparameter=( name=param2 value=pvalue2 )
  200. +]
  201.  }
  202.         }
  203.         [+SEE ALSO?\bksh93\b(1),\bssh\b(1),\bmount.nfs\b(8),\bnfs\b(5)]
  204. @@ -299,6 +346,13 @@ path=/a/b/c
  205.                         printf 'hostname=%s\n' "${urldata.host}"
  206.                         printf 'port=%s\n' "${urldata.port-2049}"
  207.                         printf 'path=%s\n' "${urldata.path-}"
  208. +                       if [[ -v urldata.parameters ]] ; then
  209. +                               for (( i=0 ; i < ${#urldata.parameters[@]} ; i++ )) ; do
  210. +                                       printf 'urlparameter=( name=%q value=%q )\n' \
  211. +                                               "${urldata.parameters[i].name}" \
  212. +                                               "${urldata.parameters[i].value}"
  213. +                               done
  214. +                       fi
  215.                         return 0
  216.                         ;;
  217.                 'url2hostportpath')
  218. @@ -307,6 +361,13 @@ path=/a/b/c
  219.                         parse_sshnfs_url urldata "${@:2:1}" || return 1
  220.                         printf 'hostport=%s\n' "${urldata.hostport}"
  221.                         printf 'path=%s\n' "${urldata.path-}"
  222. +                       if [[ -v urldata.parameters ]] ; then
  223. +                               for (( i=0 ; i < ${#urldata.parameters[@]} ; i++ )) ; do
  224. +                                       printf 'urlparameter=( name=%q value=%q )\n' \
  225. +                                               "${urldata.parameters[i].name}" \
  226. +                                               "${urldata.parameters[i].value}"
  227. +                               done
  228. +                       fi
  229.                         return 0
  230.                         ;;
  231.                 'url2compound')
  232. diff --git a/cygwin/utils/sshnfs/sshnfs.ksh b/cygwin/utils/sshnfs/sshnfs.ksh
  233. index bfccabb..21d08f0 100644
  234. --- a/cygwin/utils/sshnfs/sshnfs.ksh
  235. +++ b/cygwin/utils/sshnfs/sshnfs.ksh
  236. @@ -222,6 +222,16 @@ function netstat_find_next_free_local_tcp_port
  237.  }
  238.  
  239.  
  240. +function urldecodestr
  241. +{
  242. +       nameref out=$1
  243. +       typeset s="$2"
  244. +       s="${s//$'\\'/$'\\\\'}"
  245. +       s="${s//+/ }"
  246. +       out="${ printf "${s//~(E)(?:%([[:xdigit:]][[:xdigit:]]))/\\x}" ; }"
  247. +       return 0
  248. +}
  249. +
  250.  #
  251.  # parse_rfc1738_url - parse RFC 1838 URLs
  252.  #
  253. @@ -235,6 +245,7 @@ function parse_rfc1738_url
  254.         typeset url="$2"
  255.         typeset leftover
  256.         nameref data="$1" # output compound variable
  257. +       typeset url_param_str
  258.  
  259.         # ~(E) is POSIX extended regular expression matching (instead
  260.         # of shell pattern), "x" means "multiline", "l" means "left
  261. @@ -253,7 +264,9 @@ function parse_rfc1738_url
  262.                                 (?::([[:digit:]]+))? # port (optional)
  263.                         )
  264.                 )
  265. -               (?:\/(.*?))?/X}"                # path (optional)
  266. +               (?:\/(.*?))?                    # path (optional)
  267. +               (?:\?(.*?))?                    # URL parameters (optional)
  268. +               /X}"
  269.  
  270.         # All parsed data should be captured via eregex in .sh.match - if
  271.         # there is anything left (except the 'X') then the input string did
  272. @@ -273,8 +286,34 @@ function parse_rfc1738_url
  273.         [[ "${.sh.match[7]-}" != '' ]] && integer data.port="${.sh.match[7]}"
  274.         [[ "${.sh.match[8]-}" != '' ]] && data.uripath="${.sh.match[8]}"
  275.  
  276. +       if [[ "${.sh.match[9]-}" != '' ]] ; then
  277. +               compound -a data.parameters
  278. +
  279. +               url_param_str="${.sh.match[9]-}"
  280. +
  281. +               while [[ "$url_param_str" != '' ]] ; do
  282. +                       leftover="${url_param_str/~(Elrx)(?:(.+?)(?:=(.+?))?)(?:&(.*))?/X}"
  283. +
  284. +                       # save matches because urldecodestr uses .sh.match, too
  285. +                       typeset dp_name
  286. +                       typeset dp_value
  287. +                       typeset dp_next="${.sh.match[3]-}"
  288. +
  289. +                       urldecodestr dp_name "${.sh.match[1]-}"
  290. +                       urldecodestr dp_value "${.sh.match[1]-}"
  291. +
  292. +                       data.parameters+=(
  293. +                               name="${dp_name}"
  294. +                               value="${dp_value}"
  295. +                               )
  296. +
  297. +                       # next parameter
  298. +                       url_param_str="${dp_next}"
  299. +               done
  300. +       fi
  301. +
  302.         if [[ -v data.uripath ]] ; then
  303. -               data.path="${ printf "${data.uripath//~(E)(?:%([[:xdigit:]][[:xdigit:]]))/\\x}" ; }"
  304. +               urldecodestr data.path "${data.uripath}"
  305.         fi
  306.  
  307.         return 0
  308. diff --git a/mount/mount.c b/mount/mount.c
  309. index 67b011a..06a0c35 100644
  310. --- a/mount/mount.c
  311. +++ b/mount/mount.c
  312. @@ -71,6 +71,7 @@ static VOID PrintUsage(LPTSTR pProcess)
  313.  {
  314.      (void)_tprintf(
  315.          TEXT("Usage: %s [options] <drive letter|*> <hostname>:<path>\n")
  316. +
  317.          TEXT("* Options:\n")
  318.          TEXT("\t-h\thelp\n")
  319.          TEXT("\t/?\thelp\n")
  320. @@ -82,6 +83,7 @@ static VOID PrintUsage(LPTSTR pProcess)
  321.             " (Linux compat)\n")
  322.          TEXT("\t-p\tmake the mount persist over reboots\n")
  323.          TEXT("\t-o <comma-separated mount options>\n")
  324. +
  325.          TEXT("* Mount options:\n")
  326.          TEXT("\tro\tmount as read-only\n")
  327.          TEXT("\trw\tmount as read-write (default)\n")
  328. @@ -100,23 +102,33 @@ static VOID PrintUsage(LPTSTR pProcess)
  329.              "\t\tif this value is prefixed with 'nfsv3attrmode+'\n"
  330.              "\t\tthe mode value from a \"NfsV3Attributes\" EA will be used\n"
  331.              "\t\t(defaults \"nfsv3attrmode+0o%o\").\n")
  332. +
  333. +        TEXT("* URL parameters:\n")
  334. +        TEXT("\tro=1\tmount as read-only\n")
  335. +        TEXT("\trw=1\tmount as read-write (default)\n")
  336. +
  337.          TEXT("* Hostname:\n")
  338.          TEXT("\tDNS name, or hostname in domain\n")
  339.          TEXT("\tentry in C:\\Windows\\System32\\drivers\\etc\\hosts\n")
  340.          TEXT("\tIPv4 address\n")
  341.          TEXT("\tIPv6 address within '[', ']' "
  342.              "(will be converted to *.ipv6-literal.net)\n")
  343. +
  344.          TEXT("* Examples:\n")
  345.          TEXT("\tnfs_mount.exe -p -o rw 'H' derfwpc5131_ipv4:/export/home2/rmainz\n")
  346.          TEXT("\tnfs_mount.exe -o rw '*' bigramhost:/tmp\n")
  347. +        TEXT("\tnfs_mount.exe -o ro '*' archive1:/tmp\n")
  348. +        TEXT("\tnfs_mount.exe '*' archive1:/tmp?ro=1\n")
  349.          TEXT("\tnfs_mount.exe -o rw,sec=sys,port=30000 T grendel:/net_tmpfs2\n")
  350.          TEXT("\tnfs_mount.exe -o sec=sys,rw S nfs://myhost1//net_tmpfs2/test2\n")
  351. +        TEXT("\tnfs_mount.exe -o sec=sys S nfs://myhost1//net_tmpfs2/test2?rw=1\n")
  352.          TEXT("\tnfs_mount.exe -o sec=sys,rw S nfs://myhost1:1234//net_tmpfs2/test2\n")
  353.          TEXT("\tnfs_mount.exe -o sec=sys,rw,port=1234 S nfs://myhost1//net_tmpfs2/test2\n")
  354.          TEXT("\tnfs_mount.exe -o sec=sys,rw '*' [fe80::21b:1bff:fec3:7713]://net_tmpfs2/test2\n")
  355.          TEXT("\tnfs_mount.exe -o sec=sys,rw '*' nfs://[fe80::21b:1bff:fec3:7713]//net_tmpfs2/test2\n")
  356.          TEXT("\tnfs_mount.exe -o sec=sys,rw S nfs://myhost1//dirwithspace/dir%%20space/test2\n")
  357. -        TEXT("\tnfs_mount.exe -o sec=sys,rw S nfs://myhost1//dirwithspace/dir+space/test2\n"),
  358. +        TEXT("\tnfs_mount.exe -o sec=sys,rw S nfs://myhost1//dirwithspace/dir+space/test2\n")
  359. +        TEXT("\tnfs_mount.exe -o sec=sys S nfs://myhost1//dirwithspace/dir+space/test2?rw=1\n"),
  360.          pProcess, (int)NFS41_DRIVER_DEFAULT_CREATE_MODE);
  361.  }
  362.  
  363. @@ -404,6 +416,65 @@ static DWORD ParseRemoteName(
  364.              goto out;
  365.          }
  366.  
  367. +        if (uctx->num_parameters > 0) {
  368. +            int pi;
  369. +            const char *pname;
  370. +            const char *pvalue;
  371. +
  372. +            /*
  373. +             * FIXME: Values added here based on URL parameters
  374. +             * should be added at the front of the list of options,
  375. +             * so users can override the nfs://-URL given default.
  376. +             * Right now this does not work, e.g.
  377. +             * $ nfs_mount.exe -o rw nfs://foo//bar?ro=1 # will
  378. +             * result in a read-only mount, while the expectation
  379. +             * is that -o overrides URL settings.
  380. +             */
  381. +            for (pi = 0; pi < uctx->num_parameters ; pi++) {
  382. +                pname = uctx->parameters[pi].name;
  383. +                pvalue = uctx->parameters[pi].value;
  384. +
  385. +                if (!strcmp(pname, "rw")) {
  386. +                    if ((pvalue == NULL) || (!strcmp(pvalue, "1"))) {
  387. +                        (void)InsertOption(TEXT("rw"), TEXT("1"), pOptions);
  388. +                    }
  389. +                    else if (!strcmp(pvalue, "0")) {
  390. +                        (void)InsertOption(TEXT("ro"), TEXT("1"), pOptions);
  391. +                    }
  392. +                    else {
  393. +                        result = ERROR_BAD_ARGUMENTS;
  394. +                        (void)_ftprintf(stderr,
  395. +                            TEXT("Unsupported nfs://-URL parameter ")
  396. +                            TEXT("'%S' value '%S'.\n"),
  397. +                            pname, pvalue);
  398. +                        goto out;
  399. +                    }
  400. +                }
  401. +                else if (!strcmp(pname, "ro")) {
  402. +                    if ((pvalue == NULL) || (!strcmp(pvalue, "1"))) {
  403. +                        (void)InsertOption(TEXT("ro"), TEXT("1"), pOptions);
  404. +                    }
  405. +                    else if (!strcmp(pvalue, "0")) {
  406. +                        (void)InsertOption(TEXT("rw"), TEXT("1"), pOptions);
  407. +                    }
  408. +                    else {
  409. +                        result = ERROR_BAD_ARGUMENTS;
  410. +                        (void)_ftprintf(stderr,
  411. +                            TEXT("Unsupported nfs://-URL parameter ")
  412. +                            TEXT("'%S' value '%S'.\n"),
  413. +                            pname, pvalue);
  414. +                        goto out;
  415. +                    }
  416. +                }
  417. +                else {
  418. +                    result = ERROR_BAD_ARGUMENTS;
  419. +                    (void)_ftprintf(stderr,
  420. +                        TEXT("Unsupported nfs://-URL parameter '%S'.\n"), pname);
  421. +                    goto out;
  422. +                }
  423. +            }
  424. +        }
  425. +
  426.          if (uctx->hostport.port != -1)
  427.              port = uctx->hostport.port;
  428.  
  429. diff --git a/mount/urlparser1.c b/mount/urlparser1.c
  430. index a90d1e2..8fcae52 100644
  431. --- a/mount/urlparser1.c
  432. +++ b/mount/urlparser1.c
  433. @@ -28,10 +28,23 @@
  434.  #include <stdlib.h>
  435.  #include <stdbool.h>
  436.  #include <string.h>
  437. +#include <ctype.h>
  438.  #include <stdio.h>
  439.  
  440. +// #define TEST_URLPARSER 1
  441. +
  442.  #include "urlparser1.h"
  443.  
  444. +typedef struct _url_parser_context_private {
  445. +       url_parser_context c;
  446. +
  447. +       /* Private data */
  448. +       char *parameter_string_buff;
  449. +} url_parser_context_private;
  450. +
  451. +#define MAX_URL_PARAMETERS 256
  452. +
  453. +#ifdef _MSC_VER
  454.  /*
  455.   * Disable "warning C4996: 'wcscpy': This function or variable may be
  456.   * unsafe." because in this case the buffers are properly sized,
  457. @@ -43,6 +56,7 @@
  458.   * because it is safe to use in our code.
  459.   */
  460.  #pragma warning (disable : 4706)
  461. +#endif /* _MSC_VER */
  462.  
  463.  /*
  464.   * Original extended regular expression:
  465. @@ -62,69 +76,61 @@
  466.   *     ")"
  467.   * ")"
  468.   * "(?:/(.*?))?"                       // path (optional)
  469. + * "(?:\?(.*?))?"                      // URL parameters (optional)
  470.   * "$"
  471.   */
  472.  
  473.  #define DBGNULLSTR(s) (((s)!=NULL)?(s):"<NULL>")
  474. -#if 0
  475. +#if 0 || defined(TEST_URLPARSER)
  476.  #define D(x) x
  477.  #else
  478.  #define D(x)
  479.  #endif
  480.  
  481.  static
  482. -void urldecodestr(char *dst, const char *src, size_t len)
  483. +void urldecodestr(char *outbuff, const char *buffer, size_t len)
  484.  {
  485. -       /*
  486. -        * Unicode characters with a code point > 255 are encoded
  487. -        * as UTF-8 bytes
  488. -        */
  489. -#define isurlxdigit(c) \
  490. -       (((c) >= '0' && (c) <= '9') || \
  491. -       ((c) >= 'a' && (c) <= 'f') || \
  492. -       ((c) >= 'A' && (c) <= 'F'))
  493. -       char a, b;
  494. -       while (*src && len--) {
  495. -               if (len > 2) {
  496. -                       if ((*src == '%') &&
  497. -                               (a = src[1]) && (b = src[2])) {
  498. -                               if ((isurlxdigit(a) &&
  499. -                                       isurlxdigit(b))) {
  500. -                                       if (a >= 'a')
  501. -                                               a -= 'a'-'A';
  502. -                                       if (a >= 'A')
  503. -                                               a -= ('A' - 10);
  504. -                                       else
  505. -                                               a -= '0';
  506. -
  507. -                                       if (b >= 'a')
  508. -                                               b -= 'a'-'A';
  509. -                                       if (b >= 'A')
  510. -                                               b -= ('A' - 10);
  511. -                                       else
  512. -                                               b -= '0';
  513. -
  514. -                                       *dst++ = 16*a+b;
  515. -
  516. -                                       src+=3;
  517. -                                       len-=2;
  518. -                                       continue;
  519. -                               }
  520. +       size_t i, j;
  521. +
  522. +       for (i = j = 0 ; i < len ; ) {
  523. +               switch (buffer[i]) {
  524. +                       case '%':
  525. +                               if ((i + 2) < len) {
  526. +                                       if (isxdigit((int)buffer[i+1]) && isxdigit((int)buffer[i+2])) {
  527. +                                               const char hexstr[3] = {
  528. +                                                       buffer[i+1],
  529. +                                                       buffer[i+2],
  530. +                                                       '\0'
  531. +                                               };
  532. +                                               outbuff[j++] = (unsigned char)strtol(hexstr, NULL, 16);
  533. +                                               i += 3;
  534. +                                       } else {
  535. +                                               /* invalid hex digit */
  536. +                                               outbuff[j++] = buffer[i];
  537. +                                               i++;
  538.                                         }
  539. +                               } else {
  540. +                                       /* incomplete hex digit */
  541. +                                       outbuff[j++] = buffer[i];
  542. +                                       i++;
  543.                                 }
  544. -               if (*src == '+') {
  545. -                       *dst++ = ' ';
  546. -                       src++;
  547. -                       continue;
  548. +                               break;
  549. +                       case '+':
  550. +                               outbuff[j++] = ' ';
  551. +                               i++;
  552. +                               break;
  553. +                       default:
  554. +                               outbuff[j++] = buffer[i++];
  555. +                               break;
  556.                 }
  557. -               *dst++ = *src++;
  558.         }
  559. -       *dst++ = '\0';
  560. +
  561. +       outbuff[j] = '\0';
  562.  }
  563.  
  564.  url_parser_context *url_parser_create_context(const char *in_url, unsigned int flags)
  565.  {
  566. -       url_parser_context *uctx;
  567. +       url_parser_context_private *uctx;
  568.         char *s;
  569.         size_t in_url_len;
  570.         size_t context_len;
  571. @@ -137,30 +143,36 @@ url_parser_context *url_parser_create_context(const char *in_url, unsigned int f
  572.  
  573.         in_url_len = strlen(in_url);
  574.  
  575. -       context_len = sizeof(url_parser_context) +
  576. -               ((in_url_len+1)*5);
  577. +       context_len = sizeof(url_parser_context_private) +
  578. +               ((in_url_len+1)*6) +
  579. +               (sizeof(url_parser_name_value)*MAX_URL_PARAMETERS)+sizeof(void*);
  580.         uctx = malloc(context_len);
  581.         if (!uctx)
  582.                 return NULL;
  583.  
  584.         s = (void *)(uctx+1);
  585. -       uctx->in_url = s;               s+= in_url_len+1;
  586. -       (void)strcpy(uctx->in_url, in_url);
  587. -       uctx->scheme = s;               s+= in_url_len+1;
  588. -       uctx->login.username = s;       s+= in_url_len+1;
  589. -       uctx->hostport.hostname = s;    s+= in_url_len+1;
  590. -       uctx->path = s;                 s+= in_url_len+1;
  591. -       uctx->hostport.port = -1;
  592. -
  593. -       return uctx;
  594. +       uctx->c.in_url = s;             s+= in_url_len+1;
  595. +       (void)strcpy(uctx->c.in_url, in_url);
  596. +       uctx->c.scheme = s;             s+= in_url_len+1;
  597. +       uctx->c.login.username = s;     s+= in_url_len+1;
  598. +       uctx->c.hostport.hostname = s;  s+= in_url_len+1;
  599. +       uctx->c.path = s;               s+= in_url_len+1;
  600. +       uctx->c.hostport.port = -1;
  601. +       uctx->c.num_parameters = -1;
  602. +       uctx->c.parameters = (void *)s;         s+= (sizeof(url_parser_name_value)*MAX_URL_PARAMETERS)+sizeof(void*);
  603. +       uctx->parameter_string_buff = s;        s+= in_url_len+1;
  604. +
  605. +       return &uctx->c;
  606.  }
  607.  
  608. -int url_parser_parse(url_parser_context *uctx)
  609. +int url_parser_parse(url_parser_context *ctx)
  610.  {
  611. -       D((void)fprintf(stderr, "## parser in_url='%s'\n", uctx->in_url));
  612. +       url_parser_context_private *uctx = (url_parser_context_private *)ctx;
  613. +
  614. +       D((void)fprintf(stderr, "## parser in_url='%s'\n", uctx->c.in_url));
  615.  
  616.         char *s;
  617. -       const char *urlstr = uctx->in_url;
  618. +       const char *urlstr = uctx->c.in_url;
  619.         size_t slen;
  620.  
  621.         s = strstr(urlstr, "://");
  622. @@ -170,57 +182,120 @@ int url_parser_parse(url_parser_context *uctx)
  623.         }
  624.  
  625.         slen = s-urlstr;
  626. -       (void)memcpy(uctx->scheme, urlstr, slen);
  627. -       uctx->scheme[slen] = '\0';
  628. +       (void)memcpy(uctx->c.scheme, urlstr, slen);
  629. +       uctx->c.scheme[slen] = '\0';
  630.         urlstr += slen + 3;
  631.  
  632. -       D((void)fprintf(stdout, "scheme='%s', rest='%s'\n", uctx->scheme, urlstr));
  633. +       D((void)fprintf(stdout, "scheme='%s', rest='%s'\n", uctx->c.scheme, urlstr));
  634.  
  635.         s = strstr(urlstr, "@");
  636.         if (s) {
  637.                 /* URL has user/password */
  638.                 slen = s-urlstr;
  639. -               urldecodestr(uctx->login.username, urlstr, slen);
  640. +               urldecodestr(uctx->c.login.username, urlstr, slen);
  641.                 urlstr += slen + 1;
  642.  
  643. -               s = strstr(uctx->login.username, ":");
  644. +               s = strstr(uctx->c.login.username, ":");
  645.                 if (s) {
  646.                         /* found passwd */
  647. -                       uctx->login.passwd = s+1;
  648. +                       uctx->c.login.passwd = s+1;
  649.                         *s = '\0';
  650.                 }
  651.                 else
  652.                 {
  653. -                       uctx->login.passwd = NULL;
  654. +                       uctx->c.login.passwd = NULL;
  655.                 }
  656.  
  657.                 /* catch password-only URLs */
  658. -               if (uctx->login.username[0] == '\0')
  659. -                       uctx->login.username = NULL;
  660. +               if (uctx->c.login.username[0] == '\0')
  661. +                       uctx->c.login.username = NULL;
  662.         }
  663.         else
  664.         {
  665. -               uctx->login.username = NULL;
  666. -               uctx->login.passwd = NULL;
  667. +               uctx->c.login.username = NULL;
  668. +               uctx->c.login.passwd = NULL;
  669.         }
  670.  
  671.         D((void)fprintf(stdout, "login='%s', passwd='%s', rest='%s'\n",
  672. -               DBGNULLSTR(uctx->login.username),
  673. -               DBGNULLSTR(uctx->login.passwd),
  674. +               DBGNULLSTR(uctx->c.login.username),
  675. +               DBGNULLSTR(uctx->c.login.passwd),
  676.                 DBGNULLSTR(urlstr)));
  677.  
  678. +       char *raw_parameters;
  679. +
  680. +       uctx->c.num_parameters = 0;
  681. +       raw_parameters = strstr(urlstr, "?");
  682. +       if (raw_parameters) {
  683. +               *raw_parameters++ = '\0';
  684. +               D((void)fprintf(stdout, "raw parameters = '%s'\n", raw_parameters));
  685. +
  686. +               char *ps = raw_parameters;
  687. +               char *pv; /* parameter value */
  688. +               char *na; /* next '&' */
  689. +               char *pb = uctx->parameter_string_buff;
  690. +               char *pname;
  691. +               char *pvalue;
  692. +               ssize_t pi;
  693. +
  694. +               for (pi = 0; pi < MAX_URL_PARAMETERS ; pi++) {
  695. +                       pname = ps;
  696. +
  697. +                       /*
  698. +                        * Handle parameters without value,
  699. +                        * e.g. "path?name1&name2=value2"
  700. +                        */
  701. +                       na = strstr(ps, "&");
  702. +                       pv = strstr(ps, "=");
  703. +                       if (pv && (na?(na > pv):true)) {
  704. +                               *pv++ = '\0';
  705. +                               pvalue = pv;
  706. +                               ps = pv;
  707. +                       }
  708. +                       else {
  709. +                               pvalue = NULL;
  710. +                       }
  711. +
  712. +                       if (na) {
  713. +                               *na++ = '\0';
  714. +                       }
  715. +
  716. +                       /* URLDecode parameter name */
  717. +                       urldecodestr(pb, pname, strlen(pname));
  718. +                       uctx->c.parameters[pi].name = pb;
  719. +                       pb += strlen(uctx->c.parameters[pi].name)+1;
  720. +
  721. +                       /* URLDecode parameter value */
  722. +                       if (pvalue) {
  723. +                               urldecodestr(pb, pvalue, strlen(pvalue));
  724. +                               uctx->c.parameters[pi].value = pb;
  725. +                               pb += strlen(uctx->c.parameters[pi].value)+1;
  726. +                       }
  727. +                       else {
  728. +                               uctx->c.parameters[pi].value = NULL;
  729. +                       }
  730. +
  731. +                       /* Next '&' ? */
  732. +                       if (!na)
  733. +                               break;
  734. +
  735. +                       ps = na;
  736. +               }
  737. +
  738. +               uctx->c.num_parameters = pi+1;
  739. +       }
  740. +
  741.         s = strstr(urlstr, "/");
  742.         if (s) {
  743.                 /* URL has hostport */
  744.                 slen = s-urlstr;
  745. -               urldecodestr(uctx->hostport.hostname, urlstr, slen);
  746. +               urldecodestr(uctx->c.hostport.hostname, urlstr, slen);
  747.                 urlstr += slen + 1;
  748.  
  749.                 /*
  750.                  * check for addresses within '[' and ']', like
  751.                  * IPv6 addresses
  752.                  */
  753. -               s = uctx->hostport.hostname;
  754. +               s = uctx->c.hostport.hostname;
  755.                 if (s[0] == '[')
  756.                         s = strstr(s, "]");
  757.  
  758. @@ -232,29 +307,41 @@ int url_parser_parse(url_parser_context *uctx)
  759.                 s = strstr(s, ":");
  760.                 if (s) {
  761.                         /* found port number */
  762. -                       uctx->hostport.port = atoi(s+1);
  763. +                       uctx->c.hostport.port = atoi(s+1);
  764.                         *s = '\0';
  765.                 }
  766.         }
  767.         else
  768.         {
  769. -               (void)strcpy(uctx->hostport.hostname, urlstr);
  770. -               uctx->path = NULL;
  771. +               (void)strcpy(uctx->c.hostport.hostname, urlstr);
  772. +               uctx->c.path = NULL;
  773.                 urlstr = NULL;
  774.         }
  775.  
  776. -       D((void)fprintf(stdout, "hostport='%s', port=%d, rest='%s'\n",
  777. -               DBGNULLSTR(uctx->hostport.hostname),
  778. -               uctx->hostport.port,
  779. -               DBGNULLSTR(urlstr)));
  780. +       D((void)fprintf(stdout, "hostport='%s', port=%d, rest='%s', num_parameters=%d\n",
  781. +               DBGNULLSTR(uctx->c.hostport.hostname),
  782. +               uctx->c.hostport.port,
  783. +               DBGNULLSTR(urlstr),
  784. +               (int)uctx->c.num_parameters));
  785. +
  786. +       D(
  787. +               ssize_t dpi;
  788. +               for (dpi = 0 ; dpi < uctx->c.num_parameters ; dpi++) {
  789. +                       (void)fprintf(stdout, "param[%d]: name='%s'/value='%s'\n",
  790. +                               (int)dpi,
  791. +                               uctx->c.parameters[dpi].name,
  792. +                               DBGNULLSTR(uctx->c.parameters[dpi].value));
  793. +               }
  794. +       );
  795.  
  796.         if (!urlstr) {
  797. -               return 0;
  798. +               goto done;
  799.         }
  800.  
  801. -       urldecodestr(uctx->path, urlstr, strlen(urlstr));
  802. -       D((void)fprintf(stdout, "path='%s'\n", uctx->path));
  803. +       urldecodestr(uctx->c.path, urlstr, strlen(urlstr));
  804. +       D((void)fprintf(stdout, "path='%s'\n", uctx->c.path));
  805.  
  806. +done:
  807.         return 0;
  808.  }
  809.  
  810. @@ -301,7 +388,16 @@ int main(int ac, char *av[])
  811.         (void)test_url_parser("nfs://hostbar:93//absolutepath/a");
  812.         (void)test_url_parser("nfs://hostbar:93//absolutepath/blank%20path/a");
  813.         (void)test_url_parser("nfs://hostbar:93//absolutepath/blank+path/a");
  814. -
  815. +       (void)test_url_parser("foo://hostbar:93?param1");
  816. +       (void)test_url_parser("foo://hostbar:93?pname1=pvalue1");
  817. +       (void)test_url_parser("foo://hostbar:93?pname1=pvalue1&pname2=pvalue2");
  818. +       (void)test_url_parser("foo://hostbar:93?pname1=pvalue1&pvalue2=v2&n3=v3");
  819. +       (void)test_url_parser("foo://hostbar:93?pname1&param2=p2");
  820. +       (void)test_url_parser("foo://hostbar:93?pname1=&param2=p2");
  821. +       (void)test_url_parser("foo://hostbar:93//path/path2?param1=p1");
  822. +       (void)test_url_parser("foo://hostbar:93//path/path2?param1&param2=p2");
  823. +       (void)test_url_parser("foo://hostbar:93?pname1=pvalue1&%E2%82%AC=u+n2&n3=v3");
  824. +       (void)test_url_parser("foo://hostbar:93?pname1=pvalue1&%E2%82%AC=%E2%82%AC&n3=v3");
  825.  
  826.         (void)test_url_parser("foo://");
  827.         (void)test_url_parser("typo:/hostbar");
  828. diff --git a/mount/urlparser1.h b/mount/urlparser1.h
  829. index 8ed0f91..4526f1c 100644
  830. --- a/mount/urlparser1.h
  831. +++ b/mount/urlparser1.h
  832. @@ -26,8 +26,16 @@
  833.  
  834.  #include <stdlib.h>
  835.  
  836. -typedef
  837. -struct _url_parser_context {
  838. +#ifdef _MSC_VER
  839. +typedef signed long long ssize_t;
  840. +#endif
  841. +
  842. +typedef struct _url_parser_name_value {
  843. +       char *name;
  844. +       char *value;
  845. +} url_parser_name_value;
  846. +
  847. +typedef struct _url_parser_context {
  848.         char *in_url;
  849.  
  850.         char *scheme;
  851. @@ -40,6 +48,9 @@ struct _url_parser_context {
  852.                 signed int port;
  853.         } hostport;
  854.         char *path;
  855. +
  856. +       ssize_t num_parameters;
  857. +       url_parser_name_value *parameters;
  858.  } url_parser_context;
  859.  
  860.  /* Prototypes */

Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:

To highlight particular lines, prefix each line with {%HIGHLIGHT}




All content is user-submitted.
The administrators of this site (kpaste.net) are not responsible for their content.
Abuse reports should be emailed to us at