mirror of
https://github.com/lwthiker/curl-impersonate.git
synced 2025-08-09 05:09:36 +00:00

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.
215 lines
4.8 KiB
C
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;
|
|
}
|