Отправить файл на (web-сервер) с си клиента (openssl)

332
07 сентября 2021, 05:00

Не получается отправить файл.

Текстовые данные с заголовком application/x-www-form-urlencoded пост запроса отлично передаются, а вот при попытке отправить файл multipart/form-data запрос проходит, но файла как и не бывало.

Обработчик на сервере php, массив $_FILES пустой... Что я делаю не так ? вот си код :

#include ...
#define CHK_NULL(x) if ((x)==NULL) exit (1)
#define CHK_ERR(err,s) if ((err)==-1) { perror(s); exit(1); }
#define CHK_SSL(err) if ((err)==-1) { ERR_print_errors_fp(stderr); exit(2); }
int verify_callback (int ok, X509_STORE_CTX * ctx){
  printf("Подтверждение обратного вызова OK! %d\n", ok);
  return ok;
} 
void main () {
int err;
int sd;
struct sockaddr_in sa;
SSL_CTX *ctx;
SSL     *ssl;
X509    *server_cert;
char    *str;
char     buf[4096];
OpenSSL_add_ssl_algorithms();
SSL_load_error_strings();
ctx = SSL_CTX_new (TLS_client_method());                        
CHK_NULL(ctx);
SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT, verify_callback);
if (SSL_CTX_load_verify_locations(ctx, "./certs/s_cert.pem", "./certs/s_privkey.pem") != 1)
    ERR_print_errors_fp(stderr);
if (SSL_CTX_set_default_verify_paths(ctx) != 1)
    ERR_print_errors_fp(stderr);
if(!SSL_CTX_use_certificate_file(ctx, "./certs/c_cert.pem", SSL_FILETYPE_PEM)
|| !SSL_CTX_use_PrivateKey_file(ctx, "./certs/c_privkey.pem", SSL_FILETYPE_PEM)
|| !SSL_CTX_check_private_key(ctx)) {
    ERR_print_errors_fp(stderr);
    fprintf(stderr, "Error setting up SSL_CTX.\n");
    exit(5);
}
sd = socket (AF_INET, SOCK_STREAM, 0);       
CHK_ERR(sd, "socket");
memset(&sa, 0, sizeof(sa));
sa.sin_family      = AF_INET;
sa.sin_addr.s_addr = inet_addr(нужный айпи);
sa.sin_port        = htons(443);     
err = connect(sd, (struct sockaddr*) &sa, sizeof(sa));                   
CHK_ERR(err, "connect");
ssl = SSL_new(ctx);                         
CHK_NULL(ssl);    
SSL_set_fd(ssl, sd);
err = SSL_connect (ssl);                     
CHK_SSL(err);
printf("SSL connection using %s\n", SSL_get_cipher(ssl));
server_cert = SSL_get_peer_certificate (ssl);       
CHK_NULL(server_cert);
printf("Server certificate:\n");
str = X509_NAME_oneline(X509_get_subject_name (server_cert), 0, 0);
CHK_NULL(str);
printf("\t subject: %s\n", str);
OPENSSL_free (str);
str = X509_NAME_oneline (X509_get_issuer_name  (server_cert), 0, 0);
CHK_NULL(str);
printf("\t issuer: %s\n", str);
OPENSSL_free(str);
X509_free(server_cert);
/*
Эта часть работает отлично
char *message = "POST /send/ HTTP/1.0\r\n"
"Content-Type: application/x-www-form-urlencoded\r\n"
"Content-Length: 5\r\n\r\n"
"s=123\r\n";
err = SSL_write(ssl, message, strlen(message)); 
CHK_SSL(err);   
*/
/* отправка "файла" */
char *header="POST /send/ HTTP/1.1\r\n"
      "Host: 127.0.0.1\r\n"
      "Content-Type: multipart/form-data; boundary=myboundary\r\n"
      "Connection: close\r\n"
      "\r\n"
      "--myboundary\r\n"
      "Content-Type: application/octet-stream\r\n"
      "Content-Disposition: form-data; name=\"myfile\"; filename=\"myfile.ext\"\r\n"
      "Content-Transfer-Encoding: 8bit\r\n"
      "\r\n";
err = SSL_write(ssl, header, strlen(header)); 
CHK_SSL(err);
char body_file[]= {'1', '2', '3', '\0'};
err = SSL_write(ssl, body_file, strlen(body_file)); 
CHK_SSL(err);
char *footer = "\r\n--myboundary--\r\n";
err = SSL_write(ssl, footer, strlen(footer)); 
CHK_SSL(err);
/* конец отправки */
err = SSL_read (ssl, buf, sizeof(buf) - 1);                     
CHK_SSL(err);
buf[err] = '\0';
printf("%s\n", err, buf);
SSL_shutdown(ssl);

close(sd);
SSL_free(ssl);
SSL_CTX_free(ctx);
}

Была мысль что проблемы с сервером (проверил браузером) отлично доходит.

Answer 1

Разобрал наконец. Проблема была в заголовках (как и отметил в комментарии goldstar_labs)

Использовав свой сервер я посмотрел что посылает браузер, послав такой же запрос получил правильный ответ, всё дошло как нужно.

вот заголовки которые использовал (вдруг кому-то понадобится) :

char *header = "POST /send/ HTTP/1.1\r\n"
"Host: domain\r\n"
"User-Agent: Botenko\r\n"
"Content-Type: multipart/form-data; boundary=___18467633426502___\r\n"
"Content-Length: 156\r\n"
"Connection: keep-alive\r\n\r\n"
"--___18467633426502___\r\n"
"Content-Disposition: form-data; name='d'; filename='f'\r\n"
"Content-Type: application/octet-stream\r\n\r\n"
"123444\r\n--___18467633426502___--\r\n";
READ ALSO
Анимация css в Qt. C++

Анимация css в Qt. C++

Возможно кто-то в курсе, каким образом можно создать анимацию, например плавное изменение цвета кнопки с помощью CSS, просто подключая, например:

131
Размер класса в определенной иерархии

Размер класса в определенной иерархии

Почему объект класса A занимает 4 байта?

111
Указатель объявляется в каждом проходе цикла. Правильно ли это?

Указатель объявляется в каждом проходе цикла. Правильно ли это?

Отвечаю на вопрос, связанный с переобъявлениемВ масштабе вашего кода все нормально

108
Вставить данные в поле

Вставить данные в поле

Есть html типа

125