]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
CURLOPT_PREREQFUNCTION: add new callback
authorMax Dymond <max.dymond@microsoft.com>
Thu, 22 Jul 2021 14:32:30 +0000 (15:32 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Mon, 27 Sep 2021 15:16:43 +0000 (17:16 +0200)
Triggered before a request is made but after a connection is set up

Changes:

- callback: Update docs and callback for pre-request callback
- Add documentation for CURLOPT_PREREQDATA and CURLOPT_PREREQFUNCTION,
- Add redirect test and callback failure test
- Note that the function may be called multiple times on a redirection
- Disable new 2086 test due to Windows weirdness

Closes #7477

21 files changed:
docs/libcurl/curl_easy_setopt.3
docs/libcurl/opts/CURLOPT_PREREQDATA.3 [new file with mode: 0644]
docs/libcurl/opts/CURLOPT_PREREQFUNCTION.3 [new file with mode: 0644]
docs/libcurl/opts/Makefile.inc
docs/libcurl/symbols-in-versions
include/curl/curl.h
lib/easyoptions.c
lib/multi.c
lib/setopt.c
lib/urldata.h
tests/data/DISABLED
tests/data/Makefile.inc
tests/data/test2082 [new file with mode: 0644]
tests/data/test2083 [new file with mode: 0644]
tests/data/test2084 [new file with mode: 0644]
tests/data/test2085 [new file with mode: 0644]
tests/data/test2086 [new file with mode: 0644]
tests/libtest/.gitignore
tests/libtest/Makefile.inc
tests/libtest/libprereq.c [new file with mode: 0644]
tests/libtest/mk-lib1521.pl

index 592692b94936ad439e0e0dcc4c940ab85fb8c850..b1abf43e381a7489159b66dc7c701be334951217 100644 (file)
@@ -144,6 +144,10 @@ Suppress proxy CONNECT response headers from user callbacks. See \fICURLOPT_SUPP
 Callback to be called before a new resolve request is started. See \fICURLOPT_RESOLVER_START_FUNCTION(3)\fP
 .IP CURLOPT_RESOLVER_START_DATA
 Data pointer to pass to resolver start callback. See \fICURLOPT_RESOLVER_START_DATA(3)\fP
+.IP CURLOPT_PREREQFUNCTION
+Callback to be called after a connection is established but before a request is made on that connection. See \fICURLOPT_PREREQFUNCTION(3)\fP
+.IP CURLOPT_PREREQDATA
+Data pointer to pass to the CURLOPT_PREREQFUNCTION callback. See \fICURLOPT_PREREQDATA(3)\fP
 .SH ERROR OPTIONS
 .IP CURLOPT_ERRORBUFFER
 Error message buffer. See \fICURLOPT_ERRORBUFFER(3)\fP
diff --git a/docs/libcurl/opts/CURLOPT_PREREQDATA.3 b/docs/libcurl/opts/CURLOPT_PREREQDATA.3
new file mode 100644 (file)
index 0000000..07497a8
--- /dev/null
@@ -0,0 +1,61 @@
+.\" **************************************************************************
+.\" *                                  _   _ ____  _
+.\" *  Project                     ___| | | |  _ \| |
+.\" *                             / __| | | | |_) | |
+.\" *                            | (__| |_| |  _ <| |___
+.\" *                             \___|\___/|_| \_\_____|
+.\" *
+.\" * Copyright (C) 2021, Max Dymond, <max.dymond@microsoft.com>, et al.
+.\" *
+.\" * This software is licensed as described in the file COPYING, which
+.\" * you should have received as part of this distribution. The terms
+.\" * are also available at https://curl.se/docs/copyright.html.
+.\" *
+.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+.\" * copies of the Software, and permit persons to whom the Software is
+.\" * furnished to do so, under the terms of the COPYING file.
+.\" *
+.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+.\" * KIND, either express or implied.
+.\" *
+.\" **************************************************************************
+.\"
+.TH CURLOPT_PREREQDATA 3 "2 Aug 2021" "libcurl 7.80.0" "curl_easy_setopt options"
+.SH NAME
+CURLOPT_PREREQDATA \- custom pointer passed to the pre-request callback
+.SH SYNOPSIS
+#include <curl/curl.h>
+
+CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PREREQDATA, void *pointer);
+.SH DESCRIPTION
+Pass a \fIpointer\fP that will be untouched by libcurl and passed as the first
+argument in the pre-request callback set with
+\fICURLOPT_PREREQFUNCTION(3)\fP.
+.SH DEFAULT
+NULL
+.SH PROTOCOLS
+All
+.SH EXAMPLE
+.nf
+static int prereq_callback(void *clientp,
+                           char *conn_primary_ip,
+                           char *conn_local_ip,
+                           int conn_primary_port,
+                           int conn_local_port)
+{
+  printf("Connection made to %s:%s\n", conn_primary_ip, conn_primary_port);
+  return CURL_PREREQFUNC_OK;
+}
+
+{
+  struct data prereq_data;
+  curl_easy_setopt(CURL *handle, CURLOPT_PREREQFUNCTION, prereq_callback);
+  curl_easy_setopt(CURL *handle, CURLOPT_PREREQDATA, &prereq_data);
+}
+.fi
+.SH AVAILABILITY
+Added in 7.80.0
+.SH RETURN VALUE
+Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
+.SH "SEE ALSO"
+.BR CURLOPT_PREREQFUNCTION "(3) "
diff --git a/docs/libcurl/opts/CURLOPT_PREREQFUNCTION.3 b/docs/libcurl/opts/CURLOPT_PREREQFUNCTION.3
new file mode 100644 (file)
index 0000000..dcc782f
--- /dev/null
@@ -0,0 +1,104 @@
+.\" **************************************************************************
+.\" *                                  _   _ ____  _
+.\" *  Project                     ___| | | |  _ \| |
+.\" *                             / __| | | | |_) | |
+.\" *                            | (__| |_| |  _ <| |___
+.\" *                             \___|\___/|_| \_\_____|
+.\" *
+.\" * Copyright (C) 2021, Max Dymond, <max.dymond@microsoft.com>, et al.
+.\" *
+.\" * This software is licensed as described in the file COPYING, which
+.\" * you should have received as part of this distribution. The terms
+.\" * are also available at https://curl.se/docs/copyright.html.
+.\" *
+.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+.\" * copies of the Software, and permit persons to whom the Software is
+.\" * furnished to do so, under the terms of the COPYING file.
+.\" *
+.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+.\" * KIND, either express or implied.
+.\" *
+.\" **************************************************************************
+.\"
+.TH CURLOPT_PREREQFUNCTION 3 "2 Aug 2021" "libcurl 7.80.0" "curl_easy_setopt options"
+.SH NAME
+CURLOPT_PREREQFUNCTION \- user callback called when a connection has been
+established, but before a request has been made.
+.SH SYNOPSIS
+.nf
+#include <curl/curl.h>
+
+/* These are the return codes for the pre-request callback. */
+#define CURL_PREREQFUNC_OK 0
+#define CURL_PREREQFUNC_ABORT 1 /* fail the entire transfer */
+
+int prereq_callback(void *clientp,
+                    char *conn_primary_ip,
+                    char *conn_local_ip,
+                    int conn_primary_port,
+                    int conn_local_port);
+
+CURLcode curl_easy_setopt(CURL *handle, CURLOPT_PREREQFUNCTION, prereq_callback);
+.SH DESCRIPTION
+Pass a pointer to your callback function, which should match the prototype
+shown above.
+
+This function gets called by libcurl after a connection has been established
+or a connection has been reused (including any SSL handshaking), but before any
+request is actually made on the connection. For example, for HTTP, this
+callback is called once a connection has been established to the server, but
+before a GET/HEAD/POST/etc request has been sent.
+
+This function may be called multiple times if redirections are enabled and are
+being followed (see \fICURLOPT_FOLLOWLOCATION(3)\fP).
+
+This function is passed the following information:
+.IP conn_primary_ip
+A nul-terminated pointer to a C string containing the primary IP of the remote
+server established with this connection. For FTP, this is the IP for the control
+connection. IPv6 addresses are represented without surrounding brackets.
+.IP conn_local_ip
+A nul-terminated pointer to a C string containing the originating IP for this
+connection. IPv6 addresses are represented without surrounding brackets.
+.IP conn_primary_port
+The primary port number on the remote server established with this connection.
+For FTP, this is the port for the control connection. This can be a TCP or a
+UDP port number dependending on the protocol.
+.IP conn_local_port
+The originating port number for this connection. This can be a TCP or a UDP port
+number dependending on the protocol.
+.RE
+
+\fIclientp\fP is the pointer you set with \fICURLOPT_PREREQDATA(3)\fP.
+
+The callback function must return \fICURL_PREREQFUNC_OK\fP on success, or
+\fICURL_PREREQFUNC_ABORT\fP to cause the transfer to fail.
+
+.SH DEFAULT
+By default, this is NULL and unused.
+.SH PROTOCOLS
+ALL
+.SH EXAMPLE
+.nf
+static int prereq_callback(void *clientp,
+                           char *conn_primary_ip,
+                           char *conn_local_ip,
+                           int conn_primary_port,
+                           int conn_local_port)
+{
+  printf("Connection made to %s:%s\n", conn_primary_ip, conn_primary_port);
+  return CURL_PREREQFUNC_OK;
+}
+
+{
+  struct data prereq_data;
+  curl_easy_setopt(CURL *handle, CURLOPT_PREREQFUNCTION, prereq_callback);
+  curl_easy_setopt(CURL *handle, CURLOPT_PREREQDATA, &prereq_data);
+}
+.fi
+.SH AVAILABILITY
+Added in 7.80.0
+.SH RETURN VALUE
+Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
+.SH "SEE ALSO"
+.BR CURLOPT_PREREQDATA "(3) "
index 4ef5ddf4323337bf0b7ae35e014b3db8ed4c742e..7bac21024d4547a2dc8a5acdcf48f4230e1c2c3d 100644 (file)
@@ -254,6 +254,8 @@ man_MANS =                                      \
   CURLOPT_POSTQUOTE.3                           \
   CURLOPT_POSTREDIR.3                           \
   CURLOPT_PREQUOTE.3                            \
+  CURLOPT_PREREQDATA.3                          \
+  CURLOPT_PREREQFUNCTION.3                      \
   CURLOPT_PRE_PROXY.3                           \
   CURLOPT_PRIVATE.3                             \
   CURLOPT_PROGRESSDATA.3                        \
index 8be22d504787d68d5b7d6555ec8a0d23a429e1f4..1dbcdbd3e67e6e8c43e699bcbea17cd8675ea553 100644 (file)
@@ -531,6 +531,8 @@ CURLOPT_POSTFIELDSIZE_LARGE     7.11.1
 CURLOPT_POSTQUOTE               7.1
 CURLOPT_POSTREDIR               7.19.1
 CURLOPT_PREQUOTE                7.9.5
+CURLOPT_PREREQDATA              7.80.0
+CURLOPT_PREREQFUNCTION          7.80.0
 CURLOPT_PRE_PROXY               7.52.0
 CURLOPT_PRIVATE                 7.10.3
 CURLOPT_PROGRESSDATA            7.1
@@ -964,6 +966,8 @@ CURL_POLL_INOUT                 7.14.0
 CURL_POLL_NONE                  7.14.0
 CURL_POLL_OUT                   7.14.0
 CURL_POLL_REMOVE                7.14.0
+CURL_PREREQFUNC_ABORT           7.79.0
+CURL_PREREQFUNC_OK              7.79.0
 CURL_PROGRESSFUNC_CONTINUE      7.68.0
 CURL_PROGRESS_BAR               7.1.1         -           7.4.1
 CURL_PROGRESS_STATS             7.1.1         -           7.4.1
index 6eb0fcb826ed8232463291b235205878c8dc76b5..d0862afaf35c2f345eeae8e5080eebd0c35a26c6 100644 (file)
@@ -470,6 +470,20 @@ typedef int (*curl_debug_callback)
         size_t size,       /* size of the data pointed to */
         void *userptr);    /* whatever the user please */
 
+/* This is the CURLOPT_PREREQFUNCTION callback prototype. */
+typedef int (*curl_prereq_callback)(void *clientp,
+                                    char *conn_primary_ip,
+                                    char *conn_local_ip,
+                                    int conn_primary_port,
+                                    int conn_local_port);
+
+/* Return code for when the pre-request callback has terminated without
+   any errors */
+#define CURL_PREREQFUNC_OK 0
+/* Return code for when the pre-request callback wants to abort the
+   request */
+#define CURL_PREREQFUNC_ABORT 1
+
 /* All possible error codes from all sorts of curl functions. Future versions
    may return other values, stay prepared.
 
@@ -2105,6 +2119,13 @@ typedef enum {
   /* used by scp/sftp to verify the host's public key */
   CURLOPT(CURLOPT_SSH_HOST_PUBLIC_KEY_SHA256, CURLOPTTYPE_STRINGPOINT, 311),
 
+  /* Function that will be called immediately before the initial request
+     is made on a connection (after any protocol negotiation step).  */
+  CURLOPT(CURLOPT_PREREQFUNCTION, CURLOPTTYPE_FUNCTIONPOINT, 312),
+
+  /* Data passed to the CURLOPT_PREREQFUNCTION callback */
+  CURLOPT(CURLOPT_PREREQDATA, CURLOPTTYPE_CBPOINT, 313),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
index b1c0704d5eb37bd92a5ba74c05743dd069a4fcd6..717b081a370ada936a0a292f6c3255eb366bdbcf 100644 (file)
@@ -356,6 +356,6 @@ struct curl_easyoption Curl_easyopts[] = {
  */
 int Curl_easyopts_check(void)
 {
-  return ((CURLOPT_LASTENTRY%10000) != (311 + 1));
+  return ((CURLOPT_LASTENTRY%10000) != (313 + 1));
 }
 #endif
index 68c1a64d5feb117aa3680558dfc60c20ff97b545..f31b252625400e7faab5cb2d33363ab17b4eed1c 100644 (file)
@@ -2028,6 +2028,28 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
       break;
 
     case MSTATE_DO:
+      if(data->set.fprereq) {
+        int prereq_rc;
+
+        /* call the prerequest callback function */
+        Curl_set_in_callback(data, true);
+        prereq_rc = data->set.fprereq(data->set.prereq_userp,
+                                      data->info.conn_primary_ip,
+                                      data->info.conn_local_ip,
+                                      data->info.conn_primary_port,
+                                      data->info.conn_local_port);
+        Curl_set_in_callback(data, false);
+        if(prereq_rc != CURL_PREREQFUNC_OK) {
+          failf(data, "operation aborted by pre-request callback");
+          /* failure in pre-request callback - don't do any other processing */
+          result = CURLE_ABORTED_BY_CALLBACK;
+          Curl_posttransfer(data);
+          multi_done(data, result, FALSE);
+          stream_error = TRUE;
+          break;
+        }
+      }
+
       if(data->set.connect_only) {
         /* keep connection open for application to use the socket */
         connkeep(data->conn, "CONNECT_ONLY");
index c62a62fb5ecf560fbc17ce2bf4e97843319c270f..8e19389ae1ae656a4e6e86eb54932f07cefb72d5 100644 (file)
@@ -3013,6 +3013,12 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
       return result;
     break;
 #endif
+  case CURLOPT_PREREQFUNCTION:
+    data->set.fprereq = va_arg(param, curl_prereq_callback);
+    break;
+  case CURLOPT_PREREQDATA:
+    data->set.prereq_userp = va_arg(param, void *);
+    break;
   default:
     /* unknown tag and its companion, just ignore: */
     result = CURLE_UNKNOWN_OPTION;
index 2d1e873a582cd3ac9a4ffe48f6eb47901788d310..47cb9e282642b8afe7865f65ed94ed1fc6c963d8 100644 (file)
@@ -1652,6 +1652,8 @@ struct UserDefined {
   curl_closesocket_callback fclosesocket; /* function for closing the
                                              socket */
   void *closesocket_client;
+  curl_prereq_callback fprereq; /* pre-initial request callback */
+  void *prereq_userp; /* pre-initial request user data */
 
   void *seek_client;    /* pointer to pass to the seek callback */
   /* the 3 curl_conv_callback functions below are used on non-ASCII hosts */
index 6807fe23deafe57fd7f894630a12143655b78988..aa0fee3967220523592155ad4fedfd18ed5f4046 100644 (file)
@@ -29,6 +29,8 @@
 # test 1801 causes problems on Mac OS X and github
 # https://github.com/curl/curl/issues/380
 1801
+# test 2086 causes issues on Windows only
+2086
 #
 #
 # Tests that are disabled here for Hyper are SUPPOSED to work but
index d906ca3382ed7a733d8cdc36cc1b466d8cde4b0a..41249fdadcceb3624b2d5a0c3586b98e3af12bde 100644 (file)
@@ -229,7 +229,7 @@ test2064 test2065 test2066 test2067 test2068 test2069 \
 test2064 test2065 test2066 test2067 test2068 test2069 test2070 \
          test2071 test2072 test2073 test2074 test2075 test2076 test2077 \
 test2078 \
-test2080 test2081 \
+test2080 test2081 test2082 test2083 test2084 test2085 test2086 \
 \
 test2100 \
 \
diff --git a/tests/data/test2082 b/tests/data/test2082
new file mode 100644 (file)
index 0000000..4c37772
--- /dev/null
@@ -0,0 +1,51 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+</keywords>
+</info>
+
+# Server-side
+<reply>
+<data nocheck="yes">
+HTTP/1.1 200 OK
+Date: Tue, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Content-Type: text/html
+Content-Length: 0
+
+</data>
+</reply>
+
+# Client-side
+<client>
+<server>
+http
+</server>
+
+<name>
+Pre-request callback for HTTP
+</name>
+<tool>
+libprereq
+</tool>
+
+<command>
+%HOSTIP:%HTTPPORT/%TESTNUMBER
+</command>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<stripfile>
+s/^Local port = \d+/Local port = stripped/
+</stripfile>
+<stdout>
+Connected to %HOSTIP
+Connected from %CLIENTIP
+Remote port = %HTTPPORT
+Local port = stripped
+Returning = 0
+</stdout>
+</verify>
+</testcase>
diff --git a/tests/data/test2083 b/tests/data/test2083
new file mode 100644 (file)
index 0000000..9256151
--- /dev/null
@@ -0,0 +1,45 @@
+<testcase>
+<info>
+<keywords>
+FTP
+</keywords>
+</info>
+
+# Server-side
+<reply>
+<data>
+</data>
+</reply>
+
+# Client-side
+<client>
+<server>
+ftp
+</server>
+
+<name>
+Pre-request callback for FTP
+</name>
+<tool>
+libprereq
+</tool>
+
+<command>
+ftp://%HOSTIP:%FTPPORT/test-%TESTNUMBER/
+</command>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<stripfile>
+s/^Local port = \d+/Local port = stripped/
+</stripfile>
+<stdout>
+Connected to %HOSTIP
+Connected from %CLIENTIP
+Remote port = %FTPPORT
+Local port = stripped
+Returning = 0
+</stdout>
+</verify>
+</testcase>
diff --git a/tests/data/test2084 b/tests/data/test2084
new file mode 100644 (file)
index 0000000..ced7086
--- /dev/null
@@ -0,0 +1,54 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+</keywords>
+</info>
+
+# Server-side
+<reply>
+<data nocheck="yes">
+HTTP/1.1 200 OK
+Date: Tue, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Content-Type: text/html
+Content-Length: 0
+
+</data>
+</reply>
+
+# Client-side
+<client>
+<server>
+http
+</server>
+
+<name>
+Pre-request callback for HTTP with callback terminating transfer
+</name>
+<tool>
+libprereq
+</tool>
+
+<command>
+%HOSTIP:%HTTPPORT/%TESTNUMBER#err
+</command>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<errorcode>
+42
+</errorcode>
+<stripfile>
+s/^Local port = \d+/Local port = stripped/
+</stripfile>
+<stdout>
+Connected to %HOSTIP
+Connected from %CLIENTIP
+Remote port = %HTTPPORT
+Local port = stripped
+Returning = 1
+</stdout>
+</verify>
+</testcase>
diff --git a/tests/data/test2085 b/tests/data/test2085
new file mode 100644 (file)
index 0000000..665a756
--- /dev/null
@@ -0,0 +1,64 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+followlocation
+</keywords>
+</info>
+
+# Server-side
+<reply>
+<data nocheck="yes">
+HTTP/1.1 302 OK swsclose
+Location: data2.html/%TESTNUMBER0002
+Date: Tue, 09 Nov 2010 14:49:00 GMT
+Connection: close
+
+</data>
+<data2 nocheck="yes">
+HTTP/1.1 200 OK swsclose
+Location: this should be ignored
+Date: Tue, 09 Nov 2010 14:49:00 GMT
+Connection: close
+
+body
+</data2>
+</reply>
+
+# Client-side
+<client>
+<server>
+http
+</server>
+
+<name>
+Pre-request callback for HTTP with location following
+</name>
+<tool>
+libprereq
+</tool>
+
+<command>
+%HOSTIP:%HTTPPORT/%TESTNUMBER#redir
+</command>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<stripfile>
+s/^Local port = \d+/Local port = stripped/
+</stripfile>
+<stdout>
+Connected to %HOSTIP
+Connected from %CLIENTIP
+Remote port = %HTTPPORT
+Local port = stripped
+Returning = 0
+Connected to %HOSTIP
+Connected from %CLIENTIP
+Remote port = %HTTPPORT
+Local port = stripped
+Returning = 0
+</stdout>
+</verify>
+</testcase>
diff --git a/tests/data/test2086 b/tests/data/test2086
new file mode 100644 (file)
index 0000000..ce60aa8
--- /dev/null
@@ -0,0 +1,52 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+IPv6
+</keywords>
+</info>
+
+# Server-side
+<reply>
+<data nocheck="yes">
+HTTP/1.1 200 OK
+Date: Tue, 09 Nov 2010 14:49:00 GMT
+Server: test-server/fake
+Content-Type: text/html
+Content-Length: 0
+
+</data>
+</reply>
+
+# Client-side
+<client>
+<server>
+http-ipv6
+</server>
+
+<name>
+Pre-request callback for HTTP IPv6
+</name>
+<tool>
+libprereq
+</tool>
+
+<command>
+%HOST6IP:%HTTP6PORT/%TESTNUMBER#ipv6
+</command>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<stripfile>
+s/^Local port = \d+/Local port = stripped/
+</stripfile>
+<stdout>
+Connected to %HOST6IP
+Connected from %CLIENT6IP
+Remote port = %HTTP6PORT
+Local port = stripped
+Returning = 0
+</stdout>
+</verify>
+</testcase>
index 62d9176d56a2ee08581b0b18f48fbff876da9188..f27ba8128d3606a78eae26536a7fd217f7a5c72e 100644 (file)
@@ -5,3 +5,4 @@ lib[56][0-9][0-9]
 lib1521.c
 libauthretry
 libntlmconnect
+libprereq
index c2d0a6e8e6d70b3ec9599bcd9472c1a6f0edc78f..0f70ceb4bd014bd776250f5c03ac1f1f32e0c789 100644 (file)
@@ -36,7 +36,7 @@ SUPPORTFILES = first.c test.h
 
 # These are all libcurl test programs
 noinst_PROGRAMS = chkhostname libauthretry libntlmconnect                \
- chkdecimalpoint                                                         \
+ chkdecimalpoint libprereq                                               \
  lib500 lib501 lib502 lib503 lib504 lib505 lib506 lib507 lib508 lib509   \
  lib510 lib511 lib512 lib513 lib514 lib515 lib516 lib517 lib518 lib519   \
  lib520 lib521 lib523 lib524 lib525 lib526 lib527 lib529        lib532   \
@@ -81,6 +81,10 @@ libntlmconnect_CPPFLAGS = $(AM_CPPFLAGS)
 libauthretry_SOURCES = libauthretry.c $(SUPPORTFILES)
 libauthretry_CPPFLAGS = $(AM_CPPFLAGS)
 
+libprereq_SOURCES = libprereq.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
+libprereq_LDADD = $(TESTUTIL_LIBS)
+libprereq_CPPFLAGS = $(AM_CPPFLAGS)
+
 lib500_SOURCES = lib500.c $(SUPPORTFILES) $(TESTUTIL) $(TSTTRACE) $(MULTIBYTE)
 lib500_LDADD = $(TESTUTIL_LIBS)
 lib500_CPPFLAGS = $(AM_CPPFLAGS)
@@ -494,7 +498,7 @@ lib1520_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1520
 nodist_lib1521_SOURCES = lib1521.c $(SUPPORTFILES)
 lib1521_CPPFLAGS = $(AM_CPPFLAGS) -I$(srcdir)
 
-lib1522_SOURCES = lib1522.c $(SUPPORTFILES) $(TESTUTIL) $(TSTTRACE) 
+lib1522_SOURCES = lib1522.c $(SUPPORTFILES) $(TESTUTIL) $(TSTTRACE)
 lib1522_LDADD = $(TESTUTIL_LIBS)
 lib1522_CPPFLAGS = $(AM_CPPFLAGS)
 
diff --git a/tests/libtest/libprereq.c b/tests/libtest/libprereq.c
new file mode 100644 (file)
index 0000000..11eb18c
--- /dev/null
@@ -0,0 +1,98 @@
+/***************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2021, Max Dymond, <max.dymond@microsoft.com>
+ *
+ * This software is licensed as described in the file COPYING, which
+ * you should have received as part of this distribution. The terms
+ * are also available at https://curl.se/docs/copyright.html.
+ *
+ * You may opt to use, copy, modify, merge, publish, distribute and/or sell
+ * copies of the Software, and permit persons to whom the Software is
+ * furnished to do so, under the terms of the COPYING file.
+ *
+ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
+ * KIND, either express or implied.
+ *
+ ***************************************************************************/
+#include "test.h"
+
+typedef struct prcs {
+  int prereq_retcode;
+  int ipv6;
+} PRCS;
+
+static int prereq_callback(void *clientp,
+                           char *conn_primary_ip,
+                           char *conn_local_ip,
+                           int conn_primary_port,
+                           int conn_local_port)
+{
+  PRCS *prereq_cb = (PRCS *)clientp;
+
+  if(prereq_cb->ipv6) {
+    printf("Connected to [%s]\n", conn_primary_ip);
+    printf("Connected from [%s]\n", conn_local_ip);
+  }
+  else {
+    printf("Connected to %s\n", conn_primary_ip);
+    printf("Connected from %s\n", conn_local_ip);
+  }
+
+  printf("Remote port = %d\n", conn_primary_port);
+  printf("Local port = %d\n", conn_local_port);
+  printf("Returning = %d\n", prereq_cb->prereq_retcode);
+  return prereq_cb->prereq_retcode;
+}
+
+int test(char *URL)
+{
+  PRCS prereq_cb;
+  CURLcode ret = CURLE_OK;
+  CURL *curl = NULL;
+
+  prereq_cb.prereq_retcode = CURL_PREREQFUNC_OK;
+  prereq_cb.ipv6 = 0;
+
+  curl_global_init(CURL_GLOBAL_ALL);
+  curl = curl_easy_init();
+
+  if(curl) {
+    if(strstr(URL, "#ipv6")) {
+      /* The IP addresses should be surrounded by brackets! */
+      prereq_cb.ipv6 = 1;
+    }
+    if(strstr(URL, "#err")) {
+      /* Set the callback to exit with failure */
+      prereq_cb.prereq_retcode = CURL_PREREQFUNC_ABORT;
+    }
+
+    curl_easy_setopt(curl, CURLOPT_URL, URL);
+    curl_easy_setopt(curl, CURLOPT_PREREQFUNCTION, prereq_callback);
+    curl_easy_setopt(curl, CURLOPT_PREREQDATA, &prereq_cb);
+    curl_easy_setopt(curl, CURLOPT_WRITEDATA, stderr);
+
+    if(strstr(URL, "#redir")) {
+      /* Enable follow-location */
+      curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
+    }
+
+    ret = curl_easy_perform(curl);
+    if(ret) {
+      fprintf(stderr, "%s:%d curl_easy_perform() failed with code %d (%s)\n",
+          __FILE__, __LINE__, ret, curl_easy_strerror(ret));
+      goto test_cleanup;
+    }
+  }
+
+test_cleanup:
+  curl_easy_cleanup(curl);
+  curl_global_cleanup();
+
+  return ret;
+}
+
index 0a4ff3dccfe68f901ba7731b23c5845232229ee0..48b5bbbf213875391558e46b420e85899bf6946c 100755 (executable)
@@ -136,6 +136,7 @@ static curl_xferinfo_callback xferinfocb;
 static curl_hstsread_callback hstsreadcb;
 static curl_hstswrite_callback hstswritecb;
 static curl_resolver_start_callback resolver_start_cb;
+static curl_prereq_callback prereqcb;
 
 int test(char *URL)
 {