build: omit forward declarations

- drop redundant forward declarations.
- reorder local functions to not need forward declarations.
- tftpd: merge two `ifdef` blocks.

Closes #20297
This commit is contained in:
Viktor Szakats 2026-01-13 15:40:09 +01:00
parent 8680a07589
commit 60f9d3dd7b
No known key found for this signature in database
GPG key ID: B5ABD165E2AEF201
9 changed files with 1115 additions and 1210 deletions

View file

@ -53,39 +53,6 @@
* sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
*/
static int inet_pton4(const char *src, unsigned char *dst);
static int inet_pton6(const char *src, unsigned char *dst);
/* int
* inet_pton(af, src, dst)
* convert from presentation format (which usually means ASCII printable)
* to network format (which is usually some kind of binary format).
* return:
* 1 if the address was valid for the specified address family
* 0 if the address was not valid (`dst' is untouched in this case)
* -1 if some other error occurred (`dst' is untouched in this case, too)
* notice:
* On Windows we store the error in the thread errno, not
* in the Winsock error code. This is to avoid losing the
* actual last Winsock error. When this function returns
* -1, check errno not SOCKERRNO.
* author:
* Paul Vixie, 1996.
*/
int curlx_inet_pton(int af, const char *src, void *dst)
{
switch(af) {
case AF_INET:
return inet_pton4(src, (unsigned char *)dst);
case AF_INET6:
return inet_pton6(src, (unsigned char *)dst);
default:
errno = SOCKEAFNOSUPPORT;
return -1;
}
/* NOTREACHED */
}
/* int
* inet_pton4(src, dst)
* like inet_aton() but without all the hexadecimal and shorthand.
@ -225,4 +192,34 @@ static int inet_pton6(const char *src, unsigned char *dst)
return 1;
}
/* int
* inet_pton(af, src, dst)
* convert from presentation format (which usually means ASCII printable)
* to network format (which is usually some kind of binary format).
* return:
* 1 if the address was valid for the specified address family
* 0 if the address was not valid (`dst' is untouched in this case)
* -1 if some other error occurred (`dst' is untouched in this case, too)
* notice:
* On Windows we store the error in the thread errno, not
* in the Winsock error code. This is to avoid losing the
* actual last Winsock error. When this function returns
* -1, check errno not SOCKERRNO.
* author:
* Paul Vixie, 1996.
*/
int curlx_inet_pton(int af, const char *src, void *dst)
{
switch(af) {
case AF_INET:
return inet_pton4(src, (unsigned char *)dst);
case AF_INET6:
return inet_pton6(src, (unsigned char *)dst);
default:
errno = SOCKEAFNOSUPPORT;
return -1;
}
/* NOTREACHED */
}
#endif /* HAVE_INET_PTON */

View file

@ -112,8 +112,6 @@
* CURLRES_* defines based on the config*.h and curl_setup.h defines.
*/
static void dnscache_entry_free(struct Curl_dns_entry *dns);
#ifndef CURL_DISABLE_VERBOSE_STRINGS
static void show_resolve_info(struct Curl_easy *data,
struct Curl_dns_entry *dns);
@ -121,6 +119,18 @@ static void show_resolve_info(struct Curl_easy *data,
#define show_resolve_info(x, y) Curl_nop_stmt
#endif
static void dnscache_entry_free(struct Curl_dns_entry *dns)
{
Curl_freeaddrinfo(dns->addr);
#ifdef USE_HTTPSRR
if(dns->hinfo) {
Curl_httpsrr_cleanup(dns->hinfo);
curlx_free(dns->hinfo);
}
#endif
curlx_free(dns);
}
/*
* Curl_printable_address() stores a printable version of the 1st address
* given in the 'ai' argument. The result will be stored in the buf that is
@ -1160,18 +1170,6 @@ clean_up:
return result;
}
static void dnscache_entry_free(struct Curl_dns_entry *dns)
{
Curl_freeaddrinfo(dns->addr);
#ifdef USE_HTTPSRR
if(dns->hinfo) {
Curl_httpsrr_cleanup(dns->hinfo);
curlx_free(dns->hinfo);
}
#endif
curlx_free(dns);
}
/*
* Curl_resolv_unlink() releases a reference to the given cached DNS entry.
* When the reference count reaches 0, the entry is destroyed. It is important

View file

@ -62,20 +62,6 @@ struct pair {
struct dynbuf value;
};
static void dyn_array_free(struct dynbuf *db, size_t num_elements);
static void pair_array_free(struct pair *pair_array, size_t num_elements);
static CURLcode split_to_dyn_array(const char *source,
struct dynbuf db[MAX_QUERY_COMPONENTS],
size_t *num_splits);
static bool is_reserved_char(const char c);
static CURLcode uri_encode_path(struct Curl_str *original_path,
struct dynbuf *new_path);
static CURLcode encode_query_component(char *component, size_t len,
struct dynbuf *db);
static CURLcode http_aws_decode_encode(const char *in, size_t in_len,
struct dynbuf *out);
static bool should_urlencode(struct Curl_str *service_name);
static void sha256_to_hex(char *dst, unsigned char *sha)
{
Curl_hexencode(sha, CURL_SHA256_DIGEST_LENGTH,
@ -129,6 +115,171 @@ static void trim_headers(struct curl_slist *head)
}
}
/*
* Frees all allocated strings in a dynbuf pair array, and the dynbuf itself
*/
static void pair_array_free(struct pair *pair_array, size_t num_elements)
{
size_t index;
for(index = 0; index != num_elements; index++) {
curlx_dyn_free(&pair_array[index].key);
curlx_dyn_free(&pair_array[index].value);
}
}
/*
* Frees all allocated strings in a split dynbuf, and the dynbuf itself
*/
static void dyn_array_free(struct dynbuf *db, size_t num_elements)
{
size_t index;
for(index = 0; index < num_elements; index++)
curlx_dyn_free((&db[index]));
}
/*
* Splits source string by SPLIT_BY, and creates an array of dynbuf in db.
* db is initialized by this function.
* Caller is responsible for freeing the array elements with dyn_array_free
*/
#define SPLIT_BY '&'
static CURLcode split_to_dyn_array(const char *source,
struct dynbuf db[MAX_QUERY_COMPONENTS],
size_t *num_splits_out)
{
CURLcode result = CURLE_OK;
size_t len = strlen(source);
size_t pos; /* Position in result buffer */
size_t start = 0; /* Start of current segment */
size_t segment_length = 0;
size_t index = 0;
size_t num_splits = 0;
/* Split source_ptr on SPLIT_BY and store the segment offsets and length in
* array */
for(pos = 0; pos < len; pos++) {
if(source[pos] == SPLIT_BY) {
if(segment_length) {
curlx_dyn_init(&db[index], segment_length + 1);
result = curlx_dyn_addn(&db[index], &source[start], segment_length);
if(result)
goto fail;
segment_length = 0;
index++;
if(++num_splits == MAX_QUERY_COMPONENTS) {
result = CURLE_TOO_LARGE;
goto fail;
}
}
start = pos + 1;
}
else {
segment_length++;
}
}
if(segment_length) {
curlx_dyn_init(&db[index], segment_length + 1);
result = curlx_dyn_addn(&db[index], &source[start], segment_length);
if(!result) {
if(++num_splits == MAX_QUERY_COMPONENTS)
result = CURLE_TOO_LARGE;
}
}
fail:
*num_splits_out = num_splits;
return result;
}
static bool is_reserved_char(const char c)
{
return (ISALNUM(c) || ISURLPUNTCS(c));
}
static CURLcode uri_encode_path(struct Curl_str *original_path,
struct dynbuf *new_path)
{
const char *p = curlx_str(original_path);
size_t i;
for(i = 0; i < curlx_strlen(original_path); i++) {
/* Do not encode slashes or unreserved chars from RFC 3986 */
CURLcode result = CURLE_OK;
unsigned char c = p[i];
if(is_reserved_char(c) || c == '/')
result = curlx_dyn_addn(new_path, &c, 1);
else
result = curlx_dyn_addf(new_path, "%%%02X", c);
if(result)
return result;
}
return CURLE_OK;
}
static CURLcode encode_query_component(char *component, size_t len,
struct dynbuf *db)
{
size_t i;
for(i = 0; i < len; i++) {
CURLcode result = CURLE_OK;
unsigned char this_char = component[i];
if(is_reserved_char(this_char))
/* Escape unreserved chars from RFC 3986 */
result = curlx_dyn_addn(db, &this_char, 1);
else if(this_char == '+')
/* Encode '+' as space */
result = curlx_dyn_add(db, "%20");
else
result = curlx_dyn_addf(db, "%%%02X", this_char);
if(result)
return result;
}
return CURLE_OK;
}
/*
* Populates a dynbuf containing url_encode(url_decode(in))
*/
static CURLcode http_aws_decode_encode(const char *in, size_t in_len,
struct dynbuf *out)
{
char *out_s;
size_t out_s_len;
CURLcode result =
Curl_urldecode(in, in_len, &out_s, &out_s_len, REJECT_NADA);
if(!result) {
result = encode_query_component(out_s, out_s_len, out);
Curl_safefree(out_s);
}
return result;
}
static bool should_urlencode(struct Curl_str *service_name)
{
/*
* These services require unmodified (not additionally URL-encoded) URL
* paths.
* should_urlencode == true is equivalent to should_urlencode_uri_path
* from the AWS SDK. Urls are already normalized by the curl URL parser
*/
if(curlx_str_cmp(service_name, "s3") ||
curlx_str_cmp(service_name, "s3-express") ||
curlx_str_cmp(service_name, "s3-outposts")) {
return false;
}
return true;
}
/* maximum length for the aws sivg4 parts */
#define MAX_SIGV4_LEN 64
#define DATE_HDR_KEY_LEN (MAX_SIGV4_LEN + sizeof("X--Date"))
@ -973,172 +1124,4 @@ fail:
return result;
}
/*
* Frees all allocated strings in a dynbuf pair array, and the dynbuf itself
*/
static void pair_array_free(struct pair *pair_array, size_t num_elements)
{
size_t index;
for(index = 0; index != num_elements; index++) {
curlx_dyn_free(&pair_array[index].key);
curlx_dyn_free(&pair_array[index].value);
}
}
/*
* Frees all allocated strings in a split dynbuf, and the dynbuf itself
*/
static void dyn_array_free(struct dynbuf *db, size_t num_elements)
{
size_t index;
for(index = 0; index < num_elements; index++)
curlx_dyn_free((&db[index]));
}
/*
* Splits source string by SPLIT_BY, and creates an array of dynbuf in db.
* db is initialized by this function.
* Caller is responsible for freeing the array elements with dyn_array_free
*/
#define SPLIT_BY '&'
static CURLcode split_to_dyn_array(const char *source,
struct dynbuf db[MAX_QUERY_COMPONENTS],
size_t *num_splits_out)
{
CURLcode result = CURLE_OK;
size_t len = strlen(source);
size_t pos; /* Position in result buffer */
size_t start = 0; /* Start of current segment */
size_t segment_length = 0;
size_t index = 0;
size_t num_splits = 0;
/* Split source_ptr on SPLIT_BY and store the segment offsets and length in
* array */
for(pos = 0; pos < len; pos++) {
if(source[pos] == SPLIT_BY) {
if(segment_length) {
curlx_dyn_init(&db[index], segment_length + 1);
result = curlx_dyn_addn(&db[index], &source[start], segment_length);
if(result)
goto fail;
segment_length = 0;
index++;
if(++num_splits == MAX_QUERY_COMPONENTS) {
result = CURLE_TOO_LARGE;
goto fail;
}
}
start = pos + 1;
}
else {
segment_length++;
}
}
if(segment_length) {
curlx_dyn_init(&db[index], segment_length + 1);
result = curlx_dyn_addn(&db[index], &source[start], segment_length);
if(!result) {
if(++num_splits == MAX_QUERY_COMPONENTS)
result = CURLE_TOO_LARGE;
}
}
fail:
*num_splits_out = num_splits;
return result;
}
static bool is_reserved_char(const char c)
{
return (ISALNUM(c) || ISURLPUNTCS(c));
}
static CURLcode uri_encode_path(struct Curl_str *original_path,
struct dynbuf *new_path)
{
const char *p = curlx_str(original_path);
size_t i;
for(i = 0; i < curlx_strlen(original_path); i++) {
/* Do not encode slashes or unreserved chars from RFC 3986 */
CURLcode result = CURLE_OK;
unsigned char c = p[i];
if(is_reserved_char(c) || c == '/')
result = curlx_dyn_addn(new_path, &c, 1);
else
result = curlx_dyn_addf(new_path, "%%%02X", c);
if(result)
return result;
}
return CURLE_OK;
}
static CURLcode encode_query_component(char *component, size_t len,
struct dynbuf *db)
{
size_t i;
for(i = 0; i < len; i++) {
CURLcode result = CURLE_OK;
unsigned char this_char = component[i];
if(is_reserved_char(this_char))
/* Escape unreserved chars from RFC 3986 */
result = curlx_dyn_addn(db, &this_char, 1);
else if(this_char == '+')
/* Encode '+' as space */
result = curlx_dyn_add(db, "%20");
else
result = curlx_dyn_addf(db, "%%%02X", this_char);
if(result)
return result;
}
return CURLE_OK;
}
/*
* Populates a dynbuf containing url_encode(url_decode(in))
*/
static CURLcode http_aws_decode_encode(const char *in, size_t in_len,
struct dynbuf *out)
{
char *out_s;
size_t out_s_len;
CURLcode result =
Curl_urldecode(in, in_len, &out_s, &out_s_len, REJECT_NADA);
if(!result) {
result = encode_query_component(out_s, out_s_len, out);
Curl_safefree(out_s);
}
return result;
}
static bool should_urlencode(struct Curl_str *service_name)
{
/*
* These services require unmodified (not additionally URL-encoded) URL
* paths.
* should_urlencode == true is equivalent to should_urlencode_uri_path
* from the AWS SDK. Urls are already normalized by the curl URL parser
*/
if(curlx_str_cmp(service_name, "s3") ||
curlx_str_cmp(service_name, "s3-express") ||
curlx_str_cmp(service_name, "s3-outposts")) {
return false;
}
return true;
}
#endif /* !CURL_DISABLE_HTTP && !CURL_DISABLE_AWS */

View file

@ -80,19 +80,6 @@
*/
/*
* parsedate()
*
* Returns:
*
* PARSEDATE_OK - a fine conversion
* PARSEDATE_FAIL - failed to convert
* PARSEDATE_LATER - time overflow at the far end of time_t
* PARSEDATE_SOONER - time underflow at the low end of time_t
*/
static int parsedate(const char *date, time_t *output);
#define PARSEDATE_OK 0
#define PARSEDATE_FAIL -1
#define PARSEDATE_LATER 1

View file

@ -107,8 +107,6 @@
#include <openssl/store.h>
/* this is used in the following conditions to make them easier to read */
#define OPENSSL_HAS_PROVIDERS
static void ossl_provider_cleanup(struct Curl_easy *data);
#endif
/* AWS-LC fixed a bug with large buffers in v1.61.0 which also introduced
@ -181,8 +179,6 @@ typedef unsigned long sslerr_t;
#endif
#define ossl_valsize_t numcert_t
static CURLcode ossl_certchain(struct Curl_easy *data, SSL *ssl);
static CURLcode push_certinfo(struct Curl_easy *data,
BIO *mem, const char *label, int num)
WARN_UNUSED_RESULT;

View file

@ -36,8 +36,6 @@
#include "tool_libinfo.h"
#include "tool_strdup.h"
static char *parse_filename(const char *ptr, size_t len);
#ifdef _WIN32
#define BOLD "\x1b[1m"
#define BOLDOFF "\x1b[22m"
@ -54,10 +52,175 @@ static char *parse_filename(const char *ptr, size_t len);
#endif
#ifdef LINK
/*
* Treat the Location: header specially, by writing a special escape
* sequence that adds a hyperlink to the displayed text. This makes
* the absolute URL of the redirect clickable in supported terminals,
* which could not happen otherwise for relative URLs. The Location:
* header is supposed to always be absolute so this theoretically
* should not be needed but the real world returns plenty of relative
* URLs here.
*/
static void write_linked_location(CURL *curl, const char *location,
size_t loclen, FILE *stream);
size_t loclen, FILE *stream)
{
/* This would so simple if CURLINFO_REDIRECT_URL were available here */
CURLU *u = NULL;
char *copyloc = NULL, *locurl = NULL, *scheme = NULL, *finalurl = NULL;
const char *loc = location;
size_t llen = loclen;
int space_skipped = 0;
const char *vver = getenv("VTE_VERSION");
if(vver) {
curl_off_t num;
if(curlx_str_number(&vver, &num, CURL_OFF_T_MAX) ||
/* Skip formatting for old versions of VTE <= 0.48.1 (Mar 2017) since
some of those versions have formatting bugs. (#10428) */
(num <= 4801))
goto locout;
}
/* Strip leading whitespace of the redirect URL */
while(llen && (*loc == ' ' || *loc == '\t')) {
++loc;
--llen;
++space_skipped;
}
/* Strip the trailing end-of-line characters, normally "\r\n" */
while(llen && (loc[llen - 1] == '\n' || loc[llen - 1] == '\r'))
--llen;
/* CURLU makes it easy to handle the relative URL case */
u = curl_url();
if(!u)
goto locout;
/* Create a null-terminated and whitespace-stripped copy of Location: */
copyloc = memdup0(loc, llen);
if(!copyloc)
goto locout;
/* The original URL to use as a base for a relative redirect URL */
if(curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &locurl))
goto locout;
if(curl_url_set(u, CURLUPART_URL, locurl, 0))
goto locout;
/* Redirected location. This can be either absolute or relative. */
if(curl_url_set(u, CURLUPART_URL, copyloc, 0))
goto locout;
if(curl_url_get(u, CURLUPART_URL, &finalurl, CURLU_NO_DEFAULT_PORT))
goto locout;
if(curl_url_get(u, CURLUPART_SCHEME, &scheme, 0))
goto locout;
if(!strcmp("http", scheme) ||
!strcmp("https", scheme) ||
!strcmp("ftp", scheme) ||
!strcmp("ftps", scheme)) {
curl_mfprintf(stream, "%.*s" LINK "%s" LINKST "%.*s" LINKOFF,
space_skipped, location,
finalurl,
(int)loclen - space_skipped, loc);
goto locdone;
}
/* Not a "safe" URL: do not linkify it */
locout:
/* Write the normal output in case of error or unsafe */
fwrite(location, loclen, 1, stream);
locdone:
if(u) {
curl_free(finalurl);
curl_free(scheme);
curl_url_cleanup(u);
curlx_free(copyloc);
}
}
#endif
/*
* Copies a filename part and returns an ALLOCATED data buffer.
*/
static char *parse_filename(const char *ptr, size_t len)
{
char *copy;
char *p;
char *q;
char stop = '\0';
copy = memdup0(ptr, len);
if(!copy)
return NULL;
p = copy;
if(*p == '\'' || *p == '"') {
/* store the starting quote */
stop = *p;
p++;
}
else
stop = ';';
/* scan for the end letter and stop there */
q = strchr(p, stop);
if(q)
*q = '\0';
/* if the filename contains a path, only use filename portion */
q = strrchr(p, '/');
if(q) {
p = q + 1;
if(!*p) {
tool_safefree(copy);
return NULL;
}
}
/* If the filename contains a backslash, only use filename portion. The idea
is that even systems that do not handle backslashes as path separators
probably want the path removed for convenience. */
q = strrchr(p, '\\');
if(q) {
p = q + 1;
if(!*p) {
tool_safefree(copy);
return NULL;
}
}
/* make sure the filename does not end in \r or \n */
q = strchr(p, '\r');
if(q)
*q = '\0';
q = strchr(p, '\n');
if(q)
*q = '\0';
if(copy != p)
memmove(copy, p, strlen(p) + 1);
#if defined(_WIN32) || defined(MSDOS)
{
char *sanitized;
SANITIZEcode sc = sanitize_file_name(&sanitized, copy, 0);
tool_safefree(copy);
if(sc)
return NULL;
copy = sanitized;
}
#endif /* _WIN32 || MSDOS */
return copy;
}
int tool_write_headers(struct HdrCbData *hdrcbdata, FILE *stream)
{
struct curl_slist *h = hdrcbdata->headlist;
@ -310,173 +473,3 @@ size_t tool_header_cb(char *ptr, size_t size, size_t nmemb, void *userdata)
}
return cb;
}
/*
* Copies a filename part and returns an ALLOCATED data buffer.
*/
static char *parse_filename(const char *ptr, size_t len)
{
char *copy;
char *p;
char *q;
char stop = '\0';
copy = memdup0(ptr, len);
if(!copy)
return NULL;
p = copy;
if(*p == '\'' || *p == '"') {
/* store the starting quote */
stop = *p;
p++;
}
else
stop = ';';
/* scan for the end letter and stop there */
q = strchr(p, stop);
if(q)
*q = '\0';
/* if the filename contains a path, only use filename portion */
q = strrchr(p, '/');
if(q) {
p = q + 1;
if(!*p) {
tool_safefree(copy);
return NULL;
}
}
/* If the filename contains a backslash, only use filename portion. The idea
is that even systems that do not handle backslashes as path separators
probably want the path removed for convenience. */
q = strrchr(p, '\\');
if(q) {
p = q + 1;
if(!*p) {
tool_safefree(copy);
return NULL;
}
}
/* make sure the filename does not end in \r or \n */
q = strchr(p, '\r');
if(q)
*q = '\0';
q = strchr(p, '\n');
if(q)
*q = '\0';
if(copy != p)
memmove(copy, p, strlen(p) + 1);
#if defined(_WIN32) || defined(MSDOS)
{
char *sanitized;
SANITIZEcode sc = sanitize_file_name(&sanitized, copy, 0);
tool_safefree(copy);
if(sc)
return NULL;
copy = sanitized;
}
#endif /* _WIN32 || MSDOS */
return copy;
}
#ifdef LINK
/*
* Treat the Location: header specially, by writing a special escape
* sequence that adds a hyperlink to the displayed text. This makes
* the absolute URL of the redirect clickable in supported terminals,
* which could not happen otherwise for relative URLs. The Location:
* header is supposed to always be absolute so this theoretically
* should not be needed but the real world returns plenty of relative
* URLs here.
*/
static void write_linked_location(CURL *curl, const char *location,
size_t loclen, FILE *stream)
{
/* This would so simple if CURLINFO_REDIRECT_URL were available here */
CURLU *u = NULL;
char *copyloc = NULL, *locurl = NULL, *scheme = NULL, *finalurl = NULL;
const char *loc = location;
size_t llen = loclen;
int space_skipped = 0;
const char *vver = getenv("VTE_VERSION");
if(vver) {
curl_off_t num;
if(curlx_str_number(&vver, &num, CURL_OFF_T_MAX) ||
/* Skip formatting for old versions of VTE <= 0.48.1 (Mar 2017) since
some of those versions have formatting bugs. (#10428) */
(num <= 4801))
goto locout;
}
/* Strip leading whitespace of the redirect URL */
while(llen && (*loc == ' ' || *loc == '\t')) {
++loc;
--llen;
++space_skipped;
}
/* Strip the trailing end-of-line characters, normally "\r\n" */
while(llen && (loc[llen - 1] == '\n' || loc[llen - 1] == '\r'))
--llen;
/* CURLU makes it easy to handle the relative URL case */
u = curl_url();
if(!u)
goto locout;
/* Create a null-terminated and whitespace-stripped copy of Location: */
copyloc = memdup0(loc, llen);
if(!copyloc)
goto locout;
/* The original URL to use as a base for a relative redirect URL */
if(curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &locurl))
goto locout;
if(curl_url_set(u, CURLUPART_URL, locurl, 0))
goto locout;
/* Redirected location. This can be either absolute or relative. */
if(curl_url_set(u, CURLUPART_URL, copyloc, 0))
goto locout;
if(curl_url_get(u, CURLUPART_URL, &finalurl, CURLU_NO_DEFAULT_PORT))
goto locout;
if(curl_url_get(u, CURLUPART_SCHEME, &scheme, 0))
goto locout;
if(!strcmp("http", scheme) ||
!strcmp("https", scheme) ||
!strcmp("ftp", scheme) ||
!strcmp("ftps", scheme)) {
curl_mfprintf(stream, "%.*s" LINK "%s" LINKST "%.*s" LINKOFF,
space_skipped, location,
finalurl,
(int)loclen - space_skipped, loc);
goto locdone;
}
/* Not a "safe" URL: do not linkify it */
locout:
/* Write the normal output in case of error or unsafe */
fwrite(location, loclen, 1, stream);
locdone:
if(u) {
curl_free(finalurl);
curl_free(scheme);
curl_url_cleanup(u);
curlx_free(copyloc);
}
}
#endif

View file

@ -35,66 +35,6 @@
#include <http_request.h>
#include <http_log.h>
static void curltest_hooks(apr_pool_t *pool);
static int curltest_echo_handler(request_rec *r);
static int curltest_put_handler(request_rec *r);
static int curltest_tweak_handler(request_rec *r);
static int curltest_1_1_required(request_rec *r);
static int curltest_sslinfo_handler(request_rec *r);
AP_DECLARE_MODULE(curltest) =
{
STANDARD20_MODULE_STUFF,
NULL, /* func to create per-directory config */
NULL, /* func to merge per-directory config */
NULL, /* func to create per-server config */
NULL, /* func to merge per-server config */
NULL, /* command handlers */
curltest_hooks,
#ifdef AP_MODULE_FLAG_NONE
AP_MODULE_FLAG_ALWAYS_MERGE
#endif
};
static int curltest_post_config(apr_pool_t *p, apr_pool_t *plog,
apr_pool_t *ptemp, server_rec *s)
{
void *data = NULL;
const char *key = "mod_curltest_init_counter";
(void)p;
(void)plog;
(void)ptemp;
apr_pool_userdata_get(&data, key, s->process->pool);
if(!data) {
/* dry run */
apr_pool_userdata_set((const void *)1, key,
apr_pool_cleanup_null, s->process->pool);
return APR_SUCCESS;
}
/* mess with the overall server here */
return APR_SUCCESS;
}
static void curltest_hooks(apr_pool_t *pool)
{
ap_log_perror(APLOG_MARK, APLOG_TRACE1, 0, pool, "installing hooks");
/* Run once after configuration is set, but before mpm children initialize.
*/
ap_hook_post_config(curltest_post_config, NULL, NULL, APR_HOOK_MIDDLE);
/* curl test handlers */
ap_hook_handler(curltest_echo_handler, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_handler(curltest_put_handler, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_handler(curltest_tweak_handler, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_handler(curltest_1_1_required, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_handler(curltest_sslinfo_handler, NULL, NULL, APR_HOOK_MIDDLE);
}
#define SECS_PER_HOUR (60 * 60)
#define SECS_PER_DAY (24 * SECS_PER_HOUR)
@ -883,3 +823,56 @@ cleanup:
}
return DECLINED;
}
static int curltest_post_config(apr_pool_t *p, apr_pool_t *plog,
apr_pool_t *ptemp, server_rec *s)
{
void *data = NULL;
const char *key = "mod_curltest_init_counter";
(void)p;
(void)plog;
(void)ptemp;
apr_pool_userdata_get(&data, key, s->process->pool);
if(!data) {
/* dry run */
apr_pool_userdata_set((const void *)1, key,
apr_pool_cleanup_null, s->process->pool);
return APR_SUCCESS;
}
/* mess with the overall server here */
return APR_SUCCESS;
}
static void curltest_hooks(apr_pool_t *pool)
{
ap_log_perror(APLOG_MARK, APLOG_TRACE1, 0, pool, "installing hooks");
/* Run once after configuration is set, but before mpm children initialize.
*/
ap_hook_post_config(curltest_post_config, NULL, NULL, APR_HOOK_MIDDLE);
/* curl test handlers */
ap_hook_handler(curltest_echo_handler, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_handler(curltest_put_handler, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_handler(curltest_tweak_handler, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_handler(curltest_1_1_required, NULL, NULL, APR_HOOK_MIDDLE);
ap_hook_handler(curltest_sslinfo_handler, NULL, NULL, APR_HOOK_MIDDLE);
}
AP_DECLARE_MODULE(curltest) =
{
STANDARD20_MODULE_STUFF,
NULL, /* func to create per-directory config */
NULL, /* func to merge per-directory config */
NULL, /* func to create per-server config */
NULL, /* func to merge per-server config */
NULL, /* command handlers */
curltest_hooks,
#ifdef AP_MODULE_FLAG_NONE
AP_MODULE_FLAG_ALWAYS_MERGE
#endif
};

View file

@ -770,182 +770,6 @@ storerequest_cleanup:
errno, curlx_strerror(errno, errbuf, sizeof(errbuf)));
}
static void init_httprequest(struct sws_httprequest *req)
{
req->checkindex = 0;
req->offset = 0;
req->testno = DOCNUMBER_NOTHING;
req->partno = 0;
req->connect_request = FALSE;
req->open = TRUE;
req->auth_req = FALSE;
req->auth = FALSE;
req->cl = 0;
req->digest = FALSE;
req->ntlm = FALSE;
req->skip = 0;
req->skipall = FALSE;
req->noexpect = FALSE;
req->delay = 0;
req->writedelay = 0;
req->rcmd = RCMD_NORMALREQ;
req->prot_version = 0;
req->callcount = 0;
req->connect_port = 0;
req->done_processing = 0;
req->upgrade = 0;
req->upgrade_request = 0;
}
static int sws_send_doc(curl_socket_t sock, struct sws_httprequest *req);
/* returns 1 if the connection should be serviced again immediately, 0 if there
is no data waiting, or < 0 if it should be closed */
static int sws_get_request(curl_socket_t sock, struct sws_httprequest *req)
{
int fail = 0;
char *reqbuf = req->reqbuf;
ssize_t got = 0;
int overflow = 0;
if(req->upgrade_request) {
/* upgraded connection, work it differently until end of connection */
logmsg("Upgraded connection, this is no longer HTTP/1");
sws_send_doc(sock, req);
/* dump the request received so far to the external file */
reqbuf[req->offset] = '\0';
sws_storerequest(reqbuf, req->offset);
req->offset = 0;
/* read websocket traffic */
if(req->open) {
logmsg("wait for websocket traffic");
do {
got = sread(sock, reqbuf + req->offset,
sizeof(req->reqbuf) - req->offset);
if(got > 0) {
req->offset += got;
logmsg("Got %zu bytes from client", got);
}
if((got == -1) &&
((SOCKERRNO == EAGAIN) || (SOCKERRNO == SOCKEWOULDBLOCK))) {
int rc;
fd_set input;
fd_set output;
struct timeval timeout = { 0 };
timeout.tv_sec = 1; /* 1000 ms */
logmsg("Got EAGAIN from sread");
FD_ZERO(&input);
FD_ZERO(&output);
got = 0;
#ifdef __DJGPP__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Warith-conversion"
#endif
FD_SET(sock, &input);
#ifdef __DJGPP__
#pragma GCC diagnostic pop
#endif
do {
logmsg("Wait until readable");
rc = select((int)sock + 1, &input, &output, NULL, &timeout);
} while(rc < 0 && SOCKERRNO == SOCKEINTR && !got_exit_signal);
logmsg("readable %d", rc);
if(rc)
got = 1;
}
} while(got > 0);
}
else {
logmsg("NO wait for websocket traffic");
}
if(req->offset) {
logmsg("log the websocket traffic");
/* dump the incoming websocket traffic to the external file */
reqbuf[req->offset] = '\0';
sws_storerequest(reqbuf, req->offset);
req->offset = 0;
}
init_httprequest(req);
return -1;
}
if(req->offset >= sizeof(req->reqbuf) - 1) {
/* buffer is already full; do nothing */
overflow = 1;
}
else {
if(req->skip)
/* we are instructed to not read the entire thing, so we make sure to
only read what we are supposed to and NOT read the entire thing the
client wants to send! */
got = sread(sock, reqbuf + req->offset, req->cl);
else
got = sread(sock, reqbuf + req->offset,
sizeof(req->reqbuf) - 1 - req->offset);
if(got_exit_signal)
return -1;
if(got == 0) {
logmsg("Connection closed by client");
fail = 1;
}
else if(got < 0) {
char errbuf[STRERROR_LEN];
int error = SOCKERRNO;
if(EAGAIN == error || SOCKEWOULDBLOCK == error) {
/* nothing to read at the moment */
return 0;
}
logmsg("recv() returned error (%d) %s",
error, curlx_strerror(error, errbuf, sizeof(errbuf)));
fail = 1;
}
if(fail) {
/* dump the request received so far to the external file */
reqbuf[req->offset] = '\0';
sws_storerequest(reqbuf, req->offset);
return -1;
}
logmsg("Read %zd bytes", got);
req->offset += (size_t)got;
reqbuf[req->offset] = '\0';
req->done_processing = sws_ProcessRequest(req);
if(got_exit_signal)
return -1;
}
if(overflow || (req->offset == sizeof(req->reqbuf) - 1 && got > 0)) {
logmsg("Request would overflow buffer, closing connection");
/* dump request received so far to external file anyway */
reqbuf[sizeof(req->reqbuf) - 1] = '\0';
fail = 1;
}
else if(req->offset > sizeof(req->reqbuf) - 1) {
logmsg("Request buffer overflow, closing connection");
/* dump request received so far to external file anyway */
reqbuf[sizeof(req->reqbuf) - 1] = '\0';
fail = 1;
}
else
reqbuf[req->offset] = '\0';
/* at the end of a request dump it to an external file */
if(fail || req->done_processing)
sws_storerequest(reqbuf, req->offset);
if(got_exit_signal)
return -1;
return fail ? -1 : 1;
}
/* returns -1 on failure */
static int sws_send_doc(curl_socket_t sock, struct sws_httprequest *req)
{
@ -1225,6 +1049,180 @@ retry:
return 0;
}
static void init_httprequest(struct sws_httprequest *req)
{
req->checkindex = 0;
req->offset = 0;
req->testno = DOCNUMBER_NOTHING;
req->partno = 0;
req->connect_request = FALSE;
req->open = TRUE;
req->auth_req = FALSE;
req->auth = FALSE;
req->cl = 0;
req->digest = FALSE;
req->ntlm = FALSE;
req->skip = 0;
req->skipall = FALSE;
req->noexpect = FALSE;
req->delay = 0;
req->writedelay = 0;
req->rcmd = RCMD_NORMALREQ;
req->prot_version = 0;
req->callcount = 0;
req->connect_port = 0;
req->done_processing = 0;
req->upgrade = 0;
req->upgrade_request = 0;
}
/* returns 1 if the connection should be serviced again immediately, 0 if there
is no data waiting, or < 0 if it should be closed */
static int sws_get_request(curl_socket_t sock, struct sws_httprequest *req)
{
int fail = 0;
char *reqbuf = req->reqbuf;
ssize_t got = 0;
int overflow = 0;
if(req->upgrade_request) {
/* upgraded connection, work it differently until end of connection */
logmsg("Upgraded connection, this is no longer HTTP/1");
sws_send_doc(sock, req);
/* dump the request received so far to the external file */
reqbuf[req->offset] = '\0';
sws_storerequest(reqbuf, req->offset);
req->offset = 0;
/* read websocket traffic */
if(req->open) {
logmsg("wait for websocket traffic");
do {
got = sread(sock, reqbuf + req->offset,
sizeof(req->reqbuf) - req->offset);
if(got > 0) {
req->offset += got;
logmsg("Got %zu bytes from client", got);
}
if((got == -1) &&
((SOCKERRNO == EAGAIN) || (SOCKERRNO == SOCKEWOULDBLOCK))) {
int rc;
fd_set input;
fd_set output;
struct timeval timeout = { 0 };
timeout.tv_sec = 1; /* 1000 ms */
logmsg("Got EAGAIN from sread");
FD_ZERO(&input);
FD_ZERO(&output);
got = 0;
#ifdef __DJGPP__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Warith-conversion"
#endif
FD_SET(sock, &input);
#ifdef __DJGPP__
#pragma GCC diagnostic pop
#endif
do {
logmsg("Wait until readable");
rc = select((int)sock + 1, &input, &output, NULL, &timeout);
} while(rc < 0 && SOCKERRNO == SOCKEINTR && !got_exit_signal);
logmsg("readable %d", rc);
if(rc)
got = 1;
}
} while(got > 0);
}
else {
logmsg("NO wait for websocket traffic");
}
if(req->offset) {
logmsg("log the websocket traffic");
/* dump the incoming websocket traffic to the external file */
reqbuf[req->offset] = '\0';
sws_storerequest(reqbuf, req->offset);
req->offset = 0;
}
init_httprequest(req);
return -1;
}
if(req->offset >= sizeof(req->reqbuf) - 1) {
/* buffer is already full; do nothing */
overflow = 1;
}
else {
if(req->skip)
/* we are instructed to not read the entire thing, so we make sure to
only read what we are supposed to and NOT read the entire thing the
client wants to send! */
got = sread(sock, reqbuf + req->offset, req->cl);
else
got = sread(sock, reqbuf + req->offset,
sizeof(req->reqbuf) - 1 - req->offset);
if(got_exit_signal)
return -1;
if(got == 0) {
logmsg("Connection closed by client");
fail = 1;
}
else if(got < 0) {
char errbuf[STRERROR_LEN];
int error = SOCKERRNO;
if(EAGAIN == error || SOCKEWOULDBLOCK == error) {
/* nothing to read at the moment */
return 0;
}
logmsg("recv() returned error (%d) %s",
error, curlx_strerror(error, errbuf, sizeof(errbuf)));
fail = 1;
}
if(fail) {
/* dump the request received so far to the external file */
reqbuf[req->offset] = '\0';
sws_storerequest(reqbuf, req->offset);
return -1;
}
logmsg("Read %zd bytes", got);
req->offset += (size_t)got;
reqbuf[req->offset] = '\0';
req->done_processing = sws_ProcessRequest(req);
if(got_exit_signal)
return -1;
}
if(overflow || (req->offset == sizeof(req->reqbuf) - 1 && got > 0)) {
logmsg("Request would overflow buffer, closing connection");
/* dump request received so far to external file anyway */
reqbuf[sizeof(req->reqbuf) - 1] = '\0';
fail = 1;
}
else if(req->offset > sizeof(req->reqbuf) - 1) {
logmsg("Request buffer overflow, closing connection");
/* dump request received so far to external file anyway */
reqbuf[sizeof(req->reqbuf) - 1] = '\0';
fail = 1;
}
else
reqbuf[req->offset] = '\0';
/* at the end of a request dump it to an external file */
if(fail || req->done_processing)
sws_storerequest(reqbuf, req->offset);
if(got_exit_signal)
return -1;
return fail ? -1 : 1;
}
static curl_socket_t connect_to(const char *ipaddr, unsigned short port)
{
srvr_sockaddr_union_t serveraddr;

File diff suppressed because it is too large Load diff