I am trying to write a program in C to download some files.
The source code:
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
#include <curl/easy.h>
size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) {
size_t written;
written = fwrite(ptr, size, nmemb, stream);
return written;
}
int main(){
if(curl_global_init(CURL_GLOBAL_ALL)){
printf("curl error. Exiting.\n");
return 1;
}
char links[3][100] = {
"http://download.freeroms.com/nes_roms/08/big_nose_the_caveman.zip",
"http://download.freeroms.com/nes_roms/02/contra.zip",
"http://download.freeroms.com/nes_roms/08/super_mario_bros._(usajapan).zip"};
int n = 0, k = 0;
char *lastslash;
char* name;
CURL *handle = curl_easy_init();
CURLcode res;
FILE *file;
while(n<3){
lastslash = strrchr(links[n], '/');
name = lastslash ? lastslash + 1 : links[n];
printf("\nURL: %s\n", links[n]);
printf("Filename: %s\n", name);
curl_easy_setopt(handle, CURLOPT_URL, links[n]);
curl_easy_setopt(handle, CURLOPT_WRITEDATA, file);
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, write_data);
file = fopen(name, "wb");
res = curl_easy_perform(handle);
fclose(file);
n++;
}
curl_easy_cleanup(handle);
return 0;
}
I can compile it, but this is the output when I run it :
URL: http://download.freeroms.com/nes_roms/08/big_nose_the_caveman.zip
Filename: big_nose_the_caveman.zip
Segmentation fault (core dumped)
My compiler setting:
gcc dl.c -lcurl -o dl
I found out that the problem occurs when it tries to execute curl_easy_perform(), but I don't know what to do with it.
try this coding.
#include <stdio.h>
#include <curl/curl.h>
#include <curl/types.h>
#include <curl/easy.h>
#include <string>
size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) {
size_t written = fwrite(ptr, size, nmemb, stream);
return written;
}
int main(void) {
CURL *curl;
FILE *fp;
CURLcode res;
char *url = "http://localhost/aaa.txt";
char outfilename[FILENAME_MAX] = "C:\\bbb.txt";
curl = curl_easy_init();
if (curl) {
fp = fopen(outfilename,"wb");
curl_easy_setopt(curl, CURLOPT_URL, "http://localhost/aaa.txt");
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
res = curl_easy_perform(curl);
/* always cleanup */
curl_easy_cleanup(curl);
fclose(fp);
}
return 0;
}
You need to open the file before you set the callback data. The FILE* is stored by value, not reference.
file = fopen(name, "wb");
curl_easy_setopt(handle, CURLOPT_WRITEDATA, file);
Related
I write simple software to download image file from specific url. I using libcurl, i have this code:
#define CURL_STATICLIB
#include <stdio.h>
#include <curl/curl.h>
size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) {
size_t written;
written = fwrite(ptr, size, nmemb, stream);
return written;
}
int downloadFile() {
CURL *curl;
FILE *fp;
CURLcode res;
char *url = "http://www.example.eu/12.jpg";
char outfilename[FILENAME_MAX] = "D:\\12.jpg";
curl = curl_easy_init();
if (curl) {
fp = fopen(outfilename, "wb");
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
fclose(fp);
}
}
int main(void) {
downloadFile();
return 0;
}
When i build project i need copy dll file to project directory, because without him i have error. Is there any way to build an exe file with a built-in library? so to have the exe itself without having to attach another file?
I count on the fact that the file will be larger but for me it is a lot easier if I have 1 file, not a few, because as I add some files now I will have 1 exe and many dll files.
After compiling my program i get this error:
I'm using Code::Blocks.Program is written to be easy download manager. Problem occurs with all types of files (pdf,txt,jpg). Here's my code. I don't know why is it happening. Please help.
#define CURL_STATICLIB
#include <stdio.h>
#include <curl/curl.h>
#include <string.h>
size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream)
{
size_t written;
written = fwrite(ptr, size, nmemb, stream);
return written;
}
int main(void)
{
CURL *curl;
FILE *fp;
CURLcode res;
int x;
char y[200];
char page;
char* outfilename;
char* path_pdf = "/home/user/Desktop/document.pdf";
char* path_jpg = "/home/user/Desktop/picture.jpg";
char* path_txt = "/home/user/Desktop/document.txt";
char FILEPATH[3] = {path_pdf, path_jpg, path_txt};
printf("Enter file url: \n"); // for example http://oi58.tinypic.com/15nk3de.jpg
scanf ("%s",y);
char *url = y;
printf("Choose type of file:\n [0] - pdf\n [1] - jpg\n [2] - txt\n "); //choose 1
scanf("%d",&x);
outfilename = FILEPATH[x];
curl = curl_easy_init();
if (curl)
{
fp = fopen(outfilename,"wb");
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
curl_easy_setopt (curl, CURLOPT_VERBOSE, 1L);
res = curl_easy_perform(curl);
if (res == CURLE_OK)
{
printf("File downloaded!\n");
}
curl_easy_cleanup(curl);
fclose(fp);
}
return 0;
}
char FILEPATH[3] = {path_pdf, path_jpg, path_txt};
Is an array of char's (you want an array of strings), change to:
char *FILEPATH[3] = {path_pdf, path_jpg, path_txt};
I am developing on Linux platform. I am using libcurl and able to receive json response and saving it to file. Below is the code.
#include <curl/curl.h>
#include <curl/types.h>
#include <curl/easy.h>
#include <string.h>
#define URL "http://www.joes-hardware.com/tools.html"
size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) {
size_t written;
written = fwrite(ptr, size, nmemb, stream);
return written;
}
int main(void) {
CURL *curl;
FILE *fp;
CURLcode res;
//const char url[] = "http://www.joes-hardware.com/tools.html";
char *url= URL;
char outfilename[FILENAME_MAX] = "./json";
curl = curl_easy_init();
if (curl) {
fp = fopen(outfilename,"wb");
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
fclose(fp);
}
return 0;
}
Now I need to fetch a zip file from the server. Suppose the URL is of the format shown below:
#define URL "https://Server/File.zip"
For such URL, the code is not able to save the zip file.
How to achieve this?
I resolved the issue. The problem was with HTTPS connection. I had to add certificates for HTTPS.
Based on below links:
Can't connect to HTTPS site using cURL. Returns 0 length content instead
Getting no content from a HTTPS connection using CURL
#define CURL_STATICLIB
#include <stdio.h>
#include <curl/curl.h>
#include <curl/types.h>
#include <curl/easy.h>
#include <string.h>
#include <stdlib.h>
#define false 0
size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) {
size_t written;
written = fwrite(ptr, size, nmemb, stream);
return written;
}
int main(void) {
CURL *curl;
FILE *fp;
CURLcode res;
const char url[] = "https://example.com/filename.zip";
const char outfilename[FILENAME_MAX] = "./json.zip";
curl_version_info_data * vinfo = curl_version_info(CURLVERSION_NOW);
if(vinfo->features & CURL_VERSION_SSL){
printf("CURL: SSL enabled\n");
}else{
printf("CURL: SSL not enabled\n");
}
curl = curl_easy_init();
if (curl) {
fp = fopen(outfilename,"wb");
/* Setup the https:// verification options. Note we */
/* do this on all requests as there may be a redirect */
/* from http to https and we still want to verify */
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_CAINFO, "./ca-bundle.crt");
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, false);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
int i=fclose(fp);
if( i==0)
system("unzip -j json.zip");
}
return 0;
}
I have homework where I need somehow to compare two HTTP responses. I am writing it on C and I use libcurl to make things easier. I am calling the function that uses libcurl to do a HTTP request and response from another function, and I want to return the HTTP response as a char *. Here is my code so far (it crashes):
#include <stdio.h>
#include <curl/curl.h>
#include <string.h>
size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream) {
size_t written;
written = fwrite(ptr, size, nmemb, stream);
return written;
}
char *handle_url(void) {
CURL *curl;
char *fp;
CURLcode res;
char *url = "http://www.yahoo.com";
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
res = curl_easy_perform(curl);
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
curl_easy_cleanup(curl);
//printf("\n%s", fp);
}
return fp;
}
This solution C libcurl get output into a string works, but not in my case because I just want to return the string to the calling function.
Any ideas?
Fixed it for you. You need to handle the case where the write_data() function is called multiple times, and pass it the right kind of parameter. You also need to keep track of how big a structure you've got, so you can allocate enough memory.
I left in a debug printf in the write_data function to help you understand how it works.
#include <stdio.h>
#include <curl/curl.h>
#include <string.h>
#include <stdlib.h>
struct url_data {
size_t size;
char* data;
};
size_t write_data(void *ptr, size_t size, size_t nmemb, struct url_data *data) {
size_t index = data->size;
size_t n = (size * nmemb);
char* tmp;
data->size += (size * nmemb);
#ifdef DEBUG
fprintf(stderr, "data at %p size=%ld nmemb=%ld\n", ptr, size, nmemb);
#endif
tmp = realloc(data->data, data->size + 1); /* +1 for '\0' */
if(tmp) {
data->data = tmp;
} else {
if(data->data) {
free(data->data);
}
fprintf(stderr, "Failed to allocate memory.\n");
return 0;
}
memcpy((data->data + index), ptr, n);
data->data[data->size] = '\0';
return size * nmemb;
}
char *handle_url(char* url) {
CURL *curl;
struct url_data data;
data.size = 0;
data.data = malloc(4096); /* reasonable size initial buffer */
if(NULL == data.data) {
fprintf(stderr, "Failed to allocate memory.\n");
return NULL;
}
data.data[0] = '\0';
CURLcode res;
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data);
res = curl_easy_perform(curl);
if(res != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
}
curl_easy_cleanup(curl);
}
return data.data;
}
int main(int argc, char* argv[]) {
char* data;
if(argc < 2) {
fprintf(stderr, "Must provide URL to fetch.\n");
return 1;
}
data = handle_url(argv[1]);
if(data) {
printf("%s\n", data);
free(data);
}
return 0;
}
Note: compile with gcc -o test test.c -lcurl (assuming you pasted into test.c). Use gcc -o test test.c -lcurl -DDEBUG to see the test printf() calls.
Disclaimer: this is ugly, quick-and-dirty code. There may be bugs. Please see the more robust, better commented example here.
#define CURL_STATICLIB
#include <stdio.h>
#include <curl/curl.h>
#include <curl/types.h>
#include <curl/easy.h>
#include <string>
size_t write_data(void *ptr, size_t size, size_t nmemb, FILE *stream) {
size_t written;
written = fwrite(ptr, size, nmemb, stream);
return written;
}
int main(void) {
CURL *curl;
FILE *fp;
CURLcode res;
char *url = "http://localhost/aaa.txt";
char outfilename[FILENAME_MAX] = "C:\\bbb.txt";
curl = curl_easy_init();
if (curl) {
fp = fopen(outfilename,"wb");
curl_easy_setopt(curl, CURLOPT_URL, url);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
res = curl_easy_perform(curl);
curl_easy_cleanup(curl);
fclose(fp);
}
return 0;
}
Some one has posted this code for a question. But on execution of this file the downloaded file is not saving in C drive rather a new txt file will be generating with name "C:\cat.txt"... I want the downloaded file will be stored in my desired location in hard drive.. can any one help me...
First, the default CURLOPT_WRITEFUNCTION accepts a FILE * and uses fwrite using whatever's been set with CURLOPT_WRITEDATA, so you don't need to override the function unless you're using curl as a Win32 DLL.
Also, you aren't checking the return from fopen, which may fail.
I suspect in this case that you either aren't recompiling your code, or are running a different binary from the one you built