This commit is contained in:
Vigneshwarr 2026-07-30 04:13:10 +03:00 committed by GitHub
commit 961881dae3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 321 additions and 7 deletions

View file

@ -124,11 +124,6 @@ for each redirect.
[curl issue 6743](https://github.com/curl/curl/issues/6743)
## CURLINFO_PAUSE_STATE
Return information about the transfer's current pause state, in both
directions. See [curl issue 2588](https://github.com/curl/curl/issues/2588)
## Expose tried IP addresses that failed
When libcurl fails to connect to a host, it could offer the application the

View file

@ -189,6 +189,10 @@ See CURLINFO_NUM_CONNECTS(3)
The errno from the last failure to connect. See CURLINFO_OS_ERRNO(3)
## CURLINFO_PAUSE_STATE
The current pause state of the transfer. See CURLINFO_PAUSE_STATE(3)
## CURLINFO_POSTTRANSFER_TIME_T
The time it took from the start until the last byte is sent by libcurl.

View file

@ -0,0 +1,79 @@
---
c: Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
SPDX-License-Identifier: curl
Title: CURLINFO_PAUSE_STATE
Section: 3
Source: libcurl
See-also:
- curl_easy_getinfo (3)
- curl_easy_pause (3)
Protocol:
- All
Added-in: 8.22.0
---
# NAME
CURLINFO_PAUSE_STATE - get the current pause state
# SYNOPSIS
~~~c
#include <curl/curl.h>
CURLcode curl_easy_getinfo(CURL *handle, CURLINFO_PAUSE_STATE,
unsigned int *bitmask);
~~~
# DESCRIPTION
Pass a pointer to a long to receive a bitmask describing the current pause
state of the transfer. The bitmask uses the same values as curl_easy_pause(3):
CURLPAUSE_RECV
: Receiving is paused.
CURLPAUSE_SEND
: Sending is paused.
If neither direction is paused, the returned value is zero.
This includes pauses set with curl_easy_pause(3) as well as pauses requested
by read or write callbacks returning CURL_READFUNC_PAUSE or
CURL_WRITEFUNC_PAUSE.
This may be used from within a callback during an active transfer. An easy
handle must not be used from multiple threads simultaneously.
# %PROTOCOLS%
# EXAMPLE
~~~c
int main(void)
{
CURL *curl = curl_easy_init();
if(curl) {
long paused;
CURLcode result = curl_easy_getinfo(curl, CURLINFO_PAUSE_STATE, &paused);
if(!result) {
if(paused & CURLPAUSE_RECV)
printf("Receiving is paused\n");
if(paused & CURLPAUSE_SEND)
printf("Sending is paused\n");
}
curl_easy_cleanup(curl);
}
}
~~~
# %AVAILABILITY%
# RETURN VALUE
curl_easy_getinfo(3) returns a CURLcode indicating success or error.
CURLE_OK (0) means everything was OK, non-zero means an error occurred, see
libcurl-errors(3).

View file

@ -58,6 +58,7 @@ man_MANS = \
CURLINFO_NAMELOOKUP_TIME_T.3 \
CURLINFO_NUM_CONNECTS.3 \
CURLINFO_OS_ERRNO.3 \
CURLINFO_PAUSE_STATE.3 \
CURLINFO_PRETRANSFER_TIME.3 \
CURLINFO_PRETRANSFER_TIME_T.3 \
CURLINFO_POSTTRANSFER_TIME_T.3 \

View file

@ -470,6 +470,7 @@ CURLINFO_NONE 7.4.1
CURLINFO_NUM_CONNECTS 7.12.3
CURLINFO_OFF_T 7.55.0
CURLINFO_OS_ERRNO 7.12.2
CURLINFO_PAUSE_STATE 8.22.0
CURLINFO_POSTTRANSFER_TIME_T 8.10.0
CURLINFO_PRETRANSFER_TIME 7.4.1
CURLINFO_PRETRANSFER_TIME_T 7.61.0

View file

@ -3020,7 +3020,8 @@ typedef enum {
CURLINFO_HTTPAUTH_USED = CURLINFO_LONG + 69,
CURLINFO_PROXYAUTH_USED = CURLINFO_LONG + 70,
CURLINFO_SIZE_DELIVERED = CURLINFO_OFF_T + 71,
CURLINFO_LASTONE = 71
CURLINFO_PAUSE_STATE = CURLINFO_LONG + 72,
CURLINFO_LASTONE = 72
} CURLINFO;
/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as

View file

@ -28,6 +28,7 @@
#include "cfilters.h"
#include "vtls/vtls.h"
#include "connect.h" /* Curl_getconnectinfo() */
#include "transfer.h"
#include "bufref.h"
#include "curlx/strparse.h"
@ -370,6 +371,13 @@ static CURLcode getinfo_long(struct Curl_easy *data, CURLINFO info,
#endif
;
break;
case CURLINFO_PAUSE_STATE:
*param_longp = 0;
if(Curl_xfer_recv_is_paused(data))
*param_longp |= CURLPAUSE_RECV;
if(Curl_xfer_send_is_paused(data))
*param_longp |= CURLPAUSE_SEND;
break;
default:
return CURLE_UNKNOWN_OPTION;
}

View file

@ -288,7 +288,7 @@ test3223 test3224 test3225 test3226 test3227 test3228 test3229 \
\
test3300 test3301 test3302 test3303 test3304 test3305 test3306 \
\
test3400 test3401 \
test3400 test3401 test3403 \
\
test4000 test4001 \
\

62
tests/data/test3403 Normal file
View file

@ -0,0 +1,62 @@
<?xml version="1.0" encoding="US-ASCII"?>
<testcase>
<info>
<keywords>
HTTP
HTTP GET
CURLINFO_PAUSE_STATE
CURLPAUSE_RECV
CURLPAUSE_SEND
chunked Transfer-Encoding
DELAY
</keywords>
</info>
# Server-side
<reply>
<data>
HTTP/1.1 200 OK swsclose%CR
Transfer-Encoding: chunked%CR
%CR
4%CR
data%CR
5%CR
d474
%CR
0%CR
%CR
</data>
<datacheck>
Got bytes but pausing!
datad474
</datacheck>
<servercmd>
writedelay: 10
</servercmd>
</reply>
# Client-side
<client>
<server>
http
</server>
<tool>
lib%TESTNUMBER
</tool>
<name>
CURLINFO_PAUSE_STATE during paused transfer
</name>
<command>
http://%HOSTIP:%HTTPPORT/%TESTNUMBER
</command>
</client>
# Verify data after the test has been "shot"
<verify>
<protocol crlf="headers">
GET /%TESTNUMBER HTTP/1.1
Host: %HOSTIP:%HTTPPORT
Accept: */*
</protocol>
</verify>
</testcase>

View file

@ -125,4 +125,5 @@ TESTS_C = \
lib3010.c lib3025.c lib3026.c lib3027.c lib3033.c lib3034.c \
lib3100.c lib3101.c lib3102.c lib3103.c lib3104.c lib3105.c \
lib3207.c lib3208.c \
lib3403.c \
lib5000.c lib5004.c

162
tests/libtest/lib3403.c Normal file
View file

@ -0,0 +1,162 @@
/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 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.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.
*
* SPDX-License-Identifier: curl
*
***************************************************************************/
#include "first.h"
#include "testtrace.h"
struct t3403_state {
CURL *curl;
int errors;
int write_calls;
int xfer_while_recv_paused;
int checked_unpaused;
int checked_send_paused;
};
static int check_pause_state(struct t3403_state *st, long expected,
const char *label)
{
long state = -1;
CURLcode result = curl_easy_getinfo(st->curl, CURLINFO_PAUSE_STATE, &state);
if(result != CURLE_OK) {
curl_mfprintf(stderr, "%s: getinfo failed (%d)\n", label, (int)result);
st->errors++;
return 1;
}
if(state != expected) {
curl_mfprintf(stderr, "%s: expected %ld, got %ld\n",
label, expected, state);
st->errors++;
return 1;
}
curl_mfprintf(stderr, "%s: pause state %ld OK\n", label, state);
return 0;
}
static int t3403_xferinfo(void *userp,
curl_off_t dltotal,
curl_off_t dlnow,
curl_off_t ultotal,
curl_off_t ulnow)
{
struct t3403_state *st = (struct t3403_state *)userp;
(void)dltotal;
(void)dlnow;
(void)ultotal;
(void)ulnow;
if(st->write_calls == 1 && !st->xfer_while_recv_paused) {
st->xfer_while_recv_paused = 1;
check_pause_state(st, CURLPAUSE_RECV, "recv paused via write callback");
curl_easy_pause(st->curl, CURLPAUSE_CONT);
return 0;
}
if(st->write_calls >= 2 && !st->checked_unpaused) {
st->checked_unpaused = 1;
check_pause_state(st, 0, "unpaused after CONT");
curl_easy_pause(st->curl, CURLPAUSE_SEND);
return 0;
}
if(st->checked_unpaused && !st->checked_send_paused) {
st->checked_send_paused = 1;
check_pause_state(st, CURLPAUSE_SEND, "send paused explicitly");
curl_easy_pause(st->curl, CURLPAUSE_CONT);
}
return 0;
}
static size_t t3403_write_cb(char *ptr, size_t size, size_t nmemb, void *userp)
{
struct t3403_state *st = (struct t3403_state *)userp;
size_t len = size * nmemb;
st->write_calls++;
if(st->write_calls == 1) {
if(len)
curl_mprintf("Got bytes but pausing!\n");
return CURL_WRITEFUNC_PAUSE;
}
fwrite(ptr, size, nmemb, stdout);
return len;
}
static CURLcode test_lib3403(const char *URL)
{
CURL *curl = NULL;
CURLcode result = CURLE_OK;
struct t3403_state st;
start_test_timing();
memset(&st, 0, sizeof(st));
global_init(CURL_GLOBAL_ALL);
easy_init(curl);
st.curl = curl;
check_pause_state(&st, 0, "before transfer");
easy_setopt(curl, CURLOPT_URL, URL);
easy_setopt(curl, CURLOPT_WRITEFUNCTION, t3403_write_cb);
easy_setopt(curl, CURLOPT_WRITEDATA, &st);
easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, t3403_xferinfo);
easy_setopt(curl, CURLOPT_XFERINFODATA, &st);
easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
debug_config.nohex = TRUE;
debug_config.tracetime = TRUE;
easy_setopt(curl, CURLOPT_DEBUGDATA, &debug_config);
easy_setopt(curl, CURLOPT_DEBUGFUNCTION, libtest_debug_cb);
easy_setopt(curl, CURLOPT_VERBOSE, 1L);
result = curl_easy_perform(curl);
check_pause_state(&st, 0, "after transfer");
if(!st.xfer_while_recv_paused || !st.checked_unpaused ||
!st.checked_send_paused) {
curl_mfprintf(stderr, "missing pause state checks "
"(recv=%d unpaused=%d send=%d)\n",
st.xfer_while_recv_paused, st.checked_unpaused,
st.checked_send_paused);
st.errors++;
}
if(st.errors)
result = TEST_ERR_FAILURE;
test_cleanup:
curl_easy_cleanup(curl);
curl_global_cleanup();
return result;
}