The CURL
command that I am using is shown below.
curl -F 'file=@/home/karthik/Workspace/downloadfile.out' http://127.0.0.1:5000/file-upload --verbose
The response from the server is shown below.
* Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
> POST /file-upload HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/7.47.0
> Accept: */*
> Content-Length: 663876790
> Expect: 100-continue
> Content-Type: multipart/form-data; boundary=------------------------4e96ef0714498bd7
>
< HTTP/1.1 100 Continue
* HTTP 1.0, assume close after body
< HTTP/1.0 201 CREATED
< Content-Type: application/json
< Content-Length: 46
< Server: Werkzeug/0.16.0 Python/3.5.2
< Date: Sat, 14 Dec 2019 07:05:15 GMT
<
{
"message": "File successfully uploaded"
}
* Closing connection 0
I want to implement the same command in C/C++ using libcurl. I am using the following function.
int FileUploadDownload::upload(const std::string &filename, const std::string &url) {
CURL *curl;
CURLcode res;
struct stat file_info;
curl_off_t speed_upload, total_time;
FILE *fd;
fd = fopen(filename.c_str(), "rb");
if(!fd) {
m_logger->errorf("unable to open file: %s\n",strerror(errno));
return 1;
}
if(fstat(fileno(fd), &file_info) != 0) {
m_logger->errorf("unable to get file stats: %s\n",strerror(errno));
return 2;
}
std::cout << "filename : "<< filename << std::endl;
std::cout << "url : " << url << std::endl;
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL,
url.c_str());
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, filename.c_str());
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_READDATA, fd);
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE,
(curl_off_t) file_info.st_size);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
res = curl_easy_perform(curl);
if (res != CURLE_OK) {
m_logger->errorf("curl_easy_perform() failed: %s\n",curl_easy_strerror(res));
} else {
curl_easy_getinfo(curl, CURLINFO_SPEED_UPLOAD, &speed_upload);
curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &total_time);
m_logger->infof("Speed: %" CURL_FORMAT_CURL_OFF_T " bytes/sec during %"
CURL_FORMAT_CURL_OFF_T ".%06ld seconds\n",
speed_upload,
(total_time / 1000000), (long) (total_time % 1000000));
}
}
return 0;
}
The below is the result that I get from the server.
The result that I get is shown below.
* Trying 127.0.0.1...
* Connected to 127.0.0.1 (127.0.0.1) port 5000 (#0)
> POST /file-upload HTTP/1.1
> Host: 127.0.0.1:5000
> User-Agent: curl/7.47.0
> Accept: */*
> Content-Length: 550
> Expect: 100-continue
> Content-Type: multipart/form-data; boundary=------------------------c8ef4837136fca99
>
< HTTP/1.1 100 Continue
* HTTP 1.0, assume close after body
< HTTP/1.0 201 CREATED
< Content-Type: application/json
< Content-Length: 46
< Server: Werkzeug/0.16.0 Python/3.5.2
< Date: Sat, 14 Dec 2019 07:09:47 GMT
<
{
"message": "File successfully uploaded"
}
* Closing connection 0
My aim is to mimic the curl command above in the C/C++ code below. What am I doing wrong ?
I have some difficulty in update to the latest libcurl. However I tried to set the HTTPHEADERS manually as follows.
stringstream ss;
ss << "Content-Type:" << " multipart/form-data";
list = curl_slist_append(list, ss.str().c_str());
ss.str(std::string());
ss << "filename=" << filename;
list = curl_slist_append(list, ss.str().c_str());
ss.str(std::string());
ss << "name=file";
list = curl_slist_append(list, ss.str().c_str());
ss.str(std::string());
ss << "Content-Type:" << " text/plain";
list = curl_slist_append(list, ss.str().c_str());
ss.str(std::string());
ss << "Content-Disposition:" << " form-data";
list = curl_slist_append(list, ss.str().c_str());
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, list);
But the below code doesn't seem to work. Is the above approach valid ? If yes, what am I doing wrong?
To upload file you need to send data with content type multipart/form-data
.
For that you need to create form and attach file data in that form as below.
#include <curl/curl.h>
#include <errno.h>
#include <iostream>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <string.h>
int upload(const std::string &filename, const std::string &url) {
CURL *curl;
CURLcode res;
struct stat file_info;
curl_off_t speed_upload, total_time;
FILE *fd;
curl_mime *form = NULL;
curl_mimepart *field = NULL;
struct curl_slist *headerlist = NULL;
static const char buf[] = "Expect:";
fd = fopen(filename.c_str(), "rb");
if (!fd) {
printf("unable to open file: %s\n", strerror(errno));
return 1;
}
if (fstat(fileno(fd), &file_info) != 0) {
printf("unable to get file stats: %s\n", strerror(errno));
return 2;
}
std::cout << "filename : " << filename << ":"
<< std::endl;
std::cout << "url : " << url << std::endl;
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
form = curl_mime_init(curl);
/* Fill in the file upload field */
field = curl_mime_addpart(form);
curl_mime_name(field, "file");
curl_mime_filedata(field, filename.c_str());
headerlist = curl_slist_append(headerlist, buf);
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
curl_easy_setopt(curl, CURLOPT_MIMEPOST, form);
res = curl_easy_perform(curl);
if (res != CURLE_OK) {
printf("curl_easy_perform() failed: %s\n", curl_easy_strerror(res));
} else {
curl_easy_getinfo(curl, CURLINFO_SPEED_UPLOAD, &speed_upload);
curl_easy_getinfo(curl, CURLINFO_TOTAL_TIME, &total_time);
printf("Speed: %" CURL_FORMAT_CURL_OFF_T
" bytes/sec during %" CURL_FORMAT_CURL_OFF_T ".%06ld seconds\n",
speed_upload, (total_time / 1000000),
(long)(total_time % 1000000));
}
}
return 0;
}
int main(int argc, char **argv) { return upload(argv[1], argv[2]); }
Note:
Usage: ./a.out FileName ServerURL
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.