pastebin - collaborative debugging tool
nrubsig.kpaste.net RSS

Difference between
modified post b5f2185 by Anonymous on Fri 1st Nov 2024 10:59
original post 108bbc5d7 by Anonymous on Thu 31st Oct 2024 16:22
Download diff
Show old version | new version | both versions

    
11
diff --git a/utils/mount/Makefile.am b/utils/mount/Makefile.am
22
index 5ff1148c..ad1d0884 100644
33
--- a/utils/mount/Makefile.am
44
+++ b/utils/mount/Makefile.am
55
@@ -13,7 +13,8 @@ sbin_PROGRAMS	= mount.nfs
66
 EXTRA_DIST = nfsmount.conf $(man8_MANS) $(man5_MANS)
77
 mount_common = error.c network.c token.c \
88
 		    parse_opt.c parse_dev.c \
99
-		    nfsmount.c nfs4mount.c stropts.c\
1010
+		    nfsmount.c nfs4mount.c \
1111
+		    urlparser1.c urlparser1.h stropts.c \
1212
 		    mount_constants.h error.h network.h token.h \
1313
 		    parse_opt.h parse_dev.h \
1414
 		    nfs4_mount.h stropts.h version.h \
1515
diff --git a/utils/mount/nfs4mount.c b/utils/mount/nfs4mount.c
16-
index 0fe142a7..b4085c08 100644
16+
index 0fe142a7..20199f65 100644
1717
--- a/utils/mount/nfs4mount.c
1818
+++ b/utils/mount/nfs4mount.c
19-
@@ -50,6 +50,7 @@
19+
@@ -50,8 +50,10 @@
2020
 #include "mount_constants.h"
2121
 #include "nfs4_mount.h"
2222
 #include "nfs_mount.h"
2323
+#include "urlparser1.h"
2424
 #include "error.h"
2525
 #include "network.h"
26+
+#include "utils.h"
2627
27-
@@ -192,15 +193,62 @@ int nfs4mount(const char *spec, const char *node, int flags,
28+
 #if defined(VAR_LOCK_DIR)
29+
 #define DEFAULT_DIR VAR_LOCK_DIR
2831
 	int retry;
2932
 	int retval = EX_FAIL;
3033
 	time_t timeout, t;
3134
+	int nfs_port = NFS_PORT;
3235
+	url_parser_context *uctx = NULL;
3336
3437
 	if (strlen(spec) >= sizeof(hostdir)) {
3538
 		nfs_error(_("%s: excessively long host:dir argument\n"),
3639
 				progname);
3740
 		goto fail;
3841
 	}
3942
-	strcpy(hostdir, spec);
4043
-	if (parse_devname(hostdir, &hostname, &dirname))
4144
-		goto fail;
4245
+
4346
+	/*
4447
+	 * Support nfs://-URLS per RFC 2224 ("NFS URL
4548
+	 * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
4649
+	 * including port support (nfs://hostname@port/path/...)
4750
+	 */
4851
+	if (!strncmp(spec, "nfs://", 6)) {
52+
+		dirname = NULL;
4954
+		uctx = url_parser_create_context(spec, 0);
5055
+	        if (!uctx) {
5156
+			nfs_error(_("%s: out of memory"),
5257
+				progname);
5358
+			goto fail;
5459
+		}
5560
+
5661
+		if (url_parser_parse(uctx) < 0) {
5762
+			nfs_error(_("%s: Error parsing nfs://-URL."),
5863
+				progname);
5964
+			goto fail;
6065
+		}
6166
+		if (uctx->login.username || uctx->login.passwd) {
6267
+			nfs_error(_("%s: Username/Password are not defined for nfs://-URL."),
6368
+				progname);
6469
+			goto fail;
6570
+		}
6671
+		if (!uctx->path) {
6772
+			nfs_error(_("%s: Path missing in nfs://-URL."),
6873
+				progname);
6974
+			goto fail;
7075
+		}
7176
+		if (uctx->path[0] != '/') {
7277
+			nfs_error(_("%s: Relative nfs://-URLs are not supported."),
7378
+				progname);
7479
+			goto fail;
7580
+		}
7681
+
7782
+		if (uctx->hostport.port != -1) {
7883
+			nfs_port = uctx->hostport.port;
7984
+		}
8085
+
8186
+		hostname = uctx->hostport.hostname;
82-
+		/* fixme: |uctx->path| is in UTF-8, we should use |iconv()| to current locale */
87+
+		dirname = utf8str2mbstr(uctx->path);
8688
+
87-
+		if (parse_devname(hostdir, &hostname, &dirname))
89+
+		(void)snprintf(hostdir, sizeof(hostdir), "%s:/%s",
88-
+			goto fail;
90+
+			hostname, dirname);
89-
+	}
91+
+		spec = hostdir;
90-
92+
+
91-
 	if (fill_ipv4_sockaddr(hostname, &server_addr))
93+
+		if (uctx->num_parameters > 0) {
92-
 		goto fail;
94+
+			int pi;
93-
@@ -247,7 +295,7 @@ int nfs4mount(const char *spec, const char *node, int flags,
95+
+			const char *pname;
94-
 	/*
96+
+			const char *pvalue;
95-
 	 * NFSv4 specifies that the default port should be 2049
97+
+
96-
 	 */
98+
+			/*
97-
-	server_addr.sin_port = htons(NFS_PORT);
99+
+			 * Values added here based on URL parameters
98-
+	server_addr.sin_port = htons(nfs_port);
100+
+			 * should be added the front of the list of options,
99-
101+
+			 * so users can override the nfs://-URL given default.
100-
 	/* parse options */
102+
+			 *
101-
103+
+			 * FIXME: We do not do that here for |MS_RDONLY|!
102-
@@ -474,8 +522,12 @@ int nfs4mount(const char *spec, const char *node, int flags,
104+
+			 */
103-
 		}
105+
+			for (pi = 0; pi < uctx->num_parameters ; pi++) {
104-
 	}
106+
+				pname = uctx->parameters[pi].name;
105-
107+
+				pvalue = uctx->parameters[pi].value;
107108
+
108-
 	return EX_SUCCESS;
109+
+				if (!strcmp(pname, "rw")) {
109-
110+
+					if ((pvalue == NULL) || (!strcmp(pvalue, "1"))) {
110-
 fail:
111+
+						flags &= ~MS_RDONLY;
111-
+	url_parser_free_context(uctx);
112+
+					}
112-
+
113+
+					else if (!strcmp(pvalue, "0")) {
113-
 	return retval;
114+
+						flags |= MS_RDONLY;
114-
 }
115+
+					}
115-
diff --git a/utils/mount/nfsmount.c b/utils/mount/nfsmount.c
116+
+					else {
116-
index a1c92fe8..863aa2c6 100644
117+
+						nfs_error(_("%s: Unsupported nfs://-URL "
117-
--- a/utils/mount/nfsmount.c
118+
+							"parameter '%s' value '%s'."),
118-
+++ b/utils/mount/nfsmount.c
119+
+							progname, pname, pvalue);
119-
@@ -63,11 +63,13 @@
120+
+						goto fail;
120-
 #include "xcommon.h"
121+
+					}
121-
 #include "mount.h"
122+
+				}
122-
 #include "nfs_mount.h"
123+
+				else if (!strcmp(pname, "ro")) {
123-
+#include "urlparser1.h"
124+
+					if ((pvalue == NULL) || (!strcmp(pvalue, "1"))) {
124-
 #include "mount_constants.h"
125+
+						flags |= MS_RDONLY;
125-
 #include "nls.h"
126+
+					}
126-
 #include "error.h"
127+
+					else if (!strcmp(pvalue, "0")) {
127-
 #include "network.h"
128+
+						flags &= ~MS_RDONLY;
128-
 #include "version.h"
129+
+					}
129-
+#include "utils.h"
130+
+					else {
130-
131+
+						nfs_error(_("%s: Unsupported nfs://-URL "
131-
 #ifdef HAVE_RPCSVC_NFS_PROT_H
132+
+							"parameter '%s' value '%s'."),
132-
 #include <rpcsvc/nfs_prot.h>
133+
+							progname, pname, pvalue);
133-
@@ -521,29 +523,76 @@ nfsmount(const char *spec, const char *node, int flags,
134+
+						goto fail;
134-
 	time_t t;
135+
+					}
135-
 	time_t prevt;
136+
+				}
136-
 	time_t timeout;
137+
+				else {
137-
+	url_parser_context *uctx = NULL;
138+
+					nfs_error(_("%s: Unsupported nfs://-URL "
138-
139+
+							"parameter '%s'."),
139-
 	if (strlen(spec) >= sizeof(hostdir)) {
140+
+						progname, pname);
140-
 		nfs_error(_("%s: excessively long host:dir argument"),
141+
+					goto fail;
141-
 				progname);
142+
+				}
142-
 		goto fail;
143+
+			}
143-
 	}
144+
+		}
144-
-	strcpy(hostdir, spec);
145+
+        } else {
145-
-	if ((s = strchr(hostdir, ':'))) {
146+
+		(void)strcpy(hostdir, spec);
152147
+
153-
+	/*
148+
+		if (parse_devname(hostdir, &hostname, &dirname))
154-
+	 * Support nfs://-URLS per RFC 2224 ("NFS URL
149+
+			goto fail;
155-
+	 * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
150+
+	}
156-
+	 * including port support (nfs://hostname@port/path/...)
151+
157-
+	 */
152+
 	if (fill_ipv4_sockaddr(hostname, &server_addr))
158-
+	if (!strncmp(spec, "nfs://", 6)) {
153+
 		goto fail;
159-
+		dirname = NULL;
154+
@@ -247,7 +354,7 @@ int nfs4mount(const char *spec, const char *node, int flags,
160-
+
155+
 	/*
161-
+		uctx = url_parser_create_context(spec, 0);
156+
 	 * NFSv4 specifies that the default port should be 2049
162-
+	        if (!uctx) {
157+
 	 */
163-
+			nfs_error(_("%s: out of memory"),
158+
-	server_addr.sin_port = htons(NFS_PORT);
164-
+				progname);
159+
+	server_addr.sin_port = htons(nfs_port);
165-
+			goto fail;
160+
166-
+		}
161+
 	/* parse options */
162+
167171
+
168-
+		if (url_parser_parse(uctx) < 0) {
172+
 	return EX_SUCCESS;
169-
+			nfs_error(_("%s: Error parsing nfs://-URL."),
173+
170-
+				progname);
174+
 fail:
171-
+			goto fail;
175+
+	if (uctx) {
172-
+		}
176+
+		url_parser_free_context(uctx);
173-
+		if (uctx->login.username || uctx->login.passwd) {
177+
+		free(dirname);
174-
+			nfs_error(_("%s: Username/Password are not defined for nfs://-URL."),
178+
+	}
175-
+				progname);
179+
+
176-
+			goto fail;
180+
 	return retval;
177-
+		}
181+
 }
178-
+		if (!uctx->path) {
182+
diff --git a/utils/mount/nfsmount.c b/utils/mount/nfsmount.c
179-
+			nfs_error(_("%s: Path missing in nfs://-URL."),
183+
index a1c92fe8..1002e6e3 100644
180-
+				progname);
184+
--- a/utils/mount/nfsmount.c
181-
+			goto fail;
185+
+++ b/utils/mount/nfsmount.c
182-
+		}
186+
@@ -63,11 +63,13 @@
183-
+		if (uctx->path[0] != '/') {
187+
 #include "xcommon.h"
184-
+			nfs_error(_("%s: Relative nfs://-URLs are not supported."),
188+
 #include "mount.h"
185-
+				progname);
189+
 #include "nfs_mount.h"
186-
+			goto fail;
190+
+#include "urlparser1.h"
187-
+		}
191+
 #include "mount_constants.h"
188-
+
192+
 #include "nls.h"
189-
+		if (uctx->hostport.port != -1) {
193+
 #include "error.h"
190-
+// fixme
194+
 #include "network.h"
191-
+//			port = uctx->hostport.port;
195+
 #include "version.h"
192-
+		}
196+
+#include "utils.h"
193-
+
197+
194-
+		hostname = uctx->hostport.hostname;
198+
 #ifdef HAVE_RPCSVC_NFS_PROT_H
195-
+		dirname = utf8str2mbstr(uctx->path);
199+
 #include <rpcsvc/nfs_prot.h>
196-
+        } else {
200+
@@ -521,29 +523,133 @@ nfsmount(const char *spec, const char *node, int flags,
197-
+		strcpy(hostdir, spec);
201+
 	time_t t;
198-
+		if ((s = strchr(hostdir, ':'))) {
202+
 	time_t prevt;
199-
+			hostname = hostdir;
203+
 	time_t timeout;
200-
+			dirname = s + 1;
204+
+	url_parser_context *uctx = NULL;
201-
 			*s = '\0';
205+
+	int nfsurl_port = -1;
202-
-			nfs_error(_("%s: warning: "
206+
203-
-				  "multiple hostnames not supported"),
207+
 	if (strlen(spec) >= sizeof(hostdir)) {
204-
+			/* Ignore all but first hostname in replicated mounts
208+
 		nfs_error(_("%s: excessively long host:dir argument"),
210209
 					progname);
211-
-		}
210+
 		goto fail;
221211
 	}
222-
212+
-	strcpy(hostdir, spec);
223-
 	if (!nfs_gethostbyname(hostname, nfs_saddr))
213+
-	if ((s = strchr(hostdir, ':'))) {
224-
@@ -863,10 +912,19 @@ noauth_flavors:
214+
-		hostname = hostdir;
225-
 		}
215+
-		dirname = s + 1;
226-
 	}
216+
-		*s = '\0';
227-
217+
-		/* Ignore all but first hostname in replicated mounts
228-
+	if (uctx) {
218+
-		   until they can be fully supported. (mack@sgi.com) */
229-
+		free(dirname);
219+
-		if ((s = strchr(hostdir, ','))) {
232220
+
233-
 	return EX_SUCCESS;
221+
+	/*
234-
222+
+	 * Support nfs://-URLS per RFC 2224 ("NFS URL
235-
 	/* abort */
223+
+	 * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
236-
  fail:
224+
+	 * including port support (nfs://hostname@port/path/...)
237-
+	if (uctx) {
225+
+	 */
238-
+		free(dirname);
226+
+	if (!strncmp(spec, "nfs://", 6)) {
239-
+		url_parser_free_context(uctx);
227+
+		dirname = NULL;
240-
+	}
228+
+
241-
 	if (fsock != -1)
229+
+		uctx = url_parser_create_context(spec, 0);
242-
 		close(fsock);
230+
+	        if (!uctx) {
243-
 	return retval;
231+
+			nfs_error(_("%s: out of memory"),
244-
diff --git a/utils/mount/parse_dev.c b/utils/mount/parse_dev.c
232+
+				progname);
245-
index 2ade5d5d..2fe2cfc3 100644
233+
+			goto fail;
246-
--- a/utils/mount/parse_dev.c
234+
+		}
247-
+++ b/utils/mount/parse_dev.c
235+
+
248-
@@ -27,6 +27,8 @@
236+
+		if (url_parser_parse(uctx) < 0) {
249-
 #include "xcommon.h"
237+
+			nfs_error(_("%s: Error parsing nfs://-URL."),
250-
 #include "nls.h"
238+
+				progname);
251-
 #include "parse_dev.h"
239+
+			goto fail;
252-
+#include "urlparser1.h"
240+
+		}
253-
+#include "utils.h"
241+
+		if (uctx->login.username || uctx->login.passwd) {
254-
242+
+			nfs_error(_("%s: Username/Password are not defined for nfs://-URL."),
255-
 #ifndef NFS_MAXHOSTNAME
243+
+				progname);
256-
 #define NFS_MAXHOSTNAME		(255)
244+
+			goto fail;
257-
@@ -179,17 +181,85 @@ static int nfs_parse_square_bracket(const char *dev,
245+
+		}
258-
 }
246+
+		if (!uctx->path) {
259-
247+
+			nfs_error(_("%s: Path missing in nfs://-URL."),
260-
 /*
248+
+				progname);
261-
- * RFC 2224 says an NFS client must grok "public file handles" to
249+
+			goto fail;
262-
- * support NFS URLs.  Linux doesn't do that yet.  Print a somewhat
250+
+		}
263-
- * helpful error message in this case instead of pressing forward
251+
+		if (uctx->path[0] != '/') {
264-
- * with the mount request and failing with a cryptic error message
252+
+			nfs_error(_("%s: Relative nfs://-URLs are not supported."),
265-
- * later.
253+
+				progname);
266-
+ * Support nfs://-URLS per RFC 2224 ("NFS URL
254+
+			goto fail;
267-
+ * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
255+
+		}
268-
+ * including port support (nfs://hostname@port/path/...)
256+
+
269-
  */
257+
+		if (uctx->hostport.port != -1) {
270-
-static int nfs_parse_nfs_url(__attribute__((unused)) const char *dev,
258+
+			nfsurl_port = uctx->hostport.port;
271-
-			     __attribute__((unused)) char **hostname,
259+
+		}
279260
+
280-
+	if (out_hostname)
261+
+		hostname = uctx->hostport.hostname;
281-
+		*out_hostname = NULL;
262+
+		dirname = utf8str2mbstr(uctx->path);
284263
+
285-
+	/*
264+
+		(void)snprintf(hostdir, sizeof(hostdir), "%s:/%s",
286-
+	 * Support nfs://-URLS per RFC 2224 ("NFS URL
265+
+			hostname, dirname);
287-
+	 * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
266+
+		spec = hostdir;
290267
+
291-
+	uctx = url_parser_create_context(dev, 0);
268+
+		if (uctx->num_parameters > 0) {
292-
+	if (!uctx) {
269+
+			int pi;
293-
+		nfs_error(_("%s: out of memory"),
270+
+			const char *pname;
294-
+			progname);
271+
+			const char *pvalue;
297272
+
298-
+	if (url_parser_parse(uctx) < 0) {
273+
+			/*
299-
+		nfs_error(_("%s: Error parsing nfs://-URL."),
274+
+			 * Values added here based on URL parameters
300-
+			progname);
275+
+			 * should be added the front of the list of options,
301-
+		goto fail;
276+
+			 * so users can override the nfs://-URL given default.
302-
+	}
277+
+			 *
303-
+	if (uctx->login.username || uctx->login.passwd) {
278+
+			 * FIXME: We do not do that here for |MS_RDONLY|!
304-
+		nfs_error(_("%s: Username/Password are not defined for nfs://-URL."),
279+
+			 */
305-
+			progname);
280+
+			for (pi = 0; pi < uctx->num_parameters ; pi++) {
306-
+		goto fail;
281+
+				pname = uctx->parameters[pi].name;
307-
+	}
282+
+				pvalue = uctx->parameters[pi].value;
308-
+	if (!uctx->path) {
283+
+
309-
+		nfs_error(_("%s: Path missing in nfs://-URL."),
284+
+				if (!strcmp(pname, "rw")) {
310-
+			progname);
285+
+					if ((pvalue == NULL) || (!strcmp(pvalue, "1"))) {
311-
+		goto fail;
286+
+						flags &= ~MS_RDONLY;
312-
+	}
287+
+					}
313-
+	if (uctx->path[0] != '/') {
288+
+					else if (!strcmp(pvalue, "0")) {
314-
+		nfs_error(_("%s: Relative nfs://-URLs are not supported."),
289+
+						flags |= MS_RDONLY;
315-
+			progname);
290+
+					}
316-
+		goto fail;
291+
+					else {
317-
+	}
292+
+						nfs_error(_("%s: Unsupported nfs://-URL "
318-
+
293+
+							"parameter '%s' value '%s'."),
319-
+	if (uctx->hostport.port != -1) {
294+
+							progname, pname, pvalue);
320-
+		/* NOP here, unless we switch from hostname to hostport */
295+
+						goto fail;
321-
+	}
296+
+					}
322-
+
297+
+				}
323-
+	if (out_hostname)
298+
+				else if (!strcmp(pname, "ro")) {
324-
+		*out_hostname = strdup(uctx->hostport.hostname);
299+
+					if ((pvalue == NULL) || (!strcmp(pvalue, "1"))) {
325-
+	if (out_pathname)
300+
+						flags |= MS_RDONLY;
326-
+		*out_pathname = utf8str2mbstr(uctx->path);
301+
+					}
327-
+
302+
+					else if (!strcmp(pvalue, "0")) {
328-
+	if (((out_hostname)?(*out_hostname == NULL):0) ||
303+
+						flags &= ~MS_RDONLY;
329-
+		((out_pathname)?(*out_pathname == NULL):0)) {
304+
+					}
330-
+		nfs_error(_("%s: out of memory"),
305+
+					else {
331-
+			progname);
306+
+						nfs_error(_("%s: Unsupported nfs://-URL "
332-
+		goto fail;
307+
+							"parameter '%s' value '%s'."),
333-
+	}
308+
+							progname, pname, pvalue);
334-
+
309+
+						goto fail;
335-
+	url_parser_free_context(uctx);
310+
+					}
336-
+
311+
+				}
337-
+	return 1;
312+
+				else {
338-
+
313+
+					nfs_error(_("%s: Unsupported nfs://-URL "
339-
+fail:
314+
+							"parameter '%s'."),
340-
+	url_parser_free_context(uctx);
315+
+						progname, pname);
341-
+	if (out_hostname) {
316+
+					goto fail;
342-
+		free(*out_hostname);
317+
+				}
343-
+		*out_hostname = NULL;
318+
+			}
344-
+	}
319+
+		}
345-
+	if (out_pathname) {
320+
+        } else {
346-
+		free(*out_pathname);
321+
+		(void)strcpy(hostdir, spec);
347-
+		*out_pathname = NULL;
322+
+		if ((s = strchr(hostdir, ':'))) {
348-
+	}
323+
+			hostname = hostdir;
349-
 	return 0;
324+
+			dirname = s + 1;
350-
 }
325+
 			*s = '\0';
351-
326+
-			nfs_error(_("%s: warning: "
352-
diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
327+
-				  "multiple hostnames not supported"),
353-
index 2d5fa1f2..20dc0401 100644
328+
+			/* Ignore all but first hostname in replicated mounts
354-
--- a/utils/mount/stropts.c
329+
+			   until they can be fully supported. (mack@sgi.com) */
355-
+++ b/utils/mount/stropts.c
330+
+			if ((s = strchr(hostdir, ','))) {
356-
@@ -42,6 +42,7 @@
331+
+				*s = '\0';
357-
 #include "nls.h"
332+
+				nfs_error(_("%s: warning: "
358-
 #include "nfsrpc.h"
333+
+					"multiple hostnames not supported"),
359-
 #include "mount_constants.h"
334+
 					progname);
360-
+#include "urlparser1.h"
335+
-		}
361-
 #include "stropts.h"
336+
-	} else {
362-
 #include "error.h"
337+
-		nfs_error(_("%s: directory to mount not in host:dir format"),
363-
 #include "network.h"
338+
+			}
364-
@@ -50,6 +51,7 @@
339+
+		} else {
365-
 #include "parse_dev.h"
340+
+			nfs_error(_("%s: directory to mount not in host:dir format"),
366-
 #include "conffile.h"
341+
 				progname);
367-
 #include "misc.h"
342+
-		goto fail;
368-
+#include "utils.h"
343+
+			goto fail;
344+
+		}
369346
370-
 #ifndef NFS_PROGRAM
347+
 	if (!nfs_gethostbyname(hostname, nfs_saddr))
371-
 #define NFS_PROGRAM	(100003)
348+
@@ -579,6 +685,14 @@ nfsmount(const char *spec, const char *node, int flags,
372-
@@ -647,20 +649,177 @@ static int nfs_sys_mount(struct nfsmount_info *mi, struct mount_options *opts)
349+
 	memset(nfs_pmap, 0, sizeof(*nfs_pmap));
373-
 	if (mi->fake)
350+
 	nfs_pmap->pm_prog = NFS_PROGRAM;
375351
376-
-	if (po_join(opts, &options) == PO_FAILED) {
352+
+	if (nfsurl_port != -1) {
377-
-		errno = EIO;
353+
+		/*
378-
-		return 0;
354+
+		 * Set custom TCP port defined by a nfs://-URL here,
379-
-	}
355+
+		 * so $ mount -o port ... # can be used to override
380-
+	url_parser_context *uctx = NULL;
356+
+		 */
381-
+	int nfs_port = 2049;
357+
+		nfs_pmap->pm_port = nfsurl_port;
358+
+	}
382359
+
383-
+	/*
360+
 	/* parse options */
384-
+	 * Support nfs://-URLS per RFC 2224 ("NFS URL
361+
 	new_opts[0] = 0;
385-
+	 * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
362+
 	if (!parse_options(old_opts, &data, &bg, &retry, &mnt_server, &nfs_server,
386-
+	 * including port support (nfs://hostname@port/path/...)
363+
@@ -863,10 +977,19 @@ noauth_flavors:
387-
+	 */
364+
 		}
388-
+	if (!strncmp(mi->spec, "nfs://", 6)) {
365+
 	}
396366
397-
-	result = mount(mi->spec, mi->node, mi->type,
367+
+	if (uctx) {
398-
+		if (url_parser_parse(uctx) < 0) {
368+
+		free(dirname);
399-
+			nfs_error(_("%s: Error parsing nfs://-URL."),
369+
+		url_parser_free_context(uctx);
400-
+				progname);
370+
+	}
401-
+			result = 1;
371+
+
402-
+			goto done;
372+
 	return EX_SUCCESS;
403-
+		}
373+
404-
+		if (uctx->login.username || uctx->login.passwd) {
374+
 	/* abort */
405-
+			nfs_error(_("%s: Username/Password are not defined for nfs://-URL."),
375+
  fail:
406-
+				progname);
376+
+	if (uctx) {
407-
+			result = 1;
377+
+		free(dirname);
408-
+			goto done;
378+
+		url_parser_free_context(uctx);
409-
+		}
379+
+	}
410-
+		if (!uctx->path) {
380+
 	if (fsock != -1)
411-
+			nfs_error(_("%s: Path missing in nfs://-URL."),
381+
 		close(fsock);
412-
+				progname);
382+
 	return retval;
413-
+			result = 1;
383+
diff --git a/utils/mount/parse_dev.c b/utils/mount/parse_dev.c
414-
+			goto done;
384+
index 2ade5d5d..2fe2cfc3 100644
415-
+		}
385+
--- a/utils/mount/parse_dev.c
416-
+		if (uctx->path[0] != '/') {
386+
+++ b/utils/mount/parse_dev.c
417-
+			nfs_error(_("%s: Relative nfs://-URLs are not supported."),
387+
@@ -27,6 +27,8 @@
418-
+				progname);
388+
 #include "xcommon.h"
419-
+			result = 1;
389+
 #include "nls.h"
420-
+			goto done;
390+
 #include "parse_dev.h"
421-
+		}
391+
+#include "urlparser1.h"
422-
+
392+
+#include "utils.h"
423-
+		if (uctx->hostport.port != -1) {
393+
424-
+			nfs_port = uctx->hostport.port;
394+
 #ifndef NFS_MAXHOSTNAME
425-
+		}
395+
 #define NFS_MAXHOSTNAME		(255)
426-
+
396+
@@ -179,17 +181,85 @@ static int nfs_parse_square_bracket(const char *dev,
427-
+		char *mb_path;
397+
 }
428-
+		char mount_source[1024];
398+
429-
+
399+
 /*
430-
+		/*
400+
- * RFC 2224 says an NFS client must grok "public file handles" to
431-
+		 * |uctx->path| is in UTF-8, but we need the data in
401+
- * support NFS URLs.  Linux doesn't do that yet.  Print a somewhat
432-
+		 * the local locale, as mount(2) does not have a flag
402+
- * helpful error message in this case instead of pressing forward
433-
+		 * that the input path is in UTF-8
403+
- * with the mount request and failing with a cryptic error message
434-
+		 */
404+
- * later.
435-
+		mb_path = utf8str2mbstr(uctx->path);
405+
+ * Support nfs://-URLS per RFC 2224 ("NFS URL
436-
+		if (!mb_path) {
406+
+ * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
437-
+			nfs_error(_("%s: Could not convert path to local encoding."),
407+
+ * including port support (nfs://hostname@port/path/...)
438-
+				progname);
408+
  */
439-
+			result = 1;
409+
-static int nfs_parse_nfs_url(__attribute__((unused)) const char *dev,
440-
+			goto done;
410+
-			     __attribute__((unused)) char **hostname,
441-
+		}
411+
-			     __attribute__((unused)) char **pathname)
412+
+static int nfs_parse_nfs_url(const char *dev,
442418
+
443-
+		(void)snprintf(mount_source, sizeof(mount_source),
419+
+	if (out_hostname)
444-
+			"%s:/%s",
420+
+		*out_hostname = NULL;
445-
+			uctx->hostport.hostname,
421+
+	if (out_pathname)
446-
+			uctx->path);
422+
+		*out_pathname = NULL;
448423
+
449-
+		/*
424+
+	/*
450-
+		 * Insert "port=" option with the value from the nfs://
425+
+	 * Support nfs://-URLS per RFC 2224 ("NFS URL
451-
+		 * URL first, so users can override it with
426+
+	 * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
452-
+		 * $ mount.nfs4 -o port= #, e.g.
427+
+	 * including port support (nfs://hostname@port/path/...)
453-
+		 * $ mount.nfs4 -o port=1234 nfs://10.49.202.230:400//bigdisk /mnt4 #
428+
+	 */
460429
+
461-
+		if (uctx->num_parameters > 0) {
430+
+	uctx = url_parser_create_context(dev, 0);
462-
+			int pi;
431+
+	if (!uctx) {
463-
+			const char *pname;
432+
+		nfs_error(_("%s: out of memory"),
464-
+			const char *pvalue;
433+
+			progname);
434+
+		goto fail;
465436
+
466-
+			int rwro_already_set =
437+
+	if (url_parser_parse(uctx) < 0) {
467-
+				po_get(opts, "ro") || po_get(opts, "rw");
438+
+		nfs_error(_("%s: Error parsing nfs://-URL."),
468-
+
439+
+			progname);
469-
+			/*
440+
+		goto fail;
470-
+			 * Values added here based on URL parameters
441+
+	}
471-
+			 * should be added the front of the list of options,
442+
+	if (uctx->login.username || uctx->login.passwd) {
472-
+			 * so users can override the nfs://-URL given default.
443+
+		nfs_error(_("%s: Username/Password are not defined for nfs://-URL."),
473-
+			 */
444+
+			progname);
474-
+			for (pi = 0; pi < uctx->num_parameters ; pi++) {
445+
+		goto fail;
475-
+				pname = uctx->parameters[pi].name;
446+
+	}
476-
+				pvalue = uctx->parameters[pi].value;
447+
+	if (!uctx->path) {
448+
+		nfs_error(_("%s: Path missing in nfs://-URL."),
477457
+
478-
+				if (!strcmp(pname, "rw")) {
458+
+	if (uctx->hostport.port != -1) {
479-
+					if ((pvalue == NULL) || (!strcmp(pvalue, "1"))) {
459+
+		/* NOP here, unless we switch from hostname to hostport */
480-
+						if (!rwro_already_set)
460+
+	}
481-
+							mi->flags &= ~MS_RDONLY;
461+
+
482-
+					}
462+
+	if (out_hostname)
483-
+					else if (!strcmp(pvalue, "0")) {
463+
+		*out_hostname = strdup(uctx->hostport.hostname);
484-
+						if (!rwro_already_set)
464+
+	if (out_pathname)
485-
+							mi->flags |= MS_RDONLY;
465+
+		*out_pathname = utf8str2mbstr(uctx->path);
486-
+					}
466+
+
487-
+					else {
467+
+	if (((out_hostname)?(*out_hostname == NULL):0) ||
488-
+						nfs_error(_("%s: Unsupported nfs://-URL "
468+
+		((out_pathname)?(*out_pathname == NULL):0)) {
489-
+							"parameter '%s' value '%s'."),
469+
+		nfs_error(_("%s: out of memory"),
490-
+							progname, pname, pvalue);
470+
+			progname);
491-
+						result = 1;
471+
+		goto fail;
492-
+						goto done;
472+
+	}
493-
+					}
473+
+
494-
+				}
474+
+	url_parser_free_context(uctx);
495-
+				else if (!strcmp(pname, "ro")) {
475+
+
496-
+					if ((pvalue == NULL) || (!strcmp(pvalue, "1"))) {
476+
+	return 1;
497-
+						if (!rwro_already_set)
477+
+
498-
+							mi->flags |= MS_RDONLY;
478+
+fail:
499-
+					}
479+
+	url_parser_free_context(uctx);
500-
+					else if (!strcmp(pvalue, "0")) {
480+
+	if (out_hostname) {
501-
+						if (!rwro_already_set)
481+
+		free(*out_hostname);
502-
+							mi->flags &= ~MS_RDONLY;
482+
+		*out_hostname = NULL;
503-
+					}
483+
+	}
504-
+					else {
484+
+	if (out_pathname) {
505-
+						nfs_error(_("%s: Unsupported nfs://-URL "
485+
+		free(*out_pathname);
506-
+							"parameter '%s' value '%s'."),
486+
+		*out_pathname = NULL;
507-
+							progname, pname, pvalue);
487+
+	}
508-
+						result = 1;
488+
 	return 0;
509-
+						goto done;
489+
 }
510-
+					}
490+
511-
+				}
491+
diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
512-
+				else {
492+
index 2d5fa1f2..20dc0401 100644
513-
+					nfs_error(_("%s: Unsupported nfs://-URL "
493+
--- a/utils/mount/stropts.c
514-
+							"parameter '%s'."),
494+
+++ b/utils/mount/stropts.c
515-
+						progname, pname);
495+
@@ -42,6 +42,7 @@
516-
+					result = 1;
496+
 #include "nls.h"
517-
+					goto done;
497+
 #include "nfsrpc.h"
518-
+				}
498+
 #include "mount_constants.h"
519-
+			}
499+
+#include "urlparser1.h"
520-
+		}
500+
 #include "stropts.h"
521-
+
501+
 #include "error.h"
522-
+		if (po_join(opts, &options) == PO_FAILED) {
502+
 #include "network.h"
523-
+			errno = EIO;
503+
@@ -50,6 +51,7 @@
524-
+			result = 1;
504+
 #include "parse_dev.h"
525-
+			goto done;
505+
 #include "conffile.h"
526-
+		}
506+
 #include "misc.h"
527-
+
507+
+#include "utils.h"
528-
+		result = mount(mount_source, mi->node, mi->type,
508+
529-
 			mi->flags & ~(MS_USER|MS_USERS), options);
509+
 #ifndef NFS_PROGRAM
530-
-	free(options);
510+
 #define NFS_PROGRAM	(100003)
531-
+		free(options);
511+
@@ -647,20 +649,177 @@ static int nfs_sys_mount(struct nfsmount_info *mi, struct mount_options *opts)
532-
+	} else {
512+
 	if (mi->fake)
533-
+		if (po_join(opts, &options) == PO_FAILED) {
513+
 		return 1;
543514
544-
 	if (verbose && result) {
515+
-	if (po_join(opts, &options) == PO_FAILED) {
545-
 		int save = errno;
516+
-		errno = EIO;
546-
 		nfs_error(_("%s: mount(2): %s"), progname, strerror(save));
517+
-		return 0;
547-
 		errno = save;
518+
-	}
548-
 	}
519+
+	url_parser_context *uctx = NULL;
520+
+	int nfs_port = 2049;
549521
+
550-
+done:
522+
+	/*
551-
+	url_parser_free_context(uctx);
523+
+	 * Support nfs://-URLS per RFC 2224 ("NFS URL
552-
+
524+
+	 * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
553-
 	return !result;
525+
+	 * including port support (nfs://hostname@port/path/...)
554-
 }
526+
+	 */
527+
+	if (!strncmp(mi->spec, "nfs://", 6)) {
555535
556-
diff --git a/utils/mount/urlparser1.c b/utils/mount/urlparser1.c
536+
-	result = mount(mi->spec, mi->node, mi->type,
557-
new file mode 100644
537+
+		if (url_parser_parse(uctx) < 0) {
558-
index 00000000..572bc697
538+
+			nfs_error(_("%s: Error parsing nfs://-URL."),
559-
--- /dev/null
539+
+				progname);
560-
+++ b/utils/mount/urlparser1.c
540+
+			result = 1;
561-
@@ -0,0 +1,413 @@
541+
+			goto done;
562-
+/*
542+
+		}
563-
+ * MIT License
543+
+		if (uctx->login.username || uctx->login.passwd) {
564-
+ *
544+
+			nfs_error(_("%s: Username/Password are not defined for nfs://-URL."),
565-
+ * Copyright (c) 2024 Roland Mainz <roland.mainz@nrubsig.org>
545+
+				progname);
566-
+ *
546+
+			result = 1;
567-
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
547+
+			goto done;
568-
+ * of this software and associated documentation files (the "Software"), to deal
548+
+		}
569-
+ * in the Software without restriction, including without limitation the rights
549+
+		if (!uctx->path) {
570-
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
550+
+			nfs_error(_("%s: Path missing in nfs://-URL."),
571-
+ * copies of the Software, and to permit persons to whom the Software is
551+
+				progname);
572-
+ * furnished to do so, subject to the following conditions:
552+
+			result = 1;
573-
+ *
553+
+			goto done;
574-
+ * The above copyright notice and this permission notice shall be included in all
554+
+		}
575-
+ * copies or substantial portions of the Software.
555+
+		if (uctx->path[0] != '/') {
576-
+ *
556+
+			nfs_error(_("%s: Relative nfs://-URLs are not supported."),
577-
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
557+
+				progname);
578-
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
558+
+			result = 1;
579-
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
559+
+			goto done;
580-
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
560+
+		}
585561
+
586-
+/* urlparser1.c - simple URL parser */
562+
+		if (uctx->hostport.port != -1) {
563+
+			nfs_port = uctx->hostport.port;
587565
+
588-
+#if ((__STDC_VERSION__-0) < 201710L)
566+
+		char *mb_path;
589-
+#error Code requires ISO C17
567+
+		char mount_source[1024];
591568
+
592-
+#include <stdlib.h>
569+
+		/*
593-
+#include <stdbool.h>
570+
+		 * |uctx->path| is in UTF-8, but we need the data in
594-
+#include <string.h>
571+
+		 * the local locale, as mount(2) does not have a flag
595-
+#include <ctype.h>
572+
+		 * that the input path is in UTF-8
596-
+#include <stdio.h>
573+
+		 */
574+
+		mb_path = utf8str2mbstr(uctx->path);
597581
+
598-
+//#define TEST_URLPARSER 1
582+
+		(void)snprintf(mount_source, sizeof(mount_source),
583+
+			"%s:/%s",
599587
+
600-
+#include "urlparser1.h"
588+
+		/*
601-
+
589+
+		 * Insert "port=" option with the value from the nfs://
602-
+typedef struct _url_parser_context_private {
590+
+		 * URL first, so users can override it with
603-
+	url_parser_context c;
591+
+		 * $ mount.nfs4 -o port= #, e.g.
592+
+		 * $ mount.nfs4 -o port=1234 nfs://10.49.202.230:400//bigdisk /mnt4 #
604599
+
605-
+	/* Private data */
600+
+		if (uctx->num_parameters > 0) {
606-
+	char *parameter_string_buff;
601+
+			int pi;
607-
+} url_parser_context_private;
602+
+			const char *pname;
603+
+			const char *pvalue;
608604
+
609-
+#define MAX_URL_PARAMETERS 256
605+
+			int rwro_already_set =
606+
+				po_get(opts, "ro") || po_get(opts, "rw");
610607
+
611-
+#ifdef _MSC_VER
608+
+			/*
612-
+/*
609+
+			 * Values added here based on URL parameters
613-
+ * Disable "warning C4996: 'wcscpy': This function or variable may be
610+
+			 * should be added the front of the list of options,
614-
+ * unsafe." because in this case the buffers are properly sized,
611+
+			 * so users can override the nfs://-URL given default.
615-
+ * making this function safe
612+
+			 */
616-
+ */
613+
+			for (pi = 0; pi < uctx->num_parameters ; pi++) {
617-
+#pragma warning (disable : 4996)
614+
+				pname = uctx->parameters[pi].name;
618-
+/*
615+
+				pvalue = uctx->parameters[pi].value;
624616
+
625-
+/*
617+
+				if (!strcmp(pname, "rw")) {
626-
+ * Original extended regular expression:
618+
+					if ((pvalue == NULL) || (!strcmp(pvalue, "1"))) {
627-
+ *
619+
+						if (!rwro_already_set)
628-
+ * "^"
620+
+							mi->flags &= ~MS_RDONLY;
629-
+ * "(.+?)"				// scheme
621+
+					}
630-
+ * "://"				// '://'
622+
+					else if (!strcmp(pvalue, "0")) {
631-
+ * "("					// login
623+
+						if (!rwro_already_set)
632-
+ *	"(?:"
624+
+							mi->flags |= MS_RDONLY;
633-
+ *	"(.+?)"				// user (optional)
625+
+					}
634-
+ *		"(?::(.+))?"		// password (optional)
626+
+					else {
635-
+ *		"@"
627+
+						nfs_error(_("%s: Unsupported nfs://-URL "
636-
+ *	")?"
628+
+							"parameter '%s' value '%s'."),
637-
+ *	"("				// hostport
629+
+							progname, pname, pvalue);
638-
+ *		"(.+?)"			// host
630+
+						result = 1;
639-
+ *		"(?::([[:digit:]]+))?"	// port (optional)
631+
+						goto done;
640-
+ *	")"
632+
+					}
641-
+ * ")"
633+
+				}
642-
+ * "(?:/(.*?))?"			// path (optional)
634+
+				else if (!strcmp(pname, "ro")) {
643-
+ * "(?:\?(.*?))?"			// URL parameters (optional)
635+
+					if ((pvalue == NULL) || (!strcmp(pvalue, "1"))) {
644-
+ * "$"
636+
+						if (!rwro_already_set)
645-
+ */
637+
+							mi->flags |= MS_RDONLY;
646-
+
638+
+					}
647-
+#define DBGNULLSTR(s) (((s)!=NULL)?(s):"<NULL>")
639+
+					else if (!strcmp(pvalue, "0")) {
648-
+#if 0 || defined(TEST_URLPARSER)
640+
+						if (!rwro_already_set)
649-
+#define D(x) x
641+
+							mi->flags &= ~MS_RDONLY;
650-
+#else
642+
+					}
651-
+#define D(x)
643+
+					else {
652-
+#endif
644+
+						nfs_error(_("%s: Unsupported nfs://-URL "
653-
+
645+
+							"parameter '%s' value '%s'."),
654-
+static
646+
+							progname, pname, pvalue);
655-
+void urldecodestr(char *outbuff, const char *buffer, size_t len)
647+
+						result = 1;
656-
+{
648+
+						goto done;
657-
+	size_t i, j;
649+
+					}
658-
+
650+
+				}
659-
+	for (i = j = 0 ; i < len ; ) {
651+
+				else {
660-
+		switch (buffer[i]) {
652+
+					nfs_error(_("%s: Unsupported nfs://-URL "
661-
+			case '%':
653+
+							"parameter '%s'."),
662-
+				if ((i + 2) < len) {
654+
+						progname, pname);
663-
+					if (isxdigit((int)buffer[i+1]) && isxdigit((int)buffer[i+2])) {
655+
+					result = 1;
664-
+						const char hexstr[3] = {
656+
+					goto done;
665-
+							buffer[i+1],
657+
+				}
666-
+							buffer[i+2],
658+
+			}
667-
+							'\0'
659+
+		}
668-
+						};
660+
+
669-
+						outbuff[j++] = (unsigned char)strtol(hexstr, NULL, 16);
661+
+		if (po_join(opts, &options) == PO_FAILED) {
670-
+						i += 3;
662+
+			errno = EIO;
671-
+					} else {
663+
+			result = 1;
672-
+						/* invalid hex digit */
664+
+			goto done;
673-
+						outbuff[j++] = buffer[i];
665+
+		}
674-
+						i++;
666+
+
675-
+					}
667+
+		result = mount(mount_source, mi->node, mi->type,
676-
+				} else {
668+
 			mi->flags & ~(MS_USER|MS_USERS), options);
677-
+					/* incomplete hex digit */
669+
-	free(options);
678-
+					outbuff[j++] = buffer[i];
670+
+		free(options);
679-
+					i++;
671+
+	} else {
680-
+				}
672+
+		if (po_join(opts, &options) == PO_FAILED) {
681-
+				break;
673+
+			errno = EIO;
682-
+			case '+':
674+
+			result = 1;
683-
+				outbuff[j++] = ' ';
675+
+			goto done;
689676
+		}
691677
+
692-
+	outbuff[j] = '\0';
678+
+		result = mount(mi->spec, mi->node, mi->type,
693-
+}
679+
+			mi->flags & ~(MS_USER|MS_USERS), options);
680+
+		free(options);
694688
+
695-
+url_parser_context *url_parser_create_context(const char *in_url, unsigned int flags)
689+
+done:
696-
+{
690+
+	url_parser_free_context(uctx);
701691
+
702-
+	/* |flags| is for future extensions */
692+
 	return !result;
703-
+	(void)flags;
693+
 }
704-
+
694+
705-
+	if (!in_url)
695+
diff --git a/utils/mount/urlparser1.c b/utils/mount/urlparser1.c
706-
+		return NULL;
696+
new file mode 100644
707-
+
697+
index 00000000..572bc697
708-
+	in_url_len = strlen(in_url);
698+
--- /dev/null
709-
+
699+
+++ b/utils/mount/urlparser1.c
710-
+	context_len = sizeof(url_parser_context_private) +
700+
@@ -0,0 +1,413 @@
711-
+		((in_url_len+1)*6) +
701+
+/*
712-
+		(sizeof(url_parser_name_value)*MAX_URL_PARAMETERS)+sizeof(void*);
702+
+ * MIT License
713-
+	uctx = malloc(context_len);
703+
+ *
714-
+	if (!uctx)
704+
+ * Copyright (c) 2024 Roland Mainz <roland.mainz@nrubsig.org>
715-
+		return NULL;
705+
+ *
716-
+
706+
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
717-
+	s = (void *)(uctx+1);
707+
+ * of this software and associated documentation files (the "Software"), to deal
718-
+	uctx->c.in_url = s;		s+= in_url_len+1;
708+
+ * in the Software without restriction, including without limitation the rights
719-
+	(void)strcpy(uctx->c.in_url, in_url);
709+
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
720-
+	uctx->c.scheme = s;		s+= in_url_len+1;
710+
+ * copies of the Software, and to permit persons to whom the Software is
721-
+	uctx->c.login.username = s;	s+= in_url_len+1;
711+
+ * furnished to do so, subject to the following conditions:
722-
+	uctx->c.hostport.hostname = s;	s+= in_url_len+1;
712+
+ *
723-
+	uctx->c.path = s;		s+= in_url_len+1;
713+
+ * The above copyright notice and this permission notice shall be included in all
724-
+	uctx->c.hostport.port = -1;
714+
+ * copies or substantial portions of the Software.
725-
+	uctx->c.num_parameters = -1;
715+
+ *
726-
+	uctx->c.parameters = (void *)s;		s+= (sizeof(url_parser_name_value)*MAX_URL_PARAMETERS)+sizeof(void*);
716+
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
727-
+	uctx->parameter_string_buff = s;	s+= in_url_len+1;
717+
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
718+
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
728724
+
729-
+	return &uctx->c;
725+
+/* urlparser1.c - simple URL parser */
731726
+
732-
+int url_parser_parse(url_parser_context *ctx)
727+
+#if ((__STDC_VERSION__-0) < 201710L)
733-
+{
728+
+#error Code requires ISO C17
734-
+	url_parser_context_private *uctx = (url_parser_context_private *)ctx;
729+
+#endif
735730
+
736-
+	D((void)fprintf(stderr, "## parser in_url='%s'\n", uctx->c.in_url));
731+
+#include <stdlib.h>
732+
+#include <stdbool.h>
737736
+
738-
+	char *s;
737+
+//#define TEST_URLPARSER 1
741738
+
742-
+	s = strstr(urlstr, "://");
739+
+#include "urlparser1.h"
747740
+
748-
+	slen = s-urlstr;
741+
+typedef struct _url_parser_context_private {
749-
+	(void)memcpy(uctx->c.scheme, urlstr, slen);
742+
+	url_parser_context c;
752743
+
753-
+	D((void)fprintf(stdout, "scheme='%s', rest='%s'\n", uctx->c.scheme, urlstr));
744+
+	/* Private data */
745+
+	char *parameter_string_buff;
754747
+
755-
+	s = strstr(urlstr, "@");
748+
+#define MAX_URL_PARAMETERS 256
761749
+
762-
+		s = strstr(uctx->c.login.username, ":");
750+
+#ifdef _MSC_VER
763-
+		if (s) {
751+
+/*
764-
+			/* found passwd */
752+
+ * Disable "warning C4996: 'wcscpy': This function or variable may be
765-
+			uctx->c.login.passwd = s+1;
753+
+ * unsafe." because in this case the buffers are properly sized,
766-
+			*s = '\0';
754+
+ * making this function safe
767-
+		}
755+
+ */
768-
+		else
756+
+#pragma warning (disable : 4996)
769-
+		{
757+
+/*
770-
+			uctx->c.login.passwd = NULL;
758+
+ * Disable "warning C4706: assignment within conditional expression"
771-
+		}
759+
+ * because it is safe to use in our code.
760+
+ */
772763
+
773-
+		/* catch password-only URLs */
764+
+/*
774-
+		if (uctx->c.login.username[0] == '\0')
765+
+ * Original extended regular expression:
775-
+			uctx->c.login.username = NULL;
766+
+ *
776-
+	}
767+
+ * "^"
777-
+	else
768+
+ * "(.+?)"				// scheme
778-
+	{
769+
+ * "://"				// '://'
779-
+		uctx->c.login.username = NULL;
770+
+ * "("					// login
780-
+		uctx->c.login.passwd = NULL;
771+
+ *	"(?:"
781-
+	}
772+
+ *	"(.+?)"				// user (optional)
782-
+
773+
+ *		"(?::(.+))?"		// password (optional)
783-
+	D((void)fprintf(stdout, "login='%s', passwd='%s', rest='%s'\n",
774+
+ *		"@"
784-
+		DBGNULLSTR(uctx->c.login.username),
775+
+ *	")?"
785-
+		DBGNULLSTR(uctx->c.login.passwd),
776+
+ *	"("				// hostport
786-
+		DBGNULLSTR(urlstr)));
777+
+ *		"(.+?)"			// host
778+
+ *		"(?::([[:digit:]]+))?"	// port (optional)
787785
+
788-
+	char *raw_parameters;
786+
+#define DBGNULLSTR(s) (((s)!=NULL)?(s):"<NULL>")
787+
+#if 0 || defined(TEST_URLPARSER)
789792
+
790-
+	uctx->c.num_parameters = 0;
793+
+static
791-
+	raw_parameters = strstr(urlstr, "?");
794+
+void urldecodestr(char *outbuff, const char *buffer, size_t len)
792-
+	if (raw_parameters) {
795+
+{
793-
+		*raw_parameters++ = '\0';
796+
+	size_t i, j;
795797
+
796-
+		char *ps = raw_parameters;
798+
+	for (i = j = 0 ; i < len ; ) {
797-
+		char *pv; /* parameter value */
799+
+		switch (buffer[i]) {
798-
+		char *na; /* next '&' */
800+
+			case '%':
799-
+		char *pb = uctx->parameter_string_buff;
801+
+				if ((i + 2) < len) {
800-
+		char *pname;
802+
+					if (isxdigit((int)buffer[i+1]) && isxdigit((int)buffer[i+2])) {
801-
+		char *pvalue;
803+
+						const char hexstr[3] = {
802-
+		ssize_t pi;
804+
+							buffer[i+1],
803-
+
805+
+							buffer[i+2],
804-
+		for (pi = 0; pi < MAX_URL_PARAMETERS ; pi++) {
806+
+							'\0'
805-
+			pname = ps;
807+
+						};
806-
+
808+
+						outbuff[j++] = (unsigned char)strtol(hexstr, NULL, 16);
807-
+			/*
809+
+						i += 3;
808-
+			 * Handle parameters without value,
810+
+					} else {
809-
+			 * e.g. "path?name1&name2=value2"
811+
+						/* invalid hex digit */
810-
+			 */
812+
+						outbuff[j++] = buffer[i];
811-
+			na = strstr(ps, "&");
813+
+						i++;
812-
+			pv = strstr(ps, "=");
814+
+					}
813-
+			if (pv && (na?(na > pv):true)) {
815+
+				} else {
814-
+				*pv++ = '\0';
816+
+					/* incomplete hex digit */
815-
+				pvalue = pv;
817+
+					outbuff[j++] = buffer[i];
816-
+				ps = pv;
818+
+					i++;
817-
+			}
819+
+				}
818-
+			else {
820+
+				break;
819-
+				pvalue = NULL;
821+
+			case '+':
820-
+			}
822+
+				outbuff[j++] = ' ';
823+
+				i++;
821830
+
822-
+			if (na) {
831+
+	outbuff[j] = '\0';
823-
+				*na++ = '\0';
832+
+}
825833
+
826-
+			/* URLDecode parameter name */
834+
+url_parser_context *url_parser_create_context(const char *in_url, unsigned int flags)
827-
+			urldecodestr(pb, pname, strlen(pname));
835+
+{
828-
+			uctx->c.parameters[pi].name = pb;
836+
+	url_parser_context_private *uctx;
829-
+			pb += strlen(uctx->c.parameters[pi].name)+1;
837+
+	char *s;
838+
+	size_t in_url_len;
830840
+
831-
+			/* URLDecode parameter value */
841+
+	/* |flags| is for future extensions */
832-
+			if (pvalue) {
842+
+	(void)flags;
840843
+
841-
+			/* Next '&' ? */
844+
+	if (!in_url)
842-
+			if (!na)
845+
+		return NULL;
844846
+
845-
+			ps = na;
847+
+	in_url_len = strlen(in_url);
847848
+
848-
+		uctx->c.num_parameters = pi+1;
849+
+	context_len = sizeof(url_parser_context_private) +
849-
+	}
850+
+		((in_url_len+1)*6) +
851+
+		(sizeof(url_parser_name_value)*MAX_URL_PARAMETERS)+sizeof(void*);
850855
+
851-
+	s = strstr(urlstr, "/");
856+
+	s = (void *)(uctx+1);
852-
+	if (s) {
857+
+	uctx->c.in_url = s;		s+= in_url_len+1;
853-
+		/* URL has hostport */
858+
+	(void)strcpy(uctx->c.in_url, in_url);
854-
+		slen = s-urlstr;
859+
+	uctx->c.scheme = s;		s+= in_url_len+1;
855-
+		urldecodestr(uctx->c.hostport.hostname, urlstr, slen);
860+
+	uctx->c.login.username = s;	s+= in_url_len+1;
856-
+		urlstr += slen + 1;
861+
+	uctx->c.hostport.hostname = s;	s+= in_url_len+1;
862+
+	uctx->c.path = s;		s+= in_url_len+1;
857867
+
858-
+		/*
868+
+	return &uctx->c;
859-
+		 * check for addresses within '[' and ']', like
869+
+}
865870
+
866-
+		if (s == NULL) {
871+
+int url_parser_parse(url_parser_context *ctx)
867-
+			D((void)fprintf(stderr, "url_parser: Unmatched '[' in hostname\n"));
872+
+{
868-
+			return -1;
873+
+	url_parser_context_private *uctx = (url_parser_context_private *)ctx;
870874
+
871-
+		s = strstr(s, ":");
875+
+	D((void)fprintf(stderr, "## parser in_url='%s'\n", uctx->c.in_url));
872-
+		if (s) {
876+
+
873-
+			/* found port number */
877+
+	char *s;
874-
+			uctx->c.hostport.port = atoi(s+1);
878+
+	const char *urlstr = uctx->c.in_url;
875-
+			*s = '\0';
879+
+	size_t slen;
880+
+
877885
+	}

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