Skip to content

Instantly share code, notes, and snippets.

@sagebind
Last active July 24, 2020 15:32
Show Gist options
  • Save sagebind/24f5824f44cd1f81e9a475951f888025 to your computer and use it in GitHub Desktop.
Save sagebind/24f5824f44cd1f81e9a475951f888025 to your computer and use it in GitHub Desktop.
Example C program for curl issue #5717
#include <curl/curl.h>
#include <errno.h>
#include <netinet/in.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#define EXPECT(expr) \
{ \
if (expr != 0) \
{ \
fprintf(stderr, "%s\n", strerror(errno)); \
exit(1); \
} \
}
#define CURL_EXPECT(expr) \
{ \
CURLcode result; \
if ((result = expr) != CURLE_OK) \
{ \
fprintf(stderr, "%s\n", curl_easy_strerror(result)); \
exit(1); \
} \
}
static void *server_main(void *arg)
{
int server_socket = (int)arg;
int client_socket, len;
struct sockaddr_in client_addr;
socklen_t addr_len = sizeof(client_addr);
if ((client_socket = accept(server_socket, &client_addr, &addr_len)) < 0)
{
fprintf(stderr, "Accept failed\n");
exit(1);
}
char buf[8192];
recv(client_socket, buf, 65535, 0);
FILE *fd = fdopen(client_socket, "w");
fprintf(fd, "HTTP/1.1 200 OK\r\n");
fprintf(fd, "Content-Length: 0\r\n\r\n");
fflush(fd);
EXPECT(close(client_socket));
EXPECT(close(server_socket));
return NULL;
}
int main(int argc, char **argv)
{
CURLcode result;
int server_socket, len;
pthread_t server_thread;
CURL_EXPECT(curl_global_init(CURL_GLOBAL_ALL));
// Create a server socket.
if ((server_socket = socket(AF_INET, SOCK_STREAM, 0)) < 0)
{
fprintf(stderr, "Socket creation failed\n");
exit(1);
}
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(0);
server_addr.sin_addr.s_addr = INADDR_ANY;
len = sizeof(server_addr);
EXPECT(bind(server_socket, &server_addr, len));
EXPECT(listen(server_socket, 10000));
getsockname(server_socket, &server_addr, &len);
char url[64];
sprintf(url, "http://127.0.0.1:%d", ntohs(server_addr.sin_port));
// Spawn TCP server thread.
pthread_create(&server_thread, NULL, server_main, (void *)server_socket);
CURL *curl = curl_easy_init();
FILE *infile = fopen("main.c", "rb");
fseek(infile, 0L, SEEK_END);
long infile_size = ftell(infile);
fseek(infile, 0L, SEEK_SET);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_URL, &url);
curl_easy_setopt(curl, CURLOPT_READDATA, infile);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, fread);
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
curl_easy_setopt(curl, CURLOPT_NOBODY, 1);
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "HEAD");
curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, infile_size);
CURL_EXPECT(curl_easy_perform(curl));
curl_easy_cleanup(curl);
fclose(infile);
return 0;
}
.PHONY: run-old
run-old: out/old
$<
.PHONY: run-new
run-new: out/new
$<
.PHONY: clean
clean:
rm -r out
out/old: main.c
mkdir -p $(@D)
gcc -o $@ $< -lcurl -lpthread
out/new: main.c
mkdir -p $(@D)
gcc -o $@ $< /usr/local/lib/libcurl.a -lpthread -lssl -lcrypto
@sagebind
Copy link
Author

My C is a little rusty so this is probably not the most well-written program, but it gets the job done.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment