cfilters.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663
  1. /***************************************************************************
  2. * _ _ ____ _
  3. * Project ___| | | | _ \| |
  4. * / __| | | | |_) | |
  5. * | (__| |_| | _ <| |___
  6. * \___|\___/|_| \_\_____|
  7. *
  8. * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
  9. *
  10. * This software is licensed as described in the file COPYING, which
  11. * you should have received as part of this distribution. The terms
  12. * are also available at https://curl.se/docs/copyright.html.
  13. *
  14. * You may opt to use, copy, modify, merge, publish, distribute and/or sell
  15. * copies of the Software, and permit persons to whom the Software is
  16. * furnished to do so, under the terms of the COPYING file.
  17. *
  18. * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
  19. * KIND, either express or implied.
  20. *
  21. * SPDX-License-Identifier: curl
  22. *
  23. ***************************************************************************/
  24. #include "curl_setup.h"
  25. #include "urldata.h"
  26. #include "strerror.h"
  27. #include "cfilters.h"
  28. #include "connect.h"
  29. #include "url.h" /* for Curl_safefree() */
  30. #include "sendf.h"
  31. #include "sockaddr.h" /* required for Curl_sockaddr_storage */
  32. #include "multiif.h"
  33. #include "progress.h"
  34. #include "warnless.h"
  35. /* The last 3 #include files should be in this order */
  36. #include "curl_printf.h"
  37. #include "curl_memory.h"
  38. #include "memdebug.h"
  39. #ifndef ARRAYSIZE
  40. #define ARRAYSIZE(A) (sizeof(A)/sizeof((A)[0]))
  41. #endif
  42. void Curl_cf_def_destroy_this(struct Curl_cfilter *cf, struct Curl_easy *data)
  43. {
  44. (void)cf;
  45. (void)data;
  46. }
  47. void Curl_cf_def_close(struct Curl_cfilter *cf, struct Curl_easy *data)
  48. {
  49. cf->connected = FALSE;
  50. if(cf->next)
  51. cf->next->cft->close(cf->next, data);
  52. }
  53. CURLcode Curl_cf_def_connect(struct Curl_cfilter *cf,
  54. struct Curl_easy *data,
  55. bool blocking, bool *done)
  56. {
  57. CURLcode result;
  58. if(cf->connected) {
  59. *done = TRUE;
  60. return CURLE_OK;
  61. }
  62. if(cf->next) {
  63. result = cf->next->cft->connect(cf->next, data, blocking, done);
  64. if(!result && *done) {
  65. cf->connected = TRUE;
  66. }
  67. return result;
  68. }
  69. *done = FALSE;
  70. return CURLE_FAILED_INIT;
  71. }
  72. void Curl_cf_def_get_host(struct Curl_cfilter *cf, struct Curl_easy *data,
  73. const char **phost, const char **pdisplay_host,
  74. int *pport)
  75. {
  76. if(cf->next)
  77. cf->next->cft->get_host(cf->next, data, phost, pdisplay_host, pport);
  78. else {
  79. *phost = cf->conn->host.name;
  80. *pdisplay_host = cf->conn->host.dispname;
  81. *pport = cf->conn->port;
  82. }
  83. }
  84. int Curl_cf_def_get_select_socks(struct Curl_cfilter *cf,
  85. struct Curl_easy *data,
  86. curl_socket_t *socks)
  87. {
  88. return cf->next?
  89. cf->next->cft->get_select_socks(cf->next, data, socks) : 0;
  90. }
  91. bool Curl_cf_def_data_pending(struct Curl_cfilter *cf,
  92. const struct Curl_easy *data)
  93. {
  94. return cf->next?
  95. cf->next->cft->has_data_pending(cf->next, data) : FALSE;
  96. }
  97. ssize_t Curl_cf_def_send(struct Curl_cfilter *cf, struct Curl_easy *data,
  98. const void *buf, size_t len, CURLcode *err)
  99. {
  100. return cf->next?
  101. cf->next->cft->do_send(cf->next, data, buf, len, err) :
  102. CURLE_RECV_ERROR;
  103. }
  104. ssize_t Curl_cf_def_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
  105. char *buf, size_t len, CURLcode *err)
  106. {
  107. return cf->next?
  108. cf->next->cft->do_recv(cf->next, data, buf, len, err) :
  109. CURLE_SEND_ERROR;
  110. }
  111. bool Curl_cf_def_conn_is_alive(struct Curl_cfilter *cf,
  112. struct Curl_easy *data,
  113. bool *input_pending)
  114. {
  115. return cf->next?
  116. cf->next->cft->is_alive(cf->next, data, input_pending) :
  117. FALSE; /* pessimistic in absence of data */
  118. }
  119. CURLcode Curl_cf_def_conn_keep_alive(struct Curl_cfilter *cf,
  120. struct Curl_easy *data)
  121. {
  122. return cf->next?
  123. cf->next->cft->keep_alive(cf->next, data) :
  124. CURLE_OK;
  125. }
  126. CURLcode Curl_cf_def_query(struct Curl_cfilter *cf,
  127. struct Curl_easy *data,
  128. int query, int *pres1, void *pres2)
  129. {
  130. return cf->next?
  131. cf->next->cft->query(cf->next, data, query, pres1, pres2) :
  132. CURLE_UNKNOWN_OPTION;
  133. }
  134. void Curl_conn_cf_discard_chain(struct Curl_cfilter **pcf,
  135. struct Curl_easy *data)
  136. {
  137. struct Curl_cfilter *cfn, *cf = *pcf;
  138. if(cf) {
  139. *pcf = NULL;
  140. while(cf) {
  141. cfn = cf->next;
  142. /* prevent destroying filter to mess with its sub-chain, since
  143. * we have the reference now and will call destroy on it.
  144. */
  145. cf->next = NULL;
  146. cf->cft->destroy(cf, data);
  147. free(cf);
  148. cf = cfn;
  149. }
  150. }
  151. }
  152. void Curl_conn_cf_discard_all(struct Curl_easy *data,
  153. struct connectdata *conn, int index)
  154. {
  155. Curl_conn_cf_discard_chain(&conn->cfilter[index], data);
  156. }
  157. void Curl_conn_close(struct Curl_easy *data, int index)
  158. {
  159. struct Curl_cfilter *cf;
  160. DEBUGASSERT(data->conn);
  161. /* it is valid to call that without filters being present */
  162. cf = data->conn->cfilter[index];
  163. if(cf) {
  164. cf->cft->close(cf, data);
  165. }
  166. }
  167. ssize_t Curl_conn_recv(struct Curl_easy *data, int num, char *buf,
  168. size_t len, CURLcode *code)
  169. {
  170. struct Curl_cfilter *cf;
  171. DEBUGASSERT(data);
  172. DEBUGASSERT(data->conn);
  173. cf = data->conn->cfilter[num];
  174. while(cf && !cf->connected) {
  175. cf = cf->next;
  176. }
  177. if(cf) {
  178. return cf->cft->do_recv(cf, data, buf, len, code);
  179. }
  180. failf(data, CMSGI(data->conn, num, "recv: no filter connected"));
  181. *code = CURLE_FAILED_INIT;
  182. return -1;
  183. }
  184. ssize_t Curl_conn_send(struct Curl_easy *data, int num,
  185. const void *mem, size_t len, CURLcode *code)
  186. {
  187. struct Curl_cfilter *cf;
  188. DEBUGASSERT(data);
  189. DEBUGASSERT(data->conn);
  190. cf = data->conn->cfilter[num];
  191. while(cf && !cf->connected) {
  192. cf = cf->next;
  193. }
  194. if(cf) {
  195. return cf->cft->do_send(cf, data, mem, len, code);
  196. }
  197. failf(data, CMSGI(data->conn, num, "send: no filter connected"));
  198. DEBUGASSERT(0);
  199. *code = CURLE_FAILED_INIT;
  200. return -1;
  201. }
  202. CURLcode Curl_cf_create(struct Curl_cfilter **pcf,
  203. const struct Curl_cftype *cft,
  204. void *ctx)
  205. {
  206. struct Curl_cfilter *cf;
  207. CURLcode result = CURLE_OUT_OF_MEMORY;
  208. DEBUGASSERT(cft);
  209. cf = calloc(sizeof(*cf), 1);
  210. if(!cf)
  211. goto out;
  212. cf->cft = cft;
  213. cf->ctx = ctx;
  214. result = CURLE_OK;
  215. out:
  216. *pcf = cf;
  217. return result;
  218. }
  219. void Curl_conn_cf_add(struct Curl_easy *data,
  220. struct connectdata *conn,
  221. int index,
  222. struct Curl_cfilter *cf)
  223. {
  224. (void)data;
  225. DEBUGASSERT(conn);
  226. DEBUGASSERT(!cf->conn);
  227. DEBUGASSERT(!cf->next);
  228. cf->next = conn->cfilter[index];
  229. cf->conn = conn;
  230. cf->sockindex = index;
  231. conn->cfilter[index] = cf;
  232. DEBUGF(LOG_CF(data, cf, "added"));
  233. }
  234. void Curl_conn_cf_insert_after(struct Curl_cfilter *cf_at,
  235. struct Curl_cfilter *cf_new)
  236. {
  237. struct Curl_cfilter *tail, **pnext;
  238. DEBUGASSERT(cf_at);
  239. DEBUGASSERT(cf_new);
  240. DEBUGASSERT(!cf_new->conn);
  241. tail = cf_at->next;
  242. cf_at->next = cf_new;
  243. do {
  244. cf_new->conn = cf_at->conn;
  245. cf_new->sockindex = cf_at->sockindex;
  246. pnext = &cf_new->next;
  247. cf_new = cf_new->next;
  248. } while(cf_new);
  249. *pnext = tail;
  250. }
  251. void Curl_conn_cf_discard(struct Curl_cfilter *cf, struct Curl_easy *data)
  252. {
  253. struct Curl_cfilter **pprev = &cf->conn->cfilter[cf->sockindex];
  254. /* remove from chain if still in there */
  255. DEBUGASSERT(cf);
  256. while (*pprev) {
  257. if (*pprev == cf) {
  258. *pprev = cf->next;
  259. break;
  260. }
  261. pprev = &((*pprev)->next);
  262. }
  263. cf->cft->destroy(cf, data);
  264. free(cf);
  265. }
  266. CURLcode Curl_conn_cf_connect(struct Curl_cfilter *cf,
  267. struct Curl_easy *data,
  268. bool blocking, bool *done)
  269. {
  270. if(cf)
  271. return cf->cft->connect(cf, data, blocking, done);
  272. return CURLE_FAILED_INIT;
  273. }
  274. void Curl_conn_cf_close(struct Curl_cfilter *cf, struct Curl_easy *data)
  275. {
  276. if(cf)
  277. cf->cft->close(cf, data);
  278. }
  279. int Curl_conn_cf_get_select_socks(struct Curl_cfilter *cf,
  280. struct Curl_easy *data,
  281. curl_socket_t *socks)
  282. {
  283. if(cf)
  284. return cf->cft->get_select_socks(cf, data, socks);
  285. return 0;
  286. }
  287. bool Curl_conn_cf_data_pending(struct Curl_cfilter *cf,
  288. const struct Curl_easy *data)
  289. {
  290. if(cf)
  291. return cf->cft->has_data_pending(cf, data);
  292. return FALSE;
  293. }
  294. ssize_t Curl_conn_cf_send(struct Curl_cfilter *cf, struct Curl_easy *data,
  295. const void *buf, size_t len, CURLcode *err)
  296. {
  297. if(cf)
  298. return cf->cft->do_send(cf, data, buf, len, err);
  299. *err = CURLE_SEND_ERROR;
  300. return -1;
  301. }
  302. ssize_t Curl_conn_cf_recv(struct Curl_cfilter *cf, struct Curl_easy *data,
  303. char *buf, size_t len, CURLcode *err)
  304. {
  305. if(cf)
  306. return cf->cft->do_recv(cf, data, buf, len, err);
  307. *err = CURLE_RECV_ERROR;
  308. return -1;
  309. }
  310. CURLcode Curl_conn_connect(struct Curl_easy *data,
  311. int sockindex,
  312. bool blocking,
  313. bool *done)
  314. {
  315. struct Curl_cfilter *cf;
  316. CURLcode result = CURLE_OK;
  317. DEBUGASSERT(data);
  318. DEBUGASSERT(data->conn);
  319. cf = data->conn->cfilter[sockindex];
  320. DEBUGASSERT(cf);
  321. if(!cf)
  322. return CURLE_FAILED_INIT;
  323. *done = cf->connected;
  324. if(!*done) {
  325. result = cf->cft->connect(cf, data, blocking, done);
  326. if(!result && *done) {
  327. Curl_conn_ev_update_info(data, data->conn);
  328. Curl_conn_report_connect_stats(data, data->conn);
  329. data->conn->keepalive = Curl_now();
  330. }
  331. else if(result) {
  332. Curl_conn_report_connect_stats(data, data->conn);
  333. }
  334. }
  335. return result;
  336. }
  337. bool Curl_conn_is_connected(struct connectdata *conn, int sockindex)
  338. {
  339. struct Curl_cfilter *cf;
  340. cf = conn->cfilter[sockindex];
  341. return cf && cf->connected;
  342. }
  343. bool Curl_conn_is_ip_connected(struct Curl_easy *data, int sockindex)
  344. {
  345. struct Curl_cfilter *cf;
  346. cf = data->conn->cfilter[sockindex];
  347. while(cf) {
  348. if(cf->connected)
  349. return TRUE;
  350. if(cf->cft->flags & CF_TYPE_IP_CONNECT)
  351. return FALSE;
  352. cf = cf->next;
  353. }
  354. return FALSE;
  355. }
  356. bool Curl_conn_is_ssl(struct connectdata *conn, int sockindex)
  357. {
  358. struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL;
  359. for(; cf; cf = cf->next) {
  360. if(cf->cft->flags & CF_TYPE_SSL)
  361. return TRUE;
  362. if(cf->cft->flags & CF_TYPE_IP_CONNECT)
  363. return FALSE;
  364. }
  365. return FALSE;
  366. }
  367. bool Curl_conn_is_multiplex(struct connectdata *conn, int sockindex)
  368. {
  369. struct Curl_cfilter *cf = conn? conn->cfilter[sockindex] : NULL;
  370. for(; cf; cf = cf->next) {
  371. if(cf->cft->flags & CF_TYPE_MULTIPLEX)
  372. return TRUE;
  373. if(cf->cft->flags & CF_TYPE_IP_CONNECT
  374. || cf->cft->flags & CF_TYPE_SSL)
  375. return FALSE;
  376. }
  377. return FALSE;
  378. }
  379. bool Curl_conn_data_pending(struct Curl_easy *data, int sockindex)
  380. {
  381. struct Curl_cfilter *cf;
  382. (void)data;
  383. DEBUGASSERT(data);
  384. DEBUGASSERT(data->conn);
  385. cf = data->conn->cfilter[sockindex];
  386. while(cf && !cf->connected) {
  387. cf = cf->next;
  388. }
  389. if(cf) {
  390. return cf->cft->has_data_pending(cf, data);
  391. }
  392. return FALSE;
  393. }
  394. int Curl_conn_get_select_socks(struct Curl_easy *data, int sockindex,
  395. curl_socket_t *socks)
  396. {
  397. struct Curl_cfilter *cf;
  398. DEBUGASSERT(data);
  399. DEBUGASSERT(data->conn);
  400. cf = data->conn->cfilter[sockindex];
  401. /* if the next one is not yet connected, that's the one we want */
  402. while(cf && cf->next && !cf->next->connected)
  403. cf = cf->next;
  404. if(cf) {
  405. return cf->cft->get_select_socks(cf, data, socks);
  406. }
  407. return GETSOCK_BLANK;
  408. }
  409. void Curl_conn_get_host(struct Curl_easy *data, int sockindex,
  410. const char **phost, const char **pdisplay_host,
  411. int *pport)
  412. {
  413. struct Curl_cfilter *cf;
  414. DEBUGASSERT(data->conn);
  415. cf = data->conn->cfilter[sockindex];
  416. if(cf) {
  417. cf->cft->get_host(cf, data, phost, pdisplay_host, pport);
  418. }
  419. else {
  420. /* Some filter ask during shutdown for this, mainly for debugging
  421. * purposes. We hand out the defaults, however this is not always
  422. * accurate, as the connection might be tunneled, etc. But all that
  423. * state is already gone here. */
  424. *phost = data->conn->host.name;
  425. *pdisplay_host = data->conn->host.dispname;
  426. *pport = data->conn->remote_port;
  427. }
  428. }
  429. CURLcode Curl_cf_def_cntrl(struct Curl_cfilter *cf,
  430. struct Curl_easy *data,
  431. int event, int arg1, void *arg2)
  432. {
  433. (void)cf;
  434. (void)data;
  435. (void)event;
  436. (void)arg1;
  437. (void)arg2;
  438. return CURLE_OK;
  439. }
  440. CURLcode Curl_conn_cf_cntrl(struct Curl_cfilter *cf,
  441. struct Curl_easy *data,
  442. bool ignore_result,
  443. int event, int arg1, void *arg2)
  444. {
  445. CURLcode result = CURLE_OK;
  446. for(; cf; cf = cf->next) {
  447. if(Curl_cf_def_cntrl == cf->cft->cntrl)
  448. continue;
  449. result = cf->cft->cntrl(cf, data, event, arg1, arg2);
  450. if(!ignore_result && result)
  451. break;
  452. }
  453. return result;
  454. }
  455. curl_socket_t Curl_conn_cf_get_socket(struct Curl_cfilter *cf,
  456. struct Curl_easy *data)
  457. {
  458. curl_socket_t sock;
  459. if(cf && !cf->cft->query(cf, data, CF_QUERY_SOCKET, NULL, &sock))
  460. return sock;
  461. return CURL_SOCKET_BAD;
  462. }
  463. curl_socket_t Curl_conn_get_socket(struct Curl_easy *data, int sockindex)
  464. {
  465. struct Curl_cfilter *cf;
  466. cf = data->conn? data->conn->cfilter[sockindex] : NULL;
  467. /* if the top filter has not connected, ask it (and its sub-filters)
  468. * for the socket. Otherwise conn->sock[sockindex] should have it.
  469. */
  470. if(cf && !cf->connected)
  471. return Curl_conn_cf_get_socket(cf, data);
  472. return data->conn? data->conn->sock[sockindex] : CURL_SOCKET_BAD;
  473. }
  474. static CURLcode cf_cntrl_all(struct connectdata *conn,
  475. struct Curl_easy *data,
  476. bool ignore_result,
  477. int event, int arg1, void *arg2)
  478. {
  479. CURLcode result = CURLE_OK;
  480. size_t i;
  481. for(i = 0; i < ARRAYSIZE(conn->cfilter); ++i) {
  482. result = Curl_conn_cf_cntrl(conn->cfilter[i], data, ignore_result,
  483. event, arg1, arg2);
  484. if(!ignore_result && result)
  485. break;
  486. }
  487. return result;
  488. }
  489. void Curl_conn_ev_data_attach(struct connectdata *conn,
  490. struct Curl_easy *data)
  491. {
  492. cf_cntrl_all(conn, data, TRUE, CF_CTRL_DATA_ATTACH, 0, NULL);
  493. }
  494. void Curl_conn_ev_data_detach(struct connectdata *conn,
  495. struct Curl_easy *data)
  496. {
  497. cf_cntrl_all(conn, data, TRUE, CF_CTRL_DATA_DETACH, 0, NULL);
  498. }
  499. CURLcode Curl_conn_ev_data_setup(struct Curl_easy *data)
  500. {
  501. return cf_cntrl_all(data->conn, data, FALSE,
  502. CF_CTRL_DATA_SETUP, 0, NULL);
  503. }
  504. CURLcode Curl_conn_ev_data_idle(struct Curl_easy *data)
  505. {
  506. return cf_cntrl_all(data->conn, data, FALSE,
  507. CF_CTRL_DATA_IDLE, 0, NULL);
  508. }
  509. /**
  510. * Notify connection filters that the transfer represented by `data`
  511. * is donw with sending data (e.g. has uploaded everything).
  512. */
  513. void Curl_conn_ev_data_done_send(struct Curl_easy *data)
  514. {
  515. cf_cntrl_all(data->conn, data, TRUE, CF_CTRL_DATA_DONE_SEND, 0, NULL);
  516. }
  517. /**
  518. * Notify connection filters that the transfer represented by `data`
  519. * is finished - eventually premature, e.g. before being complete.
  520. */
  521. void Curl_conn_ev_data_done(struct Curl_easy *data, bool premature)
  522. {
  523. cf_cntrl_all(data->conn, data, TRUE, CF_CTRL_DATA_DONE, premature, NULL);
  524. }
  525. CURLcode Curl_conn_ev_data_pause(struct Curl_easy *data, bool do_pause)
  526. {
  527. return cf_cntrl_all(data->conn, data, FALSE,
  528. CF_CTRL_DATA_PAUSE, do_pause, NULL);
  529. }
  530. void Curl_conn_ev_update_info(struct Curl_easy *data,
  531. struct connectdata *conn)
  532. {
  533. cf_cntrl_all(conn, data, TRUE, CF_CTRL_CONN_INFO_UPDATE, 0, NULL);
  534. }
  535. void Curl_conn_report_connect_stats(struct Curl_easy *data,
  536. struct connectdata *conn)
  537. {
  538. struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET];
  539. if(cf) {
  540. struct curltime connected;
  541. struct curltime appconnected;
  542. memset(&connected, 0, sizeof(connected));
  543. cf->cft->query(cf, data, CF_QUERY_TIMER_CONNECT, NULL, &connected);
  544. if(connected.tv_sec || connected.tv_usec)
  545. Curl_pgrsTimeWas(data, TIMER_CONNECT, connected);
  546. memset(&appconnected, 0, sizeof(appconnected));
  547. cf->cft->query(cf, data, CF_QUERY_TIMER_APPCONNECT, NULL, &appconnected);
  548. if(appconnected.tv_sec || appconnected.tv_usec)
  549. Curl_pgrsTimeWas(data, TIMER_APPCONNECT, appconnected);
  550. }
  551. }
  552. bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn,
  553. bool *input_pending)
  554. {
  555. struct Curl_cfilter *cf = conn->cfilter[FIRSTSOCKET];
  556. return cf && !cf->conn->bits.close &&
  557. cf->cft->is_alive(cf, data, input_pending);
  558. }
  559. CURLcode Curl_conn_keep_alive(struct Curl_easy *data,
  560. struct connectdata *conn,
  561. int sockindex)
  562. {
  563. struct Curl_cfilter *cf = conn->cfilter[sockindex];
  564. return cf? cf->cft->keep_alive(cf, data) : CURLE_OK;
  565. }
  566. size_t Curl_conn_get_max_concurrent(struct Curl_easy *data,
  567. struct connectdata *conn,
  568. int sockindex)
  569. {
  570. CURLcode result;
  571. int n = 0;
  572. struct Curl_cfilter *cf = conn->cfilter[sockindex];
  573. result = cf? cf->cft->query(cf, data, CF_QUERY_MAX_CONCURRENT,
  574. &n, NULL) : CURLE_UNKNOWN_OPTION;
  575. return (result || n <= 0)? 1 : (size_t)n;
  576. }