Hi,
you may want to consider the attached patch implementing a callback
function in libcurl to be called when a http redirect (enabled by
CURLOPT_FOLLOWLOCATION) is about to be followed. The callback
function is called with the URL to be opened and may abort the
redirect by returning an error code.
I use that (from PHP) in web spider code to evaluate robots.txt
exclusions while in a chain of redirects that become more and more
common by the use of URL shorteners. The PHP integration needs
an opaque data pointer to give the (PHP) callback function the
required context.
I hope I met the the cURL standards with the submission,
korni
diff -r -ur curl-7.23.1-dist/docs/libcurl/curl_easy_setopt.3 curl-7.23.1/docs/libcurl/curl_easy_setopt.3
--- curl-7.23.1-dist/docs/libcurl/curl_easy_setopt.3 2011-11-04 23:32:55.000000000 +0100
+++ curl-7.23.1/docs/libcurl/curl_easy_setopt.3 2012-01-10 12:09:57.000000000 +0100
@@ -1171,6 +1171,20 @@
when setting \fICURLOPT_FOLLOWLOCATION\fP. (Added in 7.17.1) (This option was
known as CURLOPT_POST301 up to 7.19.0 as it only supported the 301 way before
then)
+.IP CURLOPT_REDIRECTFUNCTION
+Pass a function pointer that should match the \fIcurl_redirect_callback\fP
+prototype found in \fI<curl/curl.h>\fP. The function gets called by libcurl
+if \fICURLOPT_FOLLOWLOCATION\fP is set and a redirect is
+encountered. The function is called with an opaque pointer set
+by \fICURLOPT_REDIRECTDATA\fP and a string containing the URL
+to redirect to.
+The callback function may decide if the redirect is to be
+followed by returning \fICURLE_OK\fP or not by returning any error
+code, e.g. \fICURLE_TOO_MANY_REDIRECTS\fP.
+.IP CURLOPT_REDIRECTDATA
+Pass a pointer that will be untouched by libcurl and passed as the first
+argument to the redirect callback set with \fICURLOPT_REDIRECTFUNCTION\fP.
+
.IP CURLOPT_PUT
A parameter set to 1 tells the library to use HTTP PUT to transfer data. The
data should be set with \fICURLOPT_READDATA\fP and \fICURLOPT_INFILESIZE\fP.
diff -r -ur curl-7.23.1-dist/include/curl/curl.h curl-7.23.1/include/curl/curl.h
--- curl-7.23.1-dist/include/curl/curl.h 2011-11-04 23:32:55.000000000 +0100
+++ curl-7.23.1/include/curl/curl.h 2012-01-10 11:18:52.000000000 +0100
@@ -578,6 +578,9 @@
OpenSSL SSL_CTX */
void *userptr);
+typedef CURLcode (*curl_redirect_callback)(void *clientp,
+ char *redirurl);
+
typedef enum {
CURLPROXY_HTTP = 0, /* added in 7.10, new in 7.19.4 default is to use
CONNECT HTTP/1.1 */
@@ -1486,6 +1489,11 @@
/* allow GSSAPI credential delegation */
CINIT(GSSAPI_DELEGATION, LONG, 210),
+ /* Callback function on Location-redirects. The callback should have
+ type curl_redirect_callback */
+ CINIT(REDIRECTFUNCTION, FUNCTIONPOINT, 211),
+ CINIT(REDIRECTDATA, OBJECTPOINT, 212),
+
CURLOPT_LASTENTRY /* the last unused */
} CURLoption;
diff -r -ur curl-7.23.1-dist/lib/transfer.c curl-7.23.1/lib/transfer.c
--- curl-7.23.1-dist/lib/transfer.c 2011-11-04 23:32:57.000000000 +0100
+++ curl-7.23.1/lib/transfer.c 2012-01-10 11:16:07.000000000 +0100
@@ -1785,6 +1785,7 @@
/* Location: following will not happen when HTTP is disabled */
return CURLE_TOO_MANY_REDIRECTS;
#else
+ CURLcode cbresult;
/* Location: redirect */
bool disallowport = FALSE;
@@ -1796,6 +1797,12 @@
return CURLE_TOO_MANY_REDIRECTS;
}
+ if((data->set.fredirect)) {
+ cbresult = (data->set.fredirect)(data->set.redirect_client, newurl);
+ if(cbresult != CURLE_OK)
+ return cbresult;
+ }
+
/* mark the next request as a followed location: */
data->state.this_is_a_follow = TRUE;
diff -r -ur curl-7.23.1-dist/lib/url.c curl-7.23.1/lib/url.c
--- curl-7.23.1-dist/lib/url.c 2011-11-04 23:32:57.000000000 +0100
+++ curl-7.23.1/lib/url.c 2012-01-10 11:41:46.000000000 +0100
@@ -2263,6 +2263,21 @@
data->set.closesocket_client = va_arg(param, void *);
break;
+ case CURLOPT_REDIRECTFUNCTION:
+ /*
+ * redirect callback function: called on http-Location redirect
+ * returning CURLE_TOO_MANY_REDIRECTS or such, if redirect forbidden
+ */
+ data->set.fredirect = va_arg(param, curl_redirect_callback);
+ break;
+
+ case CURLOPT_REDIRECTDATA:
+ /*
+ * Custom client data to pass to the redirect callback
+ */
+ data->set.redirect_client = va_arg(param, void *);
+ break;
+
case CURLOPT_SSL_SESSIONID_CACHE:
data->set.ssl.sessionid = (0 != va_arg(param, long))?TRUE:FALSE;
break;
diff -r -ur curl-7.23.1-dist/lib/urldata.h curl-7.23.1/lib/urldata.h
--- curl-7.23.1-dist/lib/urldata.h 2011-11-04 23:32:57.000000000 +0100
+++ curl-7.23.1/lib/urldata.h 2012-01-10 11:16:07.000000000 +0100
@@ -1400,6 +1400,8 @@
/* function to convert from UTF-8 encoding: */
curl_conv_callback convfromutf8;
+ curl_redirect_callback fredirect; /* function to call for redirect */
+ void *redirect_client; /* pointer to pass to the redirect callback */
void *progress_client; /* pointer to pass to the progress callback */
void *ioctl_client; /* pointer to pass to the ioctl callback */
long timeout; /* in milliseconds, 0 means no timeout */
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette: http://curl.haxx.se/mail/etiquette.html