how to use CURL formadd upload file with submit fields in c++?

喜欢而已 提交于 2021-01-29 14:25:05

问题


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'"


回答1:


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;
}


来源:https://stackoverflow.com/questions/61190685/how-to-use-curl-formadd-upload-file-with-submit-fields-in-c

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!