mirror of
https://github.com/moparisthebest/curl
synced 2024-12-21 15:48:49 -05:00
curl_easy_recv: Improve documentation and example program
Follow-up to 82245ea
: Fix the example program sendrecv.c (handle
CURLE_AGAIN, handle incomplete send). Improve the documentation
for curl_easy_recv() and curl_easy_send().
Reviewed-by: Frank Meier
Assisted-by: Jay Satiro
See https://github.com/curl/curl/pull/1134
This commit is contained in:
parent
82245eaa56
commit
afff64dbcd
@ -62,10 +62,9 @@ int main(void)
|
||||
CURLcode res;
|
||||
/* Minimalistic http request */
|
||||
const char *request = "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n";
|
||||
curl_socket_t sockfd; /* socket */
|
||||
long sockextr;
|
||||
size_t iolen;
|
||||
curl_off_t nread;
|
||||
size_t request_len = strlen(request);
|
||||
curl_socket_t sockfd;
|
||||
size_t nsent_total = 0;
|
||||
|
||||
/* A general note of caution here: if you're using curl_easy_recv() or
|
||||
curl_easy_send() to implement HTTP or _any_ other protocol libcurl
|
||||
@ -82,54 +81,76 @@ int main(void)
|
||||
curl_easy_setopt(curl, CURLOPT_CONNECT_ONLY, 1L);
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
if(CURLE_OK != res) {
|
||||
printf("Error: %s\n", strerror(res));
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Extract the socket from the curl handle - we'll need it for waiting.
|
||||
* Note that this API takes a pointer to a 'long' while we use
|
||||
* curl_socket_t for sockets otherwise.
|
||||
*/
|
||||
res = curl_easy_getinfo(curl, CURLINFO_LASTSOCKET, &sockextr);
|
||||
|
||||
if(CURLE_OK != res) {
|
||||
if(res != CURLE_OK) {
|
||||
printf("Error: %s\n", curl_easy_strerror(res));
|
||||
return 1;
|
||||
}
|
||||
|
||||
sockfd = (curl_socket_t)sockextr;
|
||||
/* Extract the socket from the curl handle - we'll need it for waiting. */
|
||||
res = curl_easy_getinfo(curl, CURLINFO_ACTIVESOCKET, &sockfd);
|
||||
|
||||
/* wait for the socket to become ready for sending */
|
||||
if(!wait_on_socket(sockfd, 0, 60000L)) {
|
||||
printf("Error: timeout.\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
puts("Sending request.");
|
||||
/* Send the request. Real applications should check the iolen
|
||||
* to see if all the request has been sent */
|
||||
res = curl_easy_send(curl, request, strlen(request), &iolen);
|
||||
|
||||
if(CURLE_OK != res) {
|
||||
if(res != CURLE_OK) {
|
||||
printf("Error: %s\n", curl_easy_strerror(res));
|
||||
return 1;
|
||||
}
|
||||
puts("Reading response.");
|
||||
|
||||
/* read the response */
|
||||
printf("Sending request.\n");
|
||||
|
||||
do {
|
||||
/* Warning: This example program may loop indefinitely.
|
||||
* A production-quality program must define a timeout and exit this loop
|
||||
* as soon as the timeout has expired. */
|
||||
size_t nsent;
|
||||
do {
|
||||
nsent = 0;
|
||||
res = curl_easy_send(curl, request + nsent_total,
|
||||
request_len - nsent_total, &nsent);
|
||||
nsent_total += nsent;
|
||||
|
||||
if(res == CURLE_AGAIN && !wait_on_socket(sockfd, 0, 60000L)) {
|
||||
printf("Error: timeout.\n");
|
||||
return 1;
|
||||
}
|
||||
} while(res == CURLE_AGAIN);
|
||||
|
||||
if(res != CURLE_OK) {
|
||||
printf("Error: %s\n", curl_easy_strerror(res));
|
||||
return 1;
|
||||
}
|
||||
|
||||
printf("Sent %" CURL_FORMAT_CURL_OFF_T " bytes.\n",
|
||||
(curl_off_t)nsent);
|
||||
|
||||
} while(nsent_total < request_len);
|
||||
|
||||
printf("Reading response.\n");
|
||||
|
||||
for(;;) {
|
||||
/* Warning: This example program may loop indefinitely (see above). */
|
||||
char buf[1024];
|
||||
size_t nread;
|
||||
do {
|
||||
nread = 0;
|
||||
res = curl_easy_recv(curl, buf, sizeof(buf), &nread);
|
||||
|
||||
wait_on_socket(sockfd, 1, 60000L);
|
||||
res = curl_easy_recv(curl, buf, 1024, &iolen);
|
||||
if(res == CURLE_AGAIN && !wait_on_socket(sockfd, 1, 60000L)) {
|
||||
printf("Error: timeout.\n");
|
||||
return 1;
|
||||
}
|
||||
} while(res == CURLE_AGAIN);
|
||||
|
||||
if(CURLE_OK != res)
|
||||
if(res != CURLE_OK) {
|
||||
printf("Error: %s\n", curl_easy_strerror(res));
|
||||
break;
|
||||
}
|
||||
|
||||
nread = (curl_off_t)iolen;
|
||||
if(nread == 0) {
|
||||
/* end of the response */
|
||||
break;
|
||||
}
|
||||
|
||||
printf("Received %" CURL_FORMAT_CURL_OFF_T " bytes.\n", nread);
|
||||
printf("Received %" CURL_FORMAT_CURL_OFF_T " bytes.\n",
|
||||
(curl_off_t)nread);
|
||||
}
|
||||
|
||||
/* always cleanup */
|
||||
|
@ -46,12 +46,21 @@ calling \fIcurl_easy_perform(3)\fP or \fIcurl_multi_perform(3)\fP. Note that
|
||||
\fIcurl_easy_recv(3)\fP does not work on connections that were created without
|
||||
this option.
|
||||
|
||||
You must ensure that the socket has data to read before calling
|
||||
\fIcurl_easy_recv(3)\fP, otherwise the call will return \fBCURLE_AGAIN\fP -
|
||||
the socket is used in non-blocking mode internally. Use
|
||||
\fIcurl_easy_getinfo(3)\fP with \fICURLINFO_ACTIVESOCKET(3)\fP to obtain the
|
||||
socket; use your operating system facilities like \fIselect(2)\fP to check if
|
||||
it has any data you can read.
|
||||
The call will return \fBCURLE_AGAIN\fP if there is no data to read - the
|
||||
socket is used in non-blocking mode internally. When \fBCURLE_AGAIN\fP is
|
||||
returned, use your operating system facilities like \fIselect(2)\fP to wait
|
||||
for data. The socket may be obtained using \fIcurl_easy_getinfo(3)\fP with
|
||||
\fICURLINFO_ACTIVESOCKET(3)\fP.
|
||||
|
||||
Wait on the socket only if \fIcurl_easy_recv(3)\fP returns \fBCURLE_AGAIN\fP.
|
||||
The reason for this is libcurl or the SSL library may internally cache some
|
||||
data, therefore you should call \fIcurl_easy_recv(3)\fP until all data is
|
||||
read which would include any cached data.
|
||||
|
||||
Furthermore if you wait on the socket and it tells you there is data to read,
|
||||
\fIcurl_easy_recv(3)\fP may return \fBCURLE_AGAIN\fP if the only data that was
|
||||
read was for internal SSL processing, and no other data is available.
|
||||
|
||||
.SH AVAILABILITY
|
||||
Added in 7.18.2.
|
||||
.SH RETURN VALUE
|
||||
@ -60,13 +69,13 @@ On success, returns \fBCURLE_OK\fP, stores the received data into
|
||||
|
||||
On failure, returns the appropriate error code.
|
||||
|
||||
If there is no data to read, the function returns \fBCURLE_AGAIN\fP. Use your
|
||||
operating system facilities to wait until the data is ready, and retry.
|
||||
The function may return \fBCURLE_AGAIN\fP. In this case, use your operating
|
||||
system facilities to wait until data can be read, and retry.
|
||||
|
||||
Reading exactly 0 bytes would indicate a closed connection.
|
||||
Reading exactly 0 bytes indicates a closed connection.
|
||||
|
||||
If there's no socket available to use from the previous transfer, this function
|
||||
returns CURLE_UNSUPPORTED_PROTOCOL.
|
||||
returns \fBCURLE_UNSUPPORTED_PROTOCOL\fP.
|
||||
.SH EXAMPLE
|
||||
See \fBsendrecv.c\fP in \fBdocs/examples\fP directory for usage example.
|
||||
.SH "SEE ALSO"
|
||||
|
@ -40,16 +40,20 @@ connection set-up.
|
||||
The variable \fBn\fP points to will receive the number of sent bytes.
|
||||
|
||||
To establish the connection, set \fICURLOPT_CONNECT_ONLY(3)\fP option before
|
||||
calling \fIcurl_easy_perform(3)\fP or \fIcurl_multi_perform()\fP. Note that
|
||||
calling \fIcurl_easy_perform(3)\fP or \fIcurl_multi_perform(3)\fP. Note that
|
||||
\fIcurl_easy_send(3)\fP will not work on connections that were created without
|
||||
this option.
|
||||
|
||||
You must ensure that the socket is writable before calling
|
||||
\fIcurl_easy_send(3)\fP, otherwise the call will return \fBCURLE_AGAIN\fP -
|
||||
the socket is used in non-blocking mode internally. Use
|
||||
\fIcurl_easy_getinfo(3)\fP with \fICURLINFO_ACTIVESOCKET(3)\fP to obtain the
|
||||
socket; use your operating system facilities like \fIselect(2)\fP to check if
|
||||
it can be written to.
|
||||
The call will return \fBCURLE_AGAIN\fP if it's not possible to send data right
|
||||
now - the socket is used in non-blocking mode internally. When
|
||||
\fBCURLE_AGAIN\fP is returned, use your operating system facilities like
|
||||
\fIselect(2)\fP to wait until the socket is writable. The socket may be
|
||||
obtained using \fIcurl_easy_getinfo(3)\fP with \fICURLINFO_ACTIVESOCKET(3)\fP.
|
||||
|
||||
Furthermore if you wait on the socket and it tells you it's writable,
|
||||
\fIcurl_easy_send(3)\fP may return \fBCURLE_AGAIN\fP if the only data that was
|
||||
sent was for internal SSL processing, and no other data could be sent.
|
||||
|
||||
.SH AVAILABILITY
|
||||
Added in 7.18.2.
|
||||
.SH RETURN VALUE
|
||||
@ -59,8 +63,11 @@ wanted to send.
|
||||
|
||||
On failure, returns the appropriate error code.
|
||||
|
||||
This function may return \fBCURLE_AGAIN\fP. In this case, use your operating
|
||||
system facilities to wait until the socket is writable, and retry.
|
||||
|
||||
If there's no socket available to use from the previous transfer, this function
|
||||
returns CURLE_UNSUPPORTED_PROTOCOL.
|
||||
returns \fBCURLE_UNSUPPORTED_PROTOCOL\fP.
|
||||
.SH EXAMPLE
|
||||
See \fBsendrecv.c\fP in \fBdocs/examples\fP directory for usage example.
|
||||
.SH "SEE ALSO"
|
||||
|
@ -49,3 +49,4 @@ Added in 7.15.2
|
||||
Returns CURLE_OK if the option is supported, and CURLE_UNKNOWN_OPTION if not.
|
||||
.SH "SEE ALSO"
|
||||
.BR CURLOPT_VERBOSE "(3), " CURLOPT_HTTPPROXYTUNNEL "(3), "
|
||||
.BR curl_easy_recv "(3), " curl_easy_send "(3) "
|
||||
|
@ -8,7 +8,7 @@ HTTP GET
|
||||
|
||||
<reply>
|
||||
<data>
|
||||
HTTP/1.1 200 OK
|
||||
HTTP/1.1 200 OK swsclose
|
||||
Server: test-server/fake
|
||||
Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
|
||||
Content-Length: 6
|
||||
|
@ -77,11 +77,10 @@ int test(char *URL)
|
||||
|
||||
if(!res) {
|
||||
/* we assume that sending always work */
|
||||
size_t total=0;
|
||||
|
||||
do {
|
||||
/* busy-read like crazy */
|
||||
res = curl_easy_recv(curl, buf, 1024, &iolen);
|
||||
res = curl_easy_recv(curl, buf, sizeof(buf), &iolen);
|
||||
|
||||
#ifdef TPF
|
||||
sleep(1); /* avoid ctl-10 dump */
|
||||
@ -92,10 +91,12 @@ int test(char *URL)
|
||||
if(!write(STDOUT_FILENO, buf, iolen))
|
||||
break;
|
||||
}
|
||||
total += iolen;
|
||||
|
||||
} while(((res == CURLE_OK) || (res == CURLE_AGAIN)) && (total < 129));
|
||||
} while((res == CURLE_OK && iolen != 0) || (res == CURLE_AGAIN));
|
||||
}
|
||||
|
||||
if(res != CURLE_OK || iolen != 0)
|
||||
return TEST_ERR_FAILURE;
|
||||
}
|
||||
|
||||
test_cleanup:
|
||||
|
Loading…
Reference in New Issue
Block a user