Files
curl-impersonate/tests/minicurl.c
lwthiker 9bab04c170 Test curl-impersonate's HTTP headers
Add tests to verify that the HTTP headers and HTTP/2 pseudo-headers
generated by curl-impersonate match the expected ones from the browser.

The test uses a local nghttpd HTTP/2 server instance with a self-signed
certificate.
2022-03-04 17:31:32 +02:00

215 lines
4.8 KiB
C

/*
* A simple program that uses libcurl to fetch a URL and output to stdout.
*
* It is intended to be linked against the "regular" libcurl, with
* "libcurl-impersonate" loaded via LD_PRELOAD. It does the bare minimum
* to support the Python tests.
*/
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <getopt.h>
#include <stdbool.h>
#include <curl/curl.h>
/* Command line options. */
struct opts {
char *outfile;
uint16_t local_port_start;
uint16_t local_port_end;
bool insecure;
char *url;
};
int parse_ports_range(char *str, uint16_t *start, uint16_t *end)
{
char port[32];
char *sep;
unsigned long int tmp;
if (strlen(str) >= sizeof(port)) {
return 1;
}
strncpy(port, str, sizeof(port) - 1);
sep = strchr(port, '-');
if (!sep) {
return 1;
}
*sep = 0;
errno = 0;
tmp = strtoul(port, NULL, 10);
if (errno || tmp == 0 || tmp > 0xffff) {
return 1;
}
*start = (uint16_t)tmp;
tmp = strtoul(sep + 1, NULL, 10);
if (errno || tmp == 0 || tmp > 0xffff || tmp < *start) {
return 1;
}
*end = (uint16_t)tmp;
return 0;
}
int parse_opts(int argc, char **argv, struct opts *opts)
{
int c;
int r;
memset(opts, 0, sizeof(*opts));
opts->insecure = false;
while (1) {
int option_index = 0;
static struct option long_options[] = {
{"local-port", required_argument, NULL, 'l'}
};
c = getopt_long(argc, argv, "o:k", long_options, &option_index);
if (c == -1) {
break;
}
switch (c) {
case 'l':
r = parse_ports_range(optarg,
&opts->local_port_start,
&opts->local_port_end);
if (r) {
return r;
}
break;
case 'o':
opts->outfile = optarg;
break;
case 'k':
opts->insecure = true;
break;
}
}
if (optind < argc) {
opts->url = argv[optind++];
} else {
return 1;
}
if (optind < argc) {
/* Too many arguments. */
return 1;
}
return 0;
}
int main(int argc, char *argv[])
{
struct opts opts;
CURLcode c;
CURL *curl = NULL;
FILE *file;
if (parse_opts(argc, argv, &opts)) {
fprintf(stderr, "Invalid arguments\n");
exit(1);
}
if (opts.outfile) {
file = fopen(opts.outfile, "w");
if (!file) {
fprintf(stderr, "Failed opening %s for writing\n", opts.outfile);
exit(1);
}
} else {
file = stdout;
}
c = curl_global_init(CURL_GLOBAL_DEFAULT);
if (c) {
fprintf(stderr, "curl_global_init() failed\n");
goto out_close;
}
curl = curl_easy_init();
if (!curl) {
fprintf(stderr, "curl_easy_init() failed\n");
c = 1;
goto out;
}
c = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite);
if (c) {
fprintf(stderr, "curl_easy_setopt(CURLOPT_WRITEFUNCTION) failed\n");
goto out;
}
c = curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);
if (c) {
fprintf(stderr, "curl_easy_setopt(CURLOPT_WRITEDATA) failed\n");
goto out;
}
if (opts.local_port_start && opts.local_port_end) {
c = curl_easy_setopt(curl,
CURLOPT_LOCALPORT,
opts.local_port_start);
if (c) {
fprintf(stderr, "curl_easy_setopt(CURLOPT_LOCALPORT) failed\n");
goto out;
}
c = curl_easy_setopt(curl,
CURLOPT_LOCALPORTRANGE,
opts.local_port_end - opts.local_port_start);
if (c) {
fprintf(stderr,
"curl_easy_setopt(CURLOPT_LOCALPORTRANGE) failed\n");
goto out;
}
}
if (opts.insecure) {
c = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
if (c) {
fprintf(stderr, "curl_easy_setopt(CURLOPT_SSL_VERIFYPEER) failed\n");
goto out;
}
c = curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0);
if (c) {
fprintf(stderr, "curl_easy_setopt(CURLOPT_SSL_VERIFYHOST) failed\n");
goto out;
}
}
c = curl_easy_setopt(curl, CURLOPT_URL, opts.url);
if (c) {
fprintf(stderr, "curl_easy_setopt(CURLOPT_URL) failed\n");
goto out;
}
c = curl_easy_perform(curl);
if (c) {
fprintf(stderr, "curl_easy_perform() failed\n");
goto out;
}
c = 0;
out:
if (curl) {
curl_easy_cleanup(curl);
}
curl_global_cleanup();
out_close:
if (file) {
fclose(file);
}
return c;
}