curl / Mailing Lists / curl-library / Single Mail
Buy commercial curl support from WolfSSL. We help you work out your issues, debug your libcurl applications, use the API, port to new platforms, add new features and more. With a team lead by the curl founder himself.

Re: curl post fails.

From: Ray Satiro via curl-library <curl-library_at_lists.haxx.se>
Date: Sun, 2 Oct 2022 18:00:57 -0400

On 10/2/2022 2:09 PM, jian he via curl-library wrote:
> Follow this url
> (https://www.backblaze.com/b2/docs/b2_upload_file.html) The command
> line way will work.
>
> FILE_TO_UPLOAD=/home/jian/helloc/curl_1.c
> MIME_TYPE=text/plain
> SHA1_OF_FILE=$(openssl dgst -sha1 $FILE_TO_UPLOAD | awk '{print $2;}')
> UPLOAD_URL=https://pod-040-2009-17.backblaze.com/b2api/v2/b2_upload_file/daed35e922928ea38f340519/c004_v0402009_t0052
> UPLOAD_AUTHORIZATION_TOKEN="4_004ad5922e3f4590000000000_01a7620b_106677_upld_sg7Wnh52ocxqngTkjBLSfzE_ZzM="
> curl \
>     -v \
>     -H "Authorization: $UPLOAD_AUTHORIZATION_TOKEN" \
>     -H "X-Bz-File-Name: $FILE_TO_UPLOAD" \
>     -H "Content-Type: $MIME_TYPE" \
>     -H "X-Bz-Content-Sha1: $SHA1_OF_FILE" \
>     -H "X-Bz-Info-Author: unknown" \
>     -H "X-Bz-Server-Side-Encryption: AES256" \
>     --data-binary "_at_$FILE_TO_UPLOAD" \
>     $UPLOAD_URL
>
>
> I am trying to write it in libcurl. Then it fails.
> /*
> gcc -Wall -Wextra -pedantic -Wshadow -Ofast curl_upload.c -lcurl &&./a.out
> valgrind ./a.out
> openssl dgst -sha1 "/home/jian/helloc/curl_stmp1.c" | awk '{print $2;}'
> 03cc73740b9672c51a0cfe1b382c11bbb6a706c7
> */
> #include <stdio.h>
> #include <curl/curl.h>
> #include <string.h>
> #include <stdlib.h>
> #include <errno.h>
> #include <sys/stat.h>
> #include<stdlib.h>
> const char access_token[] =
> "4_004ad5922e3f4590000000000_01a7620b_106677_upld_sg7Wnh52ocxqngTkjBLSfzE_ZzM=";
> const char upload_url[] =
>  "https://pod-040-2009-17.backblaze.com/b2api/v2/b2_upload_file/daed35e922928ea38f340519/c004_v0402009_t0052";
> const char buckId[] = "daed35e922928ea38f340519";
> int main(void)
> {
>     // unsigned char buffer[BUFSIZ];
>     CURL *curl_handle = curl_easy_init();
>     struct stat file_info;
>     char *filename = "curl_1.c";
>     char *path = realpath(filename,NULL);
>     stat(filename,&file_info);
>
>     printf("%s file size is %zu bytes\n",path,file_info.st_size);
>     FILE *fp = fopen(path,"rb");
>     if(fp == NULL){
>         perror("failed");
>         return 1;
>     }
>
>     struct curl_slist *chunk = NULL;
>     chunk = curl_slist_append(chunk,"Content-Type: text/plain");
>     chunk = curl_slist_append(chunk,"X-Bz-File-Name:
> /home/jian/helloc/curl_1.c");
>     chunk = curl_slist_append(chunk,"Content-Length: 799");
>     chunk = curl_slist_append(chunk,"Content-Length: 799");
>     chunk = curl_slist_append(chunk,"X-Bz-Server-Side-Encryption:
> AES256");
>     chunk = curl_slist_append(chunk,"X-Bz-Content-Sha1:
> 4ce3ebcd1ac59818d2884b4e96123b794ba69c4c");
>     chunk = curl_slist_append(chunk,"X-Bz-Info-Author: unknown");
>
>     /* Content-Length: [NUMBER_OF_BYTES_IN_FILE] */
>     char size[200];
>     snprintf(size,200,"Content-Length: %lld",(long long
> int)file_info.st_size);
>     printf("size=%s\n",size);
>
>     char auth[300];
>     strcat(auth,"Authorization: ");
>     strcat(auth,access_token);
>     printf("auth:%s\n\n\n",auth);
>     chunk = curl_slist_append(chunk,auth);
>     curl_easy_setopt(curl_handle,CURLOPT_VERBOSE,1L);
> curl_easy_setopt(curl_handle,CURLOPT_HTTPHEADER,chunk);
>     curl_easy_setopt(curl_handle, CURLOPT_HTTP_VERSION,
> CURL_HTTP_VERSION_1_1);
>     curl_easy_setopt(curl_handle,CURLOPT_URL,upload_url);
>     curl_easy_setopt(curl_handle,CURLOPT_POST,1L);
>     curl_easy_setopt(curl_handle,CURLOPT_READDATA,fp);
>     CURLcode res = curl_easy_perform(curl_handle);
>     if(res != CURLE_OK){
>         fprintf(stderr,"curl_easy_perform() failed:
> %s\n",curl_easy_strerror(res));
>     }else{
>         printf("\n\nSuccess\n");
>     }
>     curl_easy_cleanup(curl_handle);
>     return 0;
> }
>
> The verbose message:
>
> /home/jian/helloc/curl_1.c file size is 759 bytes
> size=Content-Length: 759
> auth:Authorization:
> 4_004ad5922e3f4590000000000_01a7620b_106677_upld_sg7Wnh52ocxqngTkjBLSfzE_ZzM=
>
>
> *   Trying 149.137.133.93:443...
> * Connected to pod-040-2009-17.backblaze.com
> <http://pod-040-2009-17.backblaze.com> (149.137.133.93) port 443 (#0)
> * found 384 certificates in /etc/ssl/certs
> * GnuTLS ciphers:
> NORMAL:-ARCFOUR-128:-CTYPE-ALL:+CTYPE-X509:-VERS-SSL3.0
> * ALPN, offering http/1.1
> * SSL connection using TLS1.3 / ECDHE_RSA_AES_128_GCM_SHA256
> *   server certificate verification OK
> *   server certificate status verification SKIPPED
> *   common name: backblaze.com <http://backblaze.com> (matched)
> *   server certificate expiration date OK
> *   server certificate activation date OK
> *   certificate public key: RSA
> *   certificate version: #3
> *   subject: CN=backblaze.com <http://backblaze.com>
> *   start date: Mon, 26 Sep 2022 21:40:41 GMT
> *   expire date: Sun, 25 Dec 2022 21:40:40 GMT
> *   issuer: C=US,O=Let's Encrypt,CN=R3
> * ALPN, server did not agree to a protocol
> > POST
> /b2api/v2/b2_upload_file/daed35e922928ea38f340519/c004_v0402009_t0052
> HTTP/1.1
> Host: pod-040-2009-17.backblaze.com
> <http://pod-040-2009-17.backblaze.com>
> Accept: */*
> Transfer-Encoding: chunked
> Content-Type: text/plain
> X-Bz-File-Name: /home/jian/helloc/curl_1.c
> Content-Length: 799
> Content-Length: 799
> X-Bz-Server-Side-Encryption: AES256
> X-Bz-Content-Sha1: 4ce3ebcd1ac59818d2884b4e96123b794ba69c4c
> X-Bz-Info-Author: unknown
> Authorization:
> 4_004ad5922e3f4590000000000_01a7620b_106677_upld_sg7Wnh52ocxqngTkjBLSfzE_ZzM=
> Expect: 100-continue
>
> * Mark bundle as not supporting multiuse
> < HTTP/1.1 400
> < Content-Type: text/html;charset=utf-8
> < Content-Language: en
> < Content-Length: 435
> < Date: Sun, 02 Oct 2022 18:02:23 GMT
> < Connection: close
> <
> * Closing connection 0
> <!doctype html><html lang="en"><head><title>HTTP Status 400 – Bad
> Request</title><style type="text/css">body
> {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b
> {color:white;background-color:#525D76;} h1 {font-size:22px;} h2
> {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a
> {color:black;} .line
> {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP
> Status 400 – Bad Request</h1></body></html>
>
> Success
>
>
> I am not so sure why it failed.
> Interesting part: if I only have one chunk =
> curl_slist_append(chunk,"Content-Length: 799");
> then it will fail error message is like:
> {
>   "code": "bad_request",
>   "message": "Missing header: Content-Length",
>   "status": 400
> * Closing connection 0
> }
>
> If I have two lines chunk = curl_slist_append(chunk,"Content-Length:
> 799"); then it will fail because of Bad Request.
> Why did I set Length to 799?  759 + 40 = 799.
> In the doc: https://www.backblaze.com/b2/docs/b2_upload_file.html aout
> Content length:
>
> The number of bytes in the file being uploaded. Note that this
> header is required; you cannot leave it out and just use chunked
> encoding.
> When sending the SHA1 checksum at the end, the Content-Length
> should be set to the size of the file plus the 40 bytes of hex
> checksum.
>
>
> Since the only message is "HTTP Status 400 – Bad Request" then I don't
> know how to debug it any more...


You can use curl option --libcurl [1] to get the source code equivalent.
That will show you that CURLOPT_POSTFIELDS and
CURLOPT_POSTFIELDSIZE_LARGE are used to respectively set the already
read in data and its size.

In your example you have chosen instead to use CURLOPT_POST [2] and
CURLOPT_READDATA to read the data from a file. That's fine, however you
should also set CURLOPT_SEEKFUNCTION [3] (basically forward to fseek;
read the doc for pitfalls) and CURLOPT_SEEKDATA to the same pointer as
READDATA. That way if the first post request fails (like, authentication
required) the file can be properly rewound and read again from the
beginning.

Your example also sets the content length header twice, but it should
not do that even once. By using the read function you are by default
sending data using chunked encoding, and then you are adding the content
length header. The bad request looks like this:

Transfer-Encoding: chunked
Content-Type: text/plain
X-Bz-File-Name: /home/jian/helloc/curl_1.c
Content-Length: 799
Content-Length: 799

You could set CURLOPT_POSTFIELDSIZE_LARGE to set the content length
instead of using chunked encoding. These are things you need to review
the documentation for, review the links at the bottom of this e-mail.

There are other problems with your example. You are not checking the
return code of stat and you are concatenating to an uninitialized string
auth[] which will likely cause memory corruption.


[1]: https://curl.se/docs/manpage.html#--libcurl
[2]: https://curl.se/libcurl/c/CURLOPT_POST.html
[3]: https://curl.se/libcurl/c/CURLOPT_SEEKFUNCTION.html


-- 
Unsubscribe: https://lists.haxx.se/listinfo/curl-library
Etiquette:   https://curl.se/mail/etiquette.html
Received on 2022-10-03