mirror of
https://github.com/curl/curl.git
synced 2025-01-18 14:04:30 +08:00
parent
43a50a2580
commit
b46cfbc068
@ -22,7 +22,6 @@
|
||||
1.4 signal-based resolver timeouts
|
||||
1.5 get rid of PATH_MAX
|
||||
1.6 Modified buffer size approach
|
||||
1.7 Detect when called from within callbacks
|
||||
1.8 CURLOPT_RESOLVE for any port number
|
||||
1.9 Cache negative name resolves
|
||||
1.10 auto-detect proxy
|
||||
@ -239,12 +238,6 @@
|
||||
Dynamically allocate buffer size depending on protocol in use in combination
|
||||
with freeing it after each individual transfer? Other suggestions?
|
||||
|
||||
1.7 Detect when called from within callbacks
|
||||
|
||||
We should set a state variable before calling callbacks, so that we
|
||||
subsequently can add code within libcurl that returns error if called within
|
||||
callbacks for when that's not supported.
|
||||
|
||||
1.8 CURLOPT_RESOLVE for any port number
|
||||
|
||||
This option allows applications to set a replacement IP address for a given
|
||||
|
@ -252,6 +252,8 @@ Failed to match the pinned key specified with \fICURLOPT_PINNEDPUBLICKEY(3)\fP.
|
||||
Status returned failure when asked with \fICURLOPT_SSL_VERIFYSTATUS(3)\fP.
|
||||
.IP "CURLE_HTTP2_STREAM (92)"
|
||||
Stream error in the HTTP/2 framing layer.
|
||||
.IP "CURLE_RECURSIVE_API_CALL (93)"
|
||||
An API function was called from inside a callback.
|
||||
.IP "CURLE_OBSOLETE*"
|
||||
These error codes will never be returned. They were used in an old libcurl
|
||||
version and are currently unused.
|
||||
@ -285,6 +287,8 @@ curl_multi_setopt() with unsupported option
|
||||
.IP "CURLM_ADDED_ALREADY (7)"
|
||||
An easy handle already added to a multi handle was attempted to get added a
|
||||
second time. (Added in 7.32.1)
|
||||
.IP "CURLM_RECURSIVE_API_CALL (8)"
|
||||
An API function was called from inside a callback.
|
||||
.SH "CURLSHcode"
|
||||
The "share" interface will return a CURLSHcode to indicate when an error has
|
||||
occurred. Also consider \fIcurl_share_strerror(3)\fP.
|
||||
|
@ -101,6 +101,7 @@ CURLE_QUOTE_ERROR 7.17.0
|
||||
CURLE_RANGE_ERROR 7.17.0
|
||||
CURLE_READ_ERROR 7.1
|
||||
CURLE_RECV_ERROR 7.10
|
||||
CURLE_RECURSIVE_API_CALL 7.59.0
|
||||
CURLE_REMOTE_ACCESS_DENIED 7.17.0
|
||||
CURLE_REMOTE_DISK_FULL 7.17.0
|
||||
CURLE_REMOTE_FILE_EXISTS 7.17.0
|
||||
@ -323,6 +324,7 @@ CURLM_CALL_MULTI_SOCKET 7.15.5
|
||||
CURLM_INTERNAL_ERROR 7.9.6
|
||||
CURLM_OK 7.9.6
|
||||
CURLM_OUT_OF_MEMORY 7.9.6
|
||||
CURLM_RECURSIVE_API_CALL 7.59.0
|
||||
CURLM_UNKNOWN_OPTION 7.15.4
|
||||
CURLOPTTYPE_FUNCTIONPOINT 7.1
|
||||
CURLOPTTYPE_LONG 7.1
|
||||
|
@ -577,6 +577,8 @@ typedef enum {
|
||||
CURLE_SSL_INVALIDCERTSTATUS, /* 91 - invalid certificate status */
|
||||
CURLE_HTTP2_STREAM, /* 92 - stream error in HTTP/2 framing layer
|
||||
*/
|
||||
CURLE_RECURSIVE_API_CALL, /* 93 - an api function was called from
|
||||
inside a callback */
|
||||
CURL_LAST /* never use! */
|
||||
} CURLcode;
|
||||
|
||||
|
@ -70,6 +70,8 @@ typedef enum {
|
||||
CURLM_UNKNOWN_OPTION, /* curl_multi_setopt() with unsupported option */
|
||||
CURLM_ADDED_ALREADY, /* an easy handle already added to a multi handle was
|
||||
attempted to get added - again */
|
||||
CURLM_RECURSIVE_API_CALL, /* an api function was called from inside a
|
||||
callback */
|
||||
CURLM_LAST
|
||||
} CURLMcode;
|
||||
|
||||
|
@ -1033,9 +1033,11 @@ static CURLcode singleipconnect(struct connectdata *conn,
|
||||
|
||||
if(data->set.fsockopt) {
|
||||
/* activate callback for setting socket options */
|
||||
Curl_set_in_callback(data, true);
|
||||
error = data->set.fsockopt(data->set.sockopt_client,
|
||||
sockfd,
|
||||
CURLSOCKTYPE_IPCXN);
|
||||
Curl_set_in_callback(data, false);
|
||||
|
||||
if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
|
||||
isconnected = TRUE;
|
||||
@ -1311,8 +1313,12 @@ int Curl_closesocket(struct connectdata *conn,
|
||||
status */
|
||||
conn->sock_accepted[SECONDARYSOCKET] = FALSE;
|
||||
else {
|
||||
int rc;
|
||||
Curl_multi_closed(conn, sock);
|
||||
return conn->fclosesocket(conn->closesocket_client, sock);
|
||||
Curl_set_in_callback(conn->data, true);
|
||||
rc = conn->fclosesocket(conn->closesocket_client, sock);
|
||||
Curl_set_in_callback(conn->data, false);
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1363,7 +1369,7 @@ CURLcode Curl_socket(struct connectdata *conn,
|
||||
addr->addrlen = sizeof(struct Curl_sockaddr_storage);
|
||||
memcpy(&addr->sa_addr, ai->ai_addr, addr->addrlen);
|
||||
|
||||
if(data->set.fopensocket)
|
||||
if(data->set.fopensocket) {
|
||||
/*
|
||||
* If the opensocket callback is set, all the destination address
|
||||
* information is passed to the callback. Depending on this information the
|
||||
@ -1373,9 +1379,12 @@ CURLcode Curl_socket(struct connectdata *conn,
|
||||
* might have been changed and this 'new' address will actually be used
|
||||
* here to connect.
|
||||
*/
|
||||
Curl_set_in_callback(data, true);
|
||||
*sockfd = data->set.fopensocket(data->set.opensocket_client,
|
||||
CURLSOCKTYPE_IPCXN,
|
||||
(struct curl_sockaddr *)addr);
|
||||
Curl_set_in_callback(data, false);
|
||||
}
|
||||
else
|
||||
/* opensocket callback not set, so simply create the socket now */
|
||||
*sockfd = socket(addr->family, addr->socktype, addr->protocol);
|
||||
|
13
lib/easy.c
13
lib/easy.c
@ -61,6 +61,7 @@
|
||||
#include "strdup.h"
|
||||
#include "progress.h"
|
||||
#include "easyif.h"
|
||||
#include "multiif.h"
|
||||
#include "select.h"
|
||||
#include "sendf.h" /* for failf function prototype */
|
||||
#include "connect.h" /* for Curl_getconnectinfo */
|
||||
@ -761,6 +762,9 @@ static CURLcode easy_perform(struct Curl_easy *data, bool events)
|
||||
data->multi_easy = multi;
|
||||
}
|
||||
|
||||
if(multi->in_callback)
|
||||
return CURLE_RECURSIVE_API_CALL;
|
||||
|
||||
/* Copy the MAXCONNECTS option to the multi handle */
|
||||
curl_multi_setopt(multi, CURLMOPT_MAXCONNECTS, data->set.maxconnects);
|
||||
|
||||
@ -1030,6 +1034,9 @@ void curl_easy_reset(struct Curl_easy *data)
|
||||
* the pausing, you may get your write callback called at this point.
|
||||
*
|
||||
* Action is a bitmask consisting of CURLPAUSE_* bits in curl/curl.h
|
||||
*
|
||||
* NOTE: This is one of few API functions that are allowed to be called from
|
||||
* within a callback.
|
||||
*/
|
||||
CURLcode curl_easy_pause(struct Curl_easy *data, int action)
|
||||
{
|
||||
@ -1134,6 +1141,9 @@ CURLcode curl_easy_recv(struct Curl_easy *data, void *buffer, size_t buflen,
|
||||
ssize_t n1;
|
||||
struct connectdata *c;
|
||||
|
||||
if(Curl_is_in_callback(data))
|
||||
return CURLE_RECURSIVE_API_CALL;
|
||||
|
||||
result = easy_connection(data, &sfd, &c);
|
||||
if(result)
|
||||
return result;
|
||||
@ -1161,6 +1171,9 @@ CURLcode curl_easy_send(struct Curl_easy *data, const void *buffer,
|
||||
ssize_t n1;
|
||||
struct connectdata *c = NULL;
|
||||
|
||||
if(Curl_is_in_callback(data))
|
||||
return CURLE_RECURSIVE_API_CALL;
|
||||
|
||||
result = easy_connection(data, &sfd, &c);
|
||||
if(result)
|
||||
return result;
|
||||
|
16
lib/ftp.c
16
lib/ftp.c
@ -311,9 +311,11 @@ static CURLcode AcceptServerConnect(struct connectdata *conn)
|
||||
int error = 0;
|
||||
|
||||
/* activate callback for setting socket options */
|
||||
Curl_set_in_callback(data, true);
|
||||
error = data->set.fsockopt(data->set.sockopt_client,
|
||||
s,
|
||||
CURLSOCKTYPE_ACCEPT);
|
||||
Curl_set_in_callback(data, false);
|
||||
|
||||
if(error) {
|
||||
close_secondarysocket(conn);
|
||||
@ -1616,8 +1618,10 @@ static CURLcode ftp_state_ul_setup(struct connectdata *conn,
|
||||
|
||||
/* Let's read off the proper amount of bytes from the input. */
|
||||
if(conn->seek_func) {
|
||||
Curl_set_in_callback(data, true);
|
||||
seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
|
||||
SEEK_SET);
|
||||
Curl_set_in_callback(data, true);
|
||||
}
|
||||
|
||||
if(seekerr != CURL_SEEKFUNC_OK) {
|
||||
@ -3181,7 +3185,9 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
|
||||
|
||||
if(data->state.wildcardmatch) {
|
||||
if(data->set.chunk_end && ftpc->file) {
|
||||
Curl_set_in_callback(data, true);
|
||||
data->set.chunk_end(data->wildcard.customptr);
|
||||
Curl_set_in_callback(data, false);
|
||||
}
|
||||
ftpc->known_filesize = -1;
|
||||
}
|
||||
@ -3834,8 +3840,11 @@ static CURLcode wc_statemach(struct connectdata *conn)
|
||||
|
||||
infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
|
||||
if(conn->data->set.chunk_bgn) {
|
||||
long userresponse = conn->data->set.chunk_bgn(
|
||||
long userresponse;
|
||||
Curl_set_in_callback(conn->data, true);
|
||||
userresponse = conn->data->set.chunk_bgn(
|
||||
finfo, wildcard->customptr, (int)wildcard->filelist.size);
|
||||
Curl_set_in_callback(conn->data, false);
|
||||
switch(userresponse) {
|
||||
case CURL_CHUNK_BGN_FUNC_SKIP:
|
||||
infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
|
||||
@ -3871,8 +3880,11 @@ static CURLcode wc_statemach(struct connectdata *conn)
|
||||
} break;
|
||||
|
||||
case CURLWC_SKIP: {
|
||||
if(conn->data->set.chunk_end)
|
||||
if(conn->data->set.chunk_end) {
|
||||
Curl_set_in_callback(conn->data, true);
|
||||
conn->data->set.chunk_end(conn->data->wildcard.customptr);
|
||||
Curl_set_in_callback(conn->data, false);
|
||||
}
|
||||
Curl_llist_remove(&wildcard->filelist, wildcard->filelist.head, NULL);
|
||||
wildcard->state = (wildcard->filelist.size == 0) ?
|
||||
CURLWC_CLEAN : CURLWC_DOWNLOADING;
|
||||
|
@ -49,6 +49,7 @@
|
||||
#include "ftplistparser.h"
|
||||
#include "curl_fnmatch.h"
|
||||
#include "curl_memory.h"
|
||||
#include "multiif.h"
|
||||
/* The last #include file should be: */
|
||||
#include "memdebug.h"
|
||||
|
||||
@ -294,6 +295,7 @@ static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
|
||||
compare = Curl_fnmatch;
|
||||
|
||||
/* filter pattern-corresponding filenames */
|
||||
Curl_set_in_callback(conn->data, true);
|
||||
if(compare(conn->data->set.fnmatch_data, wc->pattern,
|
||||
finfo->filename) == 0) {
|
||||
/* discard symlink which is containing multiple " -> " */
|
||||
@ -305,6 +307,7 @@ static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
|
||||
else {
|
||||
add = FALSE;
|
||||
}
|
||||
Curl_set_in_callback(conn->data, false);
|
||||
|
||||
if(add) {
|
||||
Curl_llist_insert_next(llist, llist->tail, finfo, &infop->list);
|
||||
|
@ -2191,8 +2191,10 @@ CURLcode Curl_http(struct connectdata *conn, bool *done)
|
||||
/* Now, let's read off the proper amount of bytes from the
|
||||
input. */
|
||||
if(conn->seek_func) {
|
||||
Curl_set_in_callback(data, true);
|
||||
seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
|
||||
SEEK_SET);
|
||||
Curl_set_in_callback(data, false);
|
||||
}
|
||||
|
||||
if(seekerr != CURL_SEEKFUNC_OK) {
|
||||
|
@ -464,9 +464,11 @@ static int push_promise(struct Curl_easy *data,
|
||||
goto fail;
|
||||
}
|
||||
|
||||
Curl_set_in_callback(data, true);
|
||||
rv = data->multi->push_cb(data, newhandle,
|
||||
stream->push_headers_used, &heads,
|
||||
data->multi->push_userp);
|
||||
Curl_set_in_callback(data, false);
|
||||
|
||||
/* free the headers again */
|
||||
for(i = 0; i<stream->push_headers_used; i++)
|
||||
|
65
lib/multi.c
65
lib/multi.c
@ -366,6 +366,9 @@ CURLMcode curl_multi_add_handle(struct Curl_multi *multi,
|
||||
if(data->multi)
|
||||
return CURLM_ADDED_ALREADY;
|
||||
|
||||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
|
||||
/* Initialize timeout list for this handle */
|
||||
Curl_llist_init(&data->state.timeoutlist, NULL);
|
||||
|
||||
@ -640,6 +643,9 @@ CURLMcode curl_multi_remove_handle(struct Curl_multi *multi,
|
||||
if(!data->multi)
|
||||
return CURLM_OK; /* it is already removed so let's say it is fine! */
|
||||
|
||||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
|
||||
premature = (data->mstate < CURLM_STATE_COMPLETED) ? TRUE : FALSE;
|
||||
easy_owns_conn = (data->easy_conn && (data->easy_conn->data == easy)) ?
|
||||
TRUE : FALSE;
|
||||
@ -903,6 +909,9 @@ CURLMcode curl_multi_fdset(struct Curl_multi *multi,
|
||||
if(!GOOD_MULTI_HANDLE(multi))
|
||||
return CURLM_BAD_HANDLE;
|
||||
|
||||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
|
||||
data = multi->easyp;
|
||||
while(data) {
|
||||
bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE);
|
||||
@ -956,6 +965,9 @@ CURLMcode curl_multi_wait(struct Curl_multi *multi,
|
||||
if(!GOOD_MULTI_HANDLE(multi))
|
||||
return CURLM_BAD_HANDLE;
|
||||
|
||||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
|
||||
/* If the internally desired timeout is actually shorter than requested from
|
||||
the outside, then use the shorter time! But only if the internal timer
|
||||
is actually larger than -1! */
|
||||
@ -1121,6 +1133,9 @@ CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
|
||||
{
|
||||
CURLMcode rc;
|
||||
|
||||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
|
||||
rc = curl_multi_add_handle(multi, data);
|
||||
if(!rc) {
|
||||
struct SingleRequest *k = &data->req;
|
||||
@ -2127,6 +2142,9 @@ CURLMcode curl_multi_perform(struct Curl_multi *multi, int *running_handles)
|
||||
if(!GOOD_MULTI_HANDLE(multi))
|
||||
return CURLM_BAD_HANDLE;
|
||||
|
||||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
|
||||
data = multi->easyp;
|
||||
while(data) {
|
||||
CURLMcode result;
|
||||
@ -2174,6 +2192,9 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
|
||||
struct Curl_easy *nextdata;
|
||||
|
||||
if(GOOD_MULTI_HANDLE(multi)) {
|
||||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
|
||||
multi->type = 0; /* not good anymore */
|
||||
|
||||
/* Firsrt remove all remaining easy handles */
|
||||
@ -2234,7 +2255,9 @@ CURLMsg *curl_multi_info_read(struct Curl_multi *multi, int *msgs_in_queue)
|
||||
|
||||
*msgs_in_queue = 0; /* default to none */
|
||||
|
||||
if(GOOD_MULTI_HANDLE(multi) && Curl_llist_count(&multi->msglist)) {
|
||||
if(GOOD_MULTI_HANDLE(multi) &&
|
||||
!multi->in_callback &&
|
||||
Curl_llist_count(&multi->msglist)) {
|
||||
/* there is one or more messages in the list */
|
||||
struct curl_llist_element *e;
|
||||
|
||||
@ -2624,6 +2647,9 @@ CURLMcode curl_multi_setopt(struct Curl_multi *multi,
|
||||
if(!GOOD_MULTI_HANDLE(multi))
|
||||
return CURLM_BAD_HANDLE;
|
||||
|
||||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
|
||||
va_start(param, option);
|
||||
|
||||
switch(option) {
|
||||
@ -2688,7 +2714,10 @@ CURLMcode curl_multi_setopt(struct Curl_multi *multi,
|
||||
CURLMcode curl_multi_socket(struct Curl_multi *multi, curl_socket_t s,
|
||||
int *running_handles)
|
||||
{
|
||||
CURLMcode result = multi_socket(multi, FALSE, s, 0, running_handles);
|
||||
CURLMcode result;
|
||||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
result = multi_socket(multi, FALSE, s, 0, running_handles);
|
||||
if(CURLM_OK >= result)
|
||||
update_timer(multi);
|
||||
return result;
|
||||
@ -2697,8 +2726,10 @@ CURLMcode curl_multi_socket(struct Curl_multi *multi, curl_socket_t s,
|
||||
CURLMcode curl_multi_socket_action(struct Curl_multi *multi, curl_socket_t s,
|
||||
int ev_bitmask, int *running_handles)
|
||||
{
|
||||
CURLMcode result = multi_socket(multi, FALSE, s,
|
||||
ev_bitmask, running_handles);
|
||||
CURLMcode result;
|
||||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
result = multi_socket(multi, FALSE, s, ev_bitmask, running_handles);
|
||||
if(CURLM_OK >= result)
|
||||
update_timer(multi);
|
||||
return result;
|
||||
@ -2707,8 +2738,10 @@ CURLMcode curl_multi_socket_action(struct Curl_multi *multi, curl_socket_t s,
|
||||
CURLMcode curl_multi_socket_all(struct Curl_multi *multi, int *running_handles)
|
||||
|
||||
{
|
||||
CURLMcode result = multi_socket(multi, TRUE, CURL_SOCKET_BAD, 0,
|
||||
running_handles);
|
||||
CURLMcode result;
|
||||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
result = multi_socket(multi, TRUE, CURL_SOCKET_BAD, 0, running_handles);
|
||||
if(CURLM_OK >= result)
|
||||
update_timer(multi);
|
||||
return result;
|
||||
@ -2760,6 +2793,9 @@ CURLMcode curl_multi_timeout(struct Curl_multi *multi,
|
||||
if(!GOOD_MULTI_HANDLE(multi))
|
||||
return CURLM_BAD_HANDLE;
|
||||
|
||||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
|
||||
return multi_timeout(multi, timeout_ms);
|
||||
}
|
||||
|
||||
@ -2992,6 +3028,9 @@ CURLMcode curl_multi_assign(struct Curl_multi *multi, curl_socket_t s,
|
||||
{
|
||||
struct Curl_sh_entry *there = NULL;
|
||||
|
||||
if(multi->in_callback)
|
||||
return CURLM_RECURSIVE_API_CALL;
|
||||
|
||||
there = sh_getentry(&multi->sockhash, s);
|
||||
|
||||
if(!there)
|
||||
@ -3054,6 +3093,20 @@ void Curl_multi_process_pending_handles(struct Curl_multi *multi)
|
||||
}
|
||||
}
|
||||
|
||||
void Curl_set_in_callback(struct Curl_easy *easy, bool value)
|
||||
{
|
||||
if(easy->multi_easy)
|
||||
easy->multi_easy->in_callback = value;
|
||||
else if(easy->multi)
|
||||
easy->multi->in_callback = value;
|
||||
}
|
||||
|
||||
bool Curl_is_in_callback(struct Curl_easy *easy)
|
||||
{
|
||||
return ((easy->multi && easy->multi->in_callback) ||
|
||||
(easy->multi_easy && easy->multi_easy->in_callback));
|
||||
}
|
||||
|
||||
#ifdef DEBUGBUILD
|
||||
void Curl_multi_dump(struct Curl_multi *multi)
|
||||
{
|
||||
|
@ -146,6 +146,7 @@ struct Curl_multi {
|
||||
void *timer_userp;
|
||||
struct curltime timer_lastcall; /* the fixed time for the timeout for the
|
||||
previous callback */
|
||||
bool in_callback; /* true while executing a callback */
|
||||
};
|
||||
|
||||
#endif /* HEADER_CURL_MULTIHANDLE_H */
|
||||
|
@ -31,6 +31,8 @@ void Curl_expire_clear(struct Curl_easy *data);
|
||||
void Curl_expire_done(struct Curl_easy *data, expire_id id);
|
||||
bool Curl_pipeline_wanted(const struct Curl_multi* multi, int bits);
|
||||
void Curl_multi_handlePipeBreak(struct Curl_easy *data);
|
||||
void Curl_set_in_callback(struct Curl_easy *data, bool value);
|
||||
bool Curl_is_in_callback(struct Curl_easy *easy);
|
||||
|
||||
/* Internal version of curl_multi_init() accepts size parameters for the
|
||||
socket and connection hashes */
|
||||
|
@ -84,7 +84,10 @@ CURLcode Curl_convert_to_network(struct Curl_easy *data,
|
||||
{
|
||||
if(data && data->set.convtonetwork) {
|
||||
/* use translation callback */
|
||||
CURLcode result = data->set.convtonetwork(buffer, length);
|
||||
CURLcode result;
|
||||
Curl_set_in_callback(data, true);
|
||||
result = data->set.convtonetwork(buffer, length);
|
||||
Curl_set_in_callback(data, false);
|
||||
if(result) {
|
||||
failf(data,
|
||||
"CURLOPT_CONV_TO_NETWORK_FUNCTION callback returned %d: %s",
|
||||
@ -147,7 +150,10 @@ CURLcode Curl_convert_from_network(struct Curl_easy *data,
|
||||
{
|
||||
if(data && data->set.convfromnetwork) {
|
||||
/* use translation callback */
|
||||
CURLcode result = data->set.convfromnetwork(buffer, length);
|
||||
CURLcode result;
|
||||
Curl_set_in_callback(data, true);
|
||||
result = data->set.convfromnetwork(buffer, length);
|
||||
Curl_set_in_callback(data, false);
|
||||
if(result) {
|
||||
failf(data,
|
||||
"CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %d: %s",
|
||||
@ -210,7 +216,10 @@ CURLcode Curl_convert_from_utf8(struct Curl_easy *data,
|
||||
{
|
||||
if(data && data->set.convfromutf8) {
|
||||
/* use translation callback */
|
||||
CURLcode result = data->set.convfromutf8(buffer, length);
|
||||
CURLcode result;
|
||||
Curl_set_in_callback(data, true);
|
||||
result = data->set.convfromutf8(buffer, length);
|
||||
Curl_set_in_callback(data, false);
|
||||
if(result) {
|
||||
failf(data,
|
||||
"CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %d: %s",
|
||||
|
@ -24,6 +24,7 @@
|
||||
|
||||
#include "urldata.h"
|
||||
#include "sendf.h"
|
||||
#include "multiif.h"
|
||||
#include "progress.h"
|
||||
#include "curl_printf.h"
|
||||
|
||||
@ -461,22 +462,26 @@ int Curl_pgrsUpdate(struct connectdata *conn)
|
||||
|
||||
if(data->set.fxferinfo) {
|
||||
/* There's a callback set, call that */
|
||||
Curl_set_in_callback(data, true);
|
||||
result = data->set.fxferinfo(data->set.progress_client,
|
||||
data->progress.size_dl,
|
||||
data->progress.downloaded,
|
||||
data->progress.size_ul,
|
||||
data->progress.uploaded);
|
||||
Curl_set_in_callback(data, false);
|
||||
if(result)
|
||||
failf(data, "Callback aborted");
|
||||
return result;
|
||||
}
|
||||
if(data->set.fprogress) {
|
||||
/* The older deprecated callback is set, call that */
|
||||
Curl_set_in_callback(data, true);
|
||||
result = data->set.fprogress(data->set.progress_client,
|
||||
(double)data->progress.size_dl,
|
||||
(double)data->progress.downloaded,
|
||||
(double)data->progress.size_ul,
|
||||
(double)data->progress.uploaded);
|
||||
Curl_set_in_callback(data, false);
|
||||
if(result)
|
||||
failf(data, "Callback aborted");
|
||||
return result;
|
||||
|
@ -770,7 +770,9 @@ CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len)
|
||||
user_ptr = data->set.out;
|
||||
}
|
||||
|
||||
Curl_set_in_callback(data, true);
|
||||
wrote = writeit(ptr, 1, len, user_ptr);
|
||||
Curl_set_in_callback(data, false);
|
||||
|
||||
if(CURL_WRITEFUNC_PAUSE == wrote) {
|
||||
failf(data, "Cannot pause RTP");
|
||||
|
11
lib/sendf.c
11
lib/sendf.c
@ -37,6 +37,7 @@
|
||||
#include "connect.h"
|
||||
#include "vtls/vtls.h"
|
||||
#include "ssh.h"
|
||||
#include "easyif.h"
|
||||
#include "multiif.h"
|
||||
#include "non-ascii.h"
|
||||
#include "strerror.h"
|
||||
@ -598,7 +599,10 @@ CURLcode Curl_client_chop_write(struct connectdata *conn,
|
||||
}
|
||||
|
||||
if(writeheader) {
|
||||
size_t wrote = writeheader(ptr, 1, chunklen, data->set.writeheader);
|
||||
size_t wrote;
|
||||
Curl_set_in_callback(data, true);
|
||||
wrote = writeheader(ptr, 1, chunklen, data->set.writeheader);
|
||||
Curl_set_in_callback(data, false);
|
||||
|
||||
if(CURL_WRITEFUNC_PAUSE == wrote)
|
||||
/* here we pass in the HEADER bit only since if this was body as well
|
||||
@ -798,8 +802,11 @@ static int showit(struct Curl_easy *data, curl_infotype type,
|
||||
}
|
||||
#endif /* CURL_DOES_CONVERSIONS */
|
||||
|
||||
if(data->set.fdebug)
|
||||
if(data->set.fdebug) {
|
||||
Curl_set_in_callback(data, true);
|
||||
rc = (*data->set.fdebug)(data, type, ptr, size, data->set.debugdata);
|
||||
Curl_set_in_callback(data, false);
|
||||
}
|
||||
else {
|
||||
switch(type) {
|
||||
case CURLINFO_TEXT:
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "sendf.h"
|
||||
#include "http2.h"
|
||||
#include "setopt.h"
|
||||
#include "multiif.h"
|
||||
|
||||
/* The last 3 #include files should be in this order */
|
||||
#include "curl_printf.h"
|
||||
@ -2544,6 +2545,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option,
|
||||
/*
|
||||
* curl_easy_setopt() is the external interface for setting options on an
|
||||
* easy handle.
|
||||
*
|
||||
* NOTE: This is one of few API functions that are allowed to be called from
|
||||
* within a callback.
|
||||
*/
|
||||
|
||||
#undef curl_easy_setopt
|
||||
|
@ -383,8 +383,10 @@ static int myssh_is_known(struct connectdata *conn)
|
||||
}
|
||||
|
||||
/* we don't have anything equivalent to knownkey. Always NULL */
|
||||
Curl_set_in_callback(data, true);
|
||||
rc = func(data, NULL, &foundkey, /* from the remote host */
|
||||
keymatch, data->set.ssh_keyfunc_userp);
|
||||
Curl_set_in_callback(data, false);
|
||||
|
||||
switch(rc) {
|
||||
case CURLKHSTAT_FINE_ADD_TO_FILE:
|
||||
@ -1128,8 +1130,10 @@ static CURLcode myssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
if(data->state.resume_from > 0) {
|
||||
/* Let's read off the proper amount of bytes from the input. */
|
||||
if(conn->seek_func) {
|
||||
Curl_set_in_callback(data, true);
|
||||
seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
|
||||
SEEK_SET);
|
||||
Curl_set_in_callback(data, false);
|
||||
}
|
||||
|
||||
if(seekerr != CURL_SEEKFUNC_OK) {
|
||||
|
13
lib/ssh.c
13
lib/ssh.c
@ -523,9 +523,11 @@ static CURLcode ssh_knownhost(struct connectdata *conn)
|
||||
keymatch = (enum curl_khmatch)keycheck;
|
||||
|
||||
/* Ask the callback how to behave */
|
||||
Curl_set_in_callback(data, true);
|
||||
rc = func(data, knownkeyp, /* from the knownhosts file */
|
||||
&foundkey, /* from the remote host */
|
||||
keymatch, data->set.ssh_keyfunc_userp);
|
||||
Curl_set_in_callback(data, false);
|
||||
}
|
||||
else
|
||||
/* no remotekey means failure! */
|
||||
@ -1747,8 +1749,10 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
if(data->state.resume_from > 0) {
|
||||
/* Let's read off the proper amount of bytes from the input. */
|
||||
if(conn->seek_func) {
|
||||
Curl_set_in_callback(data, true);
|
||||
seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
|
||||
SEEK_SET);
|
||||
Curl_set_in_callback(data, false);
|
||||
}
|
||||
|
||||
if(seekerr != CURL_SEEKFUNC_OK) {
|
||||
@ -1765,9 +1769,12 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
|
||||
(size_t)data->set.buffer_size :
|
||||
curlx_sotouz(data->state.resume_from - passed);
|
||||
|
||||
size_t actuallyread =
|
||||
data->state.fread_func(data->state.buffer, 1,
|
||||
readthisamountnow, data->state.in);
|
||||
size_t actuallyread;
|
||||
Curl_set_in_callback(data, true);
|
||||
actuallyread = data->state.fread_func(data->state.buffer, 1,
|
||||
readthisamountnow,
|
||||
data->state.in);
|
||||
Curl_set_in_callback(data, false);
|
||||
|
||||
passed += actuallyread;
|
||||
if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
|
||||
|
@ -312,6 +312,9 @@ curl_easy_strerror(CURLcode error)
|
||||
case CURLE_HTTP2_STREAM:
|
||||
return "Stream error in the HTTP/2 framing layer";
|
||||
|
||||
case CURLE_RECURSIVE_API_CALL:
|
||||
return "API function called from within callback";
|
||||
|
||||
/* error codes not used by current libcurl */
|
||||
case CURLE_OBSOLETE20:
|
||||
case CURLE_OBSOLETE24:
|
||||
@ -380,6 +383,9 @@ curl_multi_strerror(CURLMcode error)
|
||||
case CURLM_ADDED_ALREADY:
|
||||
return "The easy handle is already added to a multi handle";
|
||||
|
||||
case CURLM_RECURSIVE_API_CALL:
|
||||
return "API function called from within callback";
|
||||
|
||||
case CURLM_LAST:
|
||||
break;
|
||||
}
|
||||
|
@ -135,8 +135,10 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp)
|
||||
|
||||
/* this function returns a size_t, so we typecast to int to prevent warnings
|
||||
with picky compilers */
|
||||
Curl_set_in_callback(data, true);
|
||||
nread = (int)data->state.fread_func(data->req.upload_fromhere, 1,
|
||||
buffersize, data->state.in);
|
||||
Curl_set_in_callback(data, false);
|
||||
|
||||
if(nread == CURL_READFUNC_ABORT) {
|
||||
failf(data, "operation aborted by callback");
|
||||
@ -302,7 +304,9 @@ CURLcode Curl_readrewind(struct connectdata *conn)
|
||||
if(data->set.seek_func) {
|
||||
int err;
|
||||
|
||||
Curl_set_in_callback(data, true);
|
||||
err = (data->set.seek_func)(data->set.seek_client, 0, SEEK_SET);
|
||||
Curl_set_in_callback(data, false);
|
||||
if(err) {
|
||||
failf(data, "seek callback returned error %d", (int)err);
|
||||
return CURLE_SEND_FAIL_REWIND;
|
||||
@ -311,8 +315,10 @@ CURLcode Curl_readrewind(struct connectdata *conn)
|
||||
else if(data->set.ioctl_func) {
|
||||
curlioerr err;
|
||||
|
||||
Curl_set_in_callback(data, true);
|
||||
err = (data->set.ioctl_func)(data, CURLIOCMD_RESTARTREAD,
|
||||
data->set.ioctl_client);
|
||||
Curl_set_in_callback(data, false);
|
||||
infof(data, "the ioctl callback returned %d\n", (int)err);
|
||||
|
||||
if(err) {
|
||||
|
@ -171,7 +171,7 @@ test1520 test1521 \
|
||||
test1525 test1526 test1527 test1528 test1529 test1530 test1531 test1532 \
|
||||
test1533 test1534 test1535 test1536 test1537 test1538 \
|
||||
test1540 \
|
||||
test1550 test1551 test1552 test1553 test1554 \
|
||||
test1550 test1551 test1552 test1553 test1554 test1555 \
|
||||
test1600 test1601 test1602 test1603 test1604 test1605 test1606 \
|
||||
\
|
||||
test1700 test1701 test1702 \
|
||||
|
@ -125,7 +125,8 @@ e89: The max connection limit is reached
|
||||
e90: SSL public key does not match pinned public key
|
||||
e91: SSL server certificate status verification FAILED
|
||||
e92: Stream error in the HTTP/2 framing layer
|
||||
e93: Unknown error
|
||||
e93: API function called from within callback
|
||||
e94: Unknown error
|
||||
m-1: Please call curl_multi_perform() soon
|
||||
m0: No error
|
||||
m1: Invalid multi handle
|
||||
@ -135,7 +136,8 @@ m4: Internal error
|
||||
m5: Invalid socket argument
|
||||
m6: Unknown option
|
||||
m7: The easy handle is already added to a multi handle
|
||||
m8: Unknown error
|
||||
m8: API function called from within callback
|
||||
m9: Unknown error
|
||||
s0: No error
|
||||
s1: Unknown share option
|
||||
s2: Share currently in use
|
||||
|
50
tests/data/test1555
Normal file
50
tests/data/test1555
Normal file
@ -0,0 +1,50 @@
|
||||
<testcase>
|
||||
<info>
|
||||
<keywords>
|
||||
RECURSIVE_API_CALL
|
||||
</keywords>
|
||||
</info>
|
||||
|
||||
# Server-side
|
||||
<reply>
|
||||
<data nocheck="yes">
|
||||
HTTP/1.1 204 PARTIAL
|
||||
X-Comment: partial response to keep the client waiting
|
||||
</data>
|
||||
<postcmd>
|
||||
wait 10
|
||||
</postcmd>
|
||||
</reply>
|
||||
|
||||
# Client-side
|
||||
<client>
|
||||
<server>
|
||||
http
|
||||
</server>
|
||||
<tool>
|
||||
lib1555
|
||||
</tool>
|
||||
<name>
|
||||
verify api is protected against calls from callbacks
|
||||
</name>
|
||||
|
||||
# this server/host won't be used for real
|
||||
<command>
|
||||
http://%HOSTIP:%HTTPPORT/1555
|
||||
</command>
|
||||
</client>
|
||||
|
||||
# Verify data after the test has been "shot"
|
||||
<verify>
|
||||
<protocol>
|
||||
</protocol>
|
||||
# 42 == CURLE_ABORTED_BY_CALLBACK
|
||||
<errorcode>
|
||||
42
|
||||
</errorcode>
|
||||
<stdout>
|
||||
curl_easy_recv returned 93
|
||||
curl_easy_send returned 93
|
||||
</stdout>
|
||||
</verify>
|
||||
</testcase>
|
@ -27,7 +27,7 @@ noinst_PROGRAMS = chkhostname libauthretry libntlmconnect \
|
||||
lib1525 lib1526 lib1527 lib1528 lib1529 lib1530 lib1531 lib1532 lib1533 \
|
||||
lib1534 lib1535 lib1536 lib1537 lib1538 \
|
||||
lib1540 \
|
||||
lib1550 lib1551 lib1552 lib1553 lib1554 \
|
||||
lib1550 lib1551 lib1552 lib1553 lib1554 lib1555 \
|
||||
lib1900 \
|
||||
lib2033
|
||||
|
||||
@ -477,6 +477,10 @@ lib1553_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
lib1554_SOURCES = lib1554.c $(SUPPORTFILES)
|
||||
lib1554_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
|
||||
lib1555_SOURCES = lib1555.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
|
||||
lib1555_LDADD = $(TESTUTIL_LIBS)
|
||||
lib1555_CPPFLAGS = $(AM_CPPFLAGS) -DLIB1555
|
||||
|
||||
lib1900_SOURCES = lib1900.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS)
|
||||
lib1900_LDADD = $(TESTUTIL_LIBS)
|
||||
lib1900_CPPFLAGS = $(AM_CPPFLAGS)
|
||||
|
77
tests/libtest/lib1555.c
Normal file
77
tests/libtest/lib1555.c
Normal file
@ -0,0 +1,77 @@
|
||||
/***************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 1998 - 2015, 2017, Daniel Stenberg, <daniel@haxx.se>, 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.haxx.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.
|
||||
*
|
||||
***************************************************************************/
|
||||
/*
|
||||
* Verify that some API functions are locked from being called inside callback
|
||||
*/
|
||||
|
||||
#include "test.h"
|
||||
|
||||
#include "memdebug.h"
|
||||
|
||||
static CURL *curl;
|
||||
|
||||
static int progressCallback(void *arg,
|
||||
double dltotal,
|
||||
double dlnow,
|
||||
double ultotal,
|
||||
double ulnow)
|
||||
{
|
||||
CURLcode res = 0;
|
||||
(void)arg;
|
||||
(void)dltotal;
|
||||
(void)dlnow;
|
||||
(void)ultotal;
|
||||
(void)ulnow;
|
||||
res = curl_easy_recv(curl, NULL, 0, NULL);
|
||||
printf("curl_easy_recv returned %d\n", res);
|
||||
res = curl_easy_send(curl, NULL, 0, NULL);
|
||||
printf("curl_easy_send returned %d\n", res);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int test(char *URL)
|
||||
{
|
||||
int res = 0;
|
||||
|
||||
global_init(CURL_GLOBAL_ALL);
|
||||
|
||||
easy_init(curl);
|
||||
|
||||
easy_setopt(curl, CURLOPT_URL, URL);
|
||||
easy_setopt(curl, CURLOPT_TIMEOUT, (long)7);
|
||||
easy_setopt(curl, CURLOPT_NOSIGNAL, (long)1);
|
||||
easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progressCallback);
|
||||
easy_setopt(curl, CURLOPT_PROGRESSDATA, NULL);
|
||||
easy_setopt(curl, CURLOPT_NOPROGRESS, (long)0);
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
test_cleanup:
|
||||
|
||||
/* undocumented cleanup sequence - type UA */
|
||||
|
||||
curl_easy_cleanup(curl);
|
||||
curl_global_cleanup();
|
||||
|
||||
return res;
|
||||
}
|
Loading…
Reference in New Issue
Block a user