I am trying to download an image file (format is .bmp) from a website using sockets and openssl library. I initiate an ssl connection and then send the http GET request using sockets and then put whatever the server sends into a file called response.txt. Usually there are some headers in the file about the response about whether the exchange was successful or not and then the image data should begin. Since the image is in .bmp format it should begin with a 'BM' tag and that's how we know where the headers start and that should be the image data for the rest of the file. So I expect that upon deleting everything before the 'BM' tag and copying the rest of the file into a .bmp file I should be able to open the image. However apparently the image is data is corrupted and I can't figure out why the corruption happens. I have tried examining the file in binary mode and comparing it to the actual image I found on the web but I still can't figure what causes the two images to differ after a certain point in their data. Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <openssl/ssl.h>
#include <openssl/bio.h>
#include <openssl/err.h>
#define h_addr h_addr_list[0]
//#define SERVER "static.vecteezy.com"
#define SERVER "filesamples.com"
#define PORT 443
//#define PATH "/system/resources/previews/002/410/747/original/cute-siamese-cat-on-yellow-background-free-photo.jpg"
#define PATH "/samples/image/bmp/sample_640%C3%97426.bmp"
int main() {
int sockfd;
struct sockaddr_in serv_addr;
struct hostent *server;
SSL_library_init();
SSL_CTX *ctx = SSL_CTX_new(TLS_client_method());
if (ctx == NULL) {
printf("Error creating SSL context\n");
return 1;
}
SSL *ssl = SSL_new(ctx);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) {
printf("Error opening socket\n");
return 1;
}
server = gethostbyname(SERVER);
if (server == NULL) {
printf("Error resolving server hostname\n");
return 1;
}
memset(&serv_addr, 0, sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(PORT);
memcpy(&serv_addr.sin_addr.s_addr, server->h_addr, server->h_length);
if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
printf("Error connecting to server\n");
return 1;
}
BIO *sbio = BIO_new_socket(sockfd, BIO_NOCLOSE);
SSL_set_bio(ssl, sbio, sbio);
if (SSL_set_tlsext_host_name(ssl, SERVER) != 1) {
printf("Error setting SNI\n");
return 1;
}
if (SSL_connect(ssl) <= 0) {
printf("Error establishing SSL connection\n");
return 1;
}
char request[1024];
sprintf(request, "GET %s HTTP/1.1\r\nHost: %s\r\n\r\n", PATH, SERVER);
SSL_write(ssl, request, strlen(request));
char response[1024];
int bytes_read;
int total_bytes_read = 0;
FILE *fp = fopen("response.txt", "wb");
if (fp == NULL) {
printf("Error opening file\n");
return 1;
}
do {
bytes_read = SSL_read(ssl, response, sizeof(response));
if (bytes_read > 0) {
printf("bytes read: %i\n",bytes_read);
fwrite(response, 1, bytes_read, fp);
total_bytes_read += bytes_read;
}
} while (bytes_read > 0);
fclose(fp);
printf("Total bytes read: %d\n", total_bytes_read);
SSL_shutdown(ssl);
SSL_free(ssl);
SSL_CTX_free(ctx);
close(sockfd);
return 0;
}
Note : the image file is on https://filesamples.com/samples/image/bmp/sample_640%C3%97426.bmp