From 2c905fd1f8200349667dc990a17daf37214700bf Mon Sep 17 00:00:00 2001
From: Jonas Schnelli <jonas.schnelli@include7.ch>
Date: Thu, 24 Nov 2011 23:28:54 +0100
Subject: [PATCH] query-part: ignore the URI part for given protocols

By setting PROTOPT_NOURLQUERY in the protocol handler struct, the
protocol will get the "query part" of the URL cut off before the data is
handled by the protocol-specific code. This makes libcurl adhere to
RFC3986 section 2.2.

Test 1220 is added to verify a file:// URL with query-part.
---
 lib/dict.c             |  2 +-
 lib/file.c             |  2 +-
 lib/ftp.c              |  5 +++--
 lib/imap.c             |  6 ++++--
 lib/pop3.c             |  5 +++--
 lib/smtp.c             |  5 +++--
 lib/ssh.c              |  6 ++++--
 lib/telnet.c           |  2 +-
 lib/tftp.c             |  2 +-
 lib/url.c              | 19 +++++++++++++++++++
 lib/urldata.h          |  2 ++
 tests/data/Makefile.am |  1 +
 tests/data/test1220    | 30 ++++++++++++++++++++++++++++++
 13 files changed, 73 insertions(+), 14 deletions(-)
 create mode 100644 tests/data/test1220

diff --git a/lib/dict.c b/lib/dict.c
index b326054d1b..0fad32bfa5 100644
--- a/lib/dict.c
+++ b/lib/dict.c
@@ -98,7 +98,7 @@ const struct Curl_handler Curl_handler_dict = {
   ZERO_NULL,                            /* readwrite */
   PORT_DICT,                            /* defport */
   CURLPROTO_DICT,                       /* protocol */
-  PROTOPT_NONE                          /* flags */
+  PROTOPT_NONE | PROTOPT_NOURLQUERY      /* flags */
 };
 
 static char *unescape_word(struct SessionHandle *data, const char *inputbuff)
diff --git a/lib/file.c b/lib/file.c
index 9421c445b0..4447c73f68 100644
--- a/lib/file.c
+++ b/lib/file.c
@@ -119,7 +119,7 @@ const struct Curl_handler Curl_handler_file = {
   ZERO_NULL,                            /* readwrite */
   0,                                    /* defport */
   CURLPROTO_FILE,                       /* protocol */
-  PROTOPT_NONETWORK                     /* flags */
+  PROTOPT_NONETWORK | PROTOPT_NOURLQUERY /* flags */
 };
 
 
diff --git a/lib/ftp.c b/lib/ftp.c
index e5b1682fcb..05f6f450f8 100644
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -178,7 +178,8 @@ const struct Curl_handler Curl_handler_ftp = {
   ZERO_NULL,                       /* readwrite */
   PORT_FTP,                        /* defport */
   CURLPROTO_FTP,                   /* protocol */
-  PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD /* flags */
+  PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD
+  | PROTOPT_NOURLQUERY /* flags */
 };
 
 
@@ -205,7 +206,7 @@ const struct Curl_handler Curl_handler_ftps = {
   PORT_FTPS,                       /* defport */
   CURLPROTO_FTP | CURLPROTO_FTPS,  /* protocol */
   PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
-  PROTOPT_NEEDSPWD /* flags */
+  PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY /* flags */
 };
 #endif
 
diff --git a/lib/imap.c b/lib/imap.c
index ab53c9d74b..c98730cb59 100644
--- a/lib/imap.c
+++ b/lib/imap.c
@@ -125,7 +125,8 @@ const struct Curl_handler Curl_handler_imap = {
   ZERO_NULL,                        /* readwrite */
   PORT_IMAP,                        /* defport */
   CURLPROTO_IMAP,                   /* protocol */
-  PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD /* flags */
+  PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD
+  | PROTOPT_NOURLQUERY              /* flags */
 };
 
 
@@ -151,7 +152,8 @@ const struct Curl_handler Curl_handler_imaps = {
   ZERO_NULL,                        /* readwrite */
   PORT_IMAPS,                       /* defport */
   CURLPROTO_IMAP | CURLPROTO_IMAPS, /* protocol */
-  PROTOPT_CLOSEACTION | PROTOPT_SSL | PROTOPT_NEEDSPWD /* flags */
+  PROTOPT_CLOSEACTION | PROTOPT_SSL | PROTOPT_NEEDSPWD
+  | PROTOPT_NOURLQUERY              /* flags */
 };
 #endif
 
diff --git a/lib/pop3.c b/lib/pop3.c
index 6cda3bc5aa..8fd8ab01f5 100644
--- a/lib/pop3.c
+++ b/lib/pop3.c
@@ -125,7 +125,7 @@ const struct Curl_handler Curl_handler_pop3 = {
   ZERO_NULL,                        /* readwrite */
   PORT_POP3,                        /* defport */
   CURLPROTO_POP3,                   /* protocol */
-  PROTOPT_CLOSEACTION               /* flags */
+  PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */
 };
 
 
@@ -151,7 +151,8 @@ const struct Curl_handler Curl_handler_pop3s = {
   ZERO_NULL,                        /* readwrite */
   PORT_POP3S,                       /* defport */
   CURLPROTO_POP3 | CURLPROTO_POP3S, /* protocol */
-  PROTOPT_CLOSEACTION | PROTOPT_SSL /* flags */
+  PROTOPT_CLOSEACTION | PROTOPT_SSL
+  | PROTOPT_NOURLQUERY              /* flags */
 };
 #endif
 
diff --git a/lib/smtp.c b/lib/smtp.c
index ea6bafaf80..7512f1d0a4 100644
--- a/lib/smtp.c
+++ b/lib/smtp.c
@@ -133,7 +133,7 @@ const struct Curl_handler Curl_handler_smtp = {
   ZERO_NULL,                        /* readwrite */
   PORT_SMTP,                        /* defport */
   CURLPROTO_SMTP,                   /* protocol */
-  PROTOPT_CLOSEACTION               /* flags */
+  PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */
 };
 
 #ifdef USE_SSL
@@ -158,7 +158,8 @@ const struct Curl_handler Curl_handler_smtps = {
   ZERO_NULL,                        /* readwrite */
   PORT_SMTPS,                       /* defport */
   CURLPROTO_SMTP | CURLPROTO_SMTPS, /* protocol */
-  PROTOPT_CLOSEACTION | PROTOPT_SSL /* flags */
+  PROTOPT_CLOSEACTION | PROTOPT_SSL
+  | PROTOPT_NOURLQUERY              /* flags */
 };
 #endif
 
diff --git a/lib/ssh.c b/lib/ssh.c
index 410f397306..91aa440624 100644
--- a/lib/ssh.c
+++ b/lib/ssh.c
@@ -171,7 +171,8 @@ const struct Curl_handler Curl_handler_scp = {
   ZERO_NULL,                            /* readwrite */
   PORT_SSH,                             /* defport */
   CURLPROTO_SCP,                        /* protocol */
-  PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION /* flags */
+  PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
+  | PROTOPT_NOURLQUERY                  /* flags */
 };
 
 
@@ -196,7 +197,8 @@ const struct Curl_handler Curl_handler_sftp = {
   ZERO_NULL,                            /* readwrite */
   PORT_SSH,                             /* defport */
   CURLPROTO_SFTP,                       /* protocol */
-  PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION /* flags */
+  PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
+  | PROTOPT_NOURLQUERY                  /* flags */
 };
 
 
diff --git a/lib/telnet.c b/lib/telnet.c
index 59094b6740..bbad08de19 100644
--- a/lib/telnet.c
+++ b/lib/telnet.c
@@ -188,7 +188,7 @@ const struct Curl_handler Curl_handler_telnet = {
   ZERO_NULL,                            /* readwrite */
   PORT_TELNET,                          /* defport */
   CURLPROTO_TELNET,                     /* protocol */
-  PROTOPT_NONE                          /* flags */
+  PROTOPT_NONE | PROTOPT_NOURLQUERY     /* flags */
 };
 
 
diff --git a/lib/tftp.c b/lib/tftp.c
index 9b44a9b3df..370665a433 100644
--- a/lib/tftp.c
+++ b/lib/tftp.c
@@ -190,7 +190,7 @@ const struct Curl_handler Curl_handler_tftp = {
   ZERO_NULL,                            /* readwrite */
   PORT_TFTP,                            /* defport */
   CURLPROTO_TFTP,                       /* protocol */
-  PROTOPT_NONE                          /* flags */
+  PROTOPT_NONE | PROTOPT_NOURLQUERY     /* flags */
 };
 
 /**********************************************************
diff --git a/lib/url.c b/lib/url.c
index 517dc18da2..2c5cb39b84 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -4824,6 +4824,25 @@ static CURLcode create_conn(struct SessionHandle *data,
   if(result != CURLE_OK)
     return result;
 
+
+  /*************************************************************
+   * If the protocol can't handle url query strings, then cut
+   * of the unhandable part
+   *************************************************************/
+  if((conn->given->flags&PROTOPT_NOURLQUERY)) {
+    char *path_q_sep = strchr(conn->data->state.path, '?');
+    if(path_q_sep) {
+      /* according to rfc3986, allow the query (?foo=bar)
+         also on protocols that can't handle it.
+
+        cut the string-part after '?'
+         */
+
+      /* terminate the string */
+      path_q_sep[0] = 0;
+    }
+  }
+
 #ifndef CURL_DISABLE_PROXY
   /*************************************************************
    * Extract the user and password from the authentication string
diff --git a/lib/urldata.h b/lib/urldata.h
index 3e7db2525c..55f0a7b851 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -713,6 +713,8 @@ struct Curl_handler {
 #define PROTOPT_NONETWORK (1<<4)   /* protocol doesn't use the network! */
 #define PROTOPT_NEEDSPWD (1<<5)    /* needs a password, and if none is set it
                                       gets a default */
+#define PROTOPT_NOURLQUERY (1<<6)   /* protocol can't handle
+                                        url query strings (?foo=bar) ! */
 
 
 /* return the count of bytes sent, or -1 on error */
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index c52ef243c6..2d86aa12c8 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -78,6 +78,7 @@ test1118 test1119 test1120 test1121 test1122 test1123 test1124 test1125	\
 test1126 test1127 test1128 test1129 test1130 test1131 \
 test1200 test1201 test1202 test1203 test1204 test1205 test1206 test1207 \
 test1208 test1209 test1210 \
+test1220 \
 test1300 test1301 test1302 test1303 test1304 test1305	\
 test1306 test1307 test1308 test1309 test1310 test1311 test1312 test1313 \
 test1314 \
diff --git a/tests/data/test1220 b/tests/data/test1220
new file mode 100644
index 0000000000..d365249601
--- /dev/null
+++ b/tests/data/test1220
@@ -0,0 +1,30 @@
+<testcase>
+# Server-side
+<reply>
+<data>
+</data>
+</reply>
+
+# Client-side
+<client>
+<server>
+file
+</server>
+ <name>
+file:// URLs with query string
+ </name>
+ <command>
+file://localhost/%PWD/log/test1220.txt?a_query=foobar#afragment
+</command>
+<file name="log/test1220.txt">
+contents in a single file
+</file>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<stdout>
+contents in a single file
+</stdout>
+</verify>
+</testcase>
-- 
GitLab