In C++, I want to use libcurl to check that a URL is text/html, and if yes, to then download the body, else it stops.
I want this todo in one step, not first sending HEAD, if HEAD is ok, requesting the page again to download.
If this is not possible with libcurl, does it give other libaries for C++, which would support this?
To send a HTTP HEAD request, you need to set this option up:
curl_easy_setopt(ctx,CURLOPT_NOBODY ,1 );
and you can also have a look at this question: help needed on libcurl programming in sending HTTP HEAD Request
to separate headers from body (don't know if it is really needed), you can have a look at :
http://curl.haxx.se/libcurl/c/sepheaders.html
to download lot of different URLs libcurl-multi, you should have a look at :
http://curl.haxx.se/libcurl/c/libcurl-multi.html
slight modification of http://curl.haxx.se/libcurl/c/sendrecv.html:
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
/* Auxiliary function that waits on the socket. */
static int wait_on_socket(curl_socket_t sockfd, int for_recv, long timeout_ms)
{
struct timeval tv;
fd_set infd, outfd, errfd;
int res;
tv.tv_sec = timeout_ms / 1000;
tv.tv_usec= (timeout_ms % 1000) * 1000;
FD_ZERO(&infd);
FD_ZERO(&outfd);
FD_ZERO(&errfd);
FD_SET(sockfd, &errfd); /* always check for error */
if(for_recv)
{
FD_SET(sockfd, &infd);
}
else
{
FD_SET(sockfd, &outfd);
}
/* select() returns the number of signalled sockets or -1 */
res = select(sockfd + 1, &infd, &outfd, &errfd, &tv);
return res;
}
int main(void)
{
CURL *curl;
CURLcode res;
/* Minimalistic http request */
const char *request = "GET / HTTP/1.0\r\nHost: m0g.net\r\n\r\n";
curl_socket_t sockfd; /* socket */
long sockextr;
size_t iolen;
curl_off_t nread;
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "http://m0g.net");
/* Do not do the transfer - only connect to host */
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)
{
printf("Error: %s\n", curl_easy_strerror(res));
return 1;
}
sockfd = sockextr;
/* 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)
{
printf("Error: %s\n", curl_easy_strerror(res));
return 1;
}
puts("Reading response.");
char data[2048];
int idxread=0;
/* read the response */
for(;;)
{
char buf[1024];
wait_on_socket(sockfd, 1, 60000L);
res = curl_easy_recv(curl, buf, 32, &iolen);
if(CURLE_OK != res)
break;
if (nread+idxread > 2048)
break;
strncpy(data+idxread,buf,nread);
idxread+=nread;
if (strstr(data,"\r\n\r\n") != NULL) {
if (strstr(data,"Content-Type: text/html") == NULL) {
printf("not an html document.");
return 2;
}
}
nread = (curl_off_t)iolen;
printf("Received %" CURL_FORMAT_CURL_OFF_T " bytes.\n", nread);
}
printf("'''%s'''\n", data);
/* always cleanup */
curl_easy_cleanup(curl);
}
return 0;
}
This is a few years late, but here's an alternative way of doing this proposed by Linus Nielsen Feltzing, the original author of cURL.
#include <curl/curl.h>
int main(int argc, char *argv[])
{
CURLcode ret;
CURL *hnd = curl_easy_init();
curl_easy_setopt(hnd, CURLOPT_URL, "http://www.haxx.se");
curl_easy_setopt(hnd, CURLOPT_HEADER, 1);
curl_easy_setopt(hnd, CURLOPT_NOBODY, 1);
ret = curl_easy_perform(hnd);
curl_easy_cleanup(hnd);
}
Linus proposed this in a 2007 thread on the curl-library
mailing list.