Issue
i want to upload file with some fields such as file ID identifier to server with CURL libary.
after some experiments, i failed to send even the file ID to server. following is the code.
any help or clue is appreciated :)
the following code is based on the CURL library exmples Testlib554 unit, you can download the source code from here.
and the detailed questions are followed.
first,whether the files i want to upload is in right formadd format? actually , icant understand it well, how to add the file name and the file paths
second, how to fill the fields or attributes of this transfer ,ie. the JSON format string "{"caseDesignId":37}" , when uploading the file meanwhile.
static int once(char *URL, bool oldstyle)
{
CURL *curl;
CURLcode res = CURLE_OK;
CURLFORMcode formrc;
struct curl_httppost *formpost = NULL;
struct curl_httppost *lastptr = NULL;
struct WriteThis pooh;
struct WriteThis pooh2;
pooh.readptr = data;
pooh.sizeleft = strlen(data);
/* Fill in the file upload field */
if(oldstyle) {
formrc = curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "sendfile",
CURLFORM_STREAM, &pooh,
CURLFORM_CONTENTSLENGTH, (long)pooh.sizeleft,
CURLFORM_FILENAME, **pathfile[0],// file i want to upload to server
CURLFORM_END);
}
else {
/* new style */
formrc = curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "sendfile alternative",
CURLFORM_STREAM, &pooh,
CURLFORM_CONTENTLEN, (curl_off_t)pooh.sizeleft,
CURLFORM_FILENAME, pathfile[0],// file i want to upload to server
CURLFORM_END);
}
if(formrc)
printf("curl_formadd(1) = %d\n", (int)formrc);
/* Now add the same data with another name and make it not look like
a file upload but still using the callback */
pooh2.readptr = data;
pooh2.sizeleft = strlen(data);
/* Fill in the file upload field */
formrc = curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "callbackdata",
CURLFORM_STREAM, &pooh2,
CURLFORM_CONTENTSLENGTH, (long)pooh2.sizeleft,
CURLFORM_END);
if(formrc)
fprintf(stderr,"curl_formadd(2) = %d\n", (int)formrc);
/* Fill in the filename field */
formrc = curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "filename",
CURLFORM_COPYCONTENTS, pathfile[1],// file i want to upload to server
CURLFORM_END);
if(formrc)
printf("curl_formadd(3) = %d\n", (int)formrc);
/* Fill in a submit field too */
// here i want to upload "{\"caseDesignId\":88}" with the files to server ....but fails
formrc = curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "caseDesignId",// the submit fields "key"
CURLFORM_COPYCONTENTS, "37", // the submit fields "value"
CURLFORM_CONTENTTYPE, "text/plain",
CURLFORM_END);
if(formrc)
printf("curl_formadd(4) = %d\n", (int)formrc);
formrc = curl_formadd(&formpost, &lastptr,
CURLFORM_COPYNAME, "caseDesignId",
CURLFORM_BUFFER, "{\"caseDesignId\":37}",
CURLFORM_BUFFERPTR, "{\"caseDesignId\":37}",
CURLFORM_BUFFERLENGTH, (long)strlen("{\"caseDesignId\":37}"),//anthoer try
CURLFORM_END);
if(formrc)
printf("curl_formadd(5) = %d\n", (int)formrc);
curl = curl_easy_init();
if(!curl) {
fprintf(stderr, "curl_easy_init() failed\n");
curl_formfree(formpost);
curl_global_cleanup();
return TEST_ERR_MAJOR_BAD;
}
/* First set the URL that is about to receive our POST. */
test_setopt(curl, CURLOPT_URL, URL);
/* Now specify we want to POST data */
test_setopt(curl, CURLOPT_POST, 1L);
/* Set the expected POST size */
test_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)pooh.sizeleft);
/* we want to use our own read function */
test_setopt(curl, CURLOPT_READFUNCTION, read_callback);
/* send a multi-part formpost */
test_setopt(curl, CURLOPT_HTTPPOST, formpost);
/* get verbose debug output please */
test_setopt(curl, CURLOPT_VERBOSE, 1L);
/* include headers in the output */
test_setopt(curl, CURLOPT_HEADER, 1L);
/* Perform the request, res will get the return code */
res = curl_easy_perform(curl);
test_cleanup:
/* always cleanup */
curl_easy_cleanup(curl);
/* now cleanup the formpost chain */
curl_formfree(formpost);
return res;
}
the error info is "status 400 code error : bad request, message :failed to convert value of ****to required type 'int'"
Solution
finally, problem is solved.
first, as for the process of finding the way. tools of wireshark and postman is much helpful. with those tools, i compare the two way of uploading files with attributes. when uploading with postman i grab the package with wireshark which used as a standard format of uploading. this maybe more helpful than the answer.
second, the main code which upload file with some attribute of one transfer goes as followed.
static int once(char *URL, bool oldstyle)
{
CURL *curl;
CURLcode res = CURLE_OK;
CURLFORMcode formrc;
int nFileSize = (0);
struct curl_httppost *formpost = NULL;
struct curl_httppost *lastptr = NULL;
struct WriteThis pooh;
struct WriteThis pooh2;
struct WriteThis pw;
FILE* hFile = fopen(pathfile[0], "rb+");
if (NULL != hFile) {
fseek(hFile, 0, SEEK_END);
pw.sizeleft = ftell(hFile);
fseek(hFile, 0, SEEK_SET);
pw.readptr = (char*)malloc(pw.sizeleft + 1);
memset(pw.readptr, 0, pw.sizeleft+1);
nFileSize = fread(pw.readptr, 1, pw.sizeleft + 1, hFile);
fclose(hFile);
hFile = NULL;
}
pooh.readptr = data;
pooh.sizeleft = strlen(data);
/* Fill in the file upload field */
if(oldstyle) {
formrc = curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "file",
CURLFORM_STREAM, &pooh,
CURLFORM_CONTENTSLENGTH, (long)pooh.sizeleft,
CURLFORM_FILENAME, "face0.png",//"postit2.c",
CURLFORM_END);
}
else {
/* new style */
formrc = curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "file",
CURLFORM_STREAM, &pw,
CURLFORM_CONTENTLEN, (curl_off_t)pw.sizeleft,
CURLFORM_FILENAME, "face0.png",//"file name 2",
CURLFORM_CONTENTTYPE, "image/png",
CURLFORM_END);
}
if(formrc)
printf("curl_formadd(1) = %d\n", (int)formrc);
/* Now add the same data with another name and make it not look like
a file upload but still using the callback */
/* Fill in a submit field too */
formrc = curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "caseDesignId",
CURLFORM_COPYCONTENTS, "37",
///CURLFORM_CONTENTTYPE, "text/plain",
CURLFORM_END);
if(formrc)
printf("curl_formadd(4) = %d\n", (int)formrc);
curl = curl_easy_init();
if(!curl) {
fprintf(stderr, "curl_easy_init() failed\n");
curl_formfree(formpost);
curl_global_cleanup();
return TEST_ERR_MAJOR_BAD;
}
/* First set the URL that is about to receive our POST. */
test_setopt(curl, CURLOPT_URL, URL);
/* Now specify we want to POST data */
test_setopt(curl, CURLOPT_POST, 1L);
/* Set the expected POST size */
test_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)pooh.sizeleft);
/* we want to use our own read function */
test_setopt(curl, CURLOPT_READFUNCTION, read_callback);
/* send a multi-part formpost */
test_setopt(curl, CURLOPT_HTTPPOST, formpost);
/* get verbose debug output please */
test_setopt(curl, CURLOPT_VERBOSE, 1L);
/* include headers in the output */
test_setopt(curl, CURLOPT_HEADER, 1L);
/* Perform the request, res will get the return code */
res = curl_easy_perform(curl);
test_cleanup:
/* always cleanup */
curl_easy_cleanup(curl);
/* now cleanup the formpost chain */
curl_formfree(formpost);
return res;
}
Answered By - nUOs Answer Checked By - David Marino (WPSolving Volunteer)