mirror of
https://github.com/curl/curl.git
synced 2026-07-24 12:17:16 +03:00
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:
parent
8680a07589
commit
60f9d3dd7b
9 changed files with 1115 additions and 1210 deletions
|
|
@ -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 */
|
||||
|
|
|
|||
26
lib/hostip.c
26
lib/hostip.c
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
1070
tests/server/tftpd.c
1070
tests/server/tftpd.c
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue