Added option http-version

This commit is contained in:
Gerhard Rieger 2023-06-17 21:30:37 +02:00
parent 9f632ec651
commit 454a499401
9 changed files with 116 additions and 22 deletions

View file

@ -20,6 +20,11 @@ Features:
Added option ipv6-join-source-group.
Thanks to Martin Buck and David Schweizer for sending patches.
Added option http-version to PROXY-CONNECT address to support servers
that are not able to handle HTTP version 1.0
Test: PROXY_HTTPVERSION
Feature inspired by Robin Palotai.
Corrections:
When a sub process (EXEC, SYSTEM) terminated with exit code other than
0, its last sent data might have been lost depending on timing of read/

View file

@ -2421,6 +2421,10 @@ Options that can be provided with HTTP type addresses. The only HTTP address
currently implemented is link(proxy-connect)(ADDRESS_PROXY_CONNECT).
startdit()
label(OPTION_HTTP_VERSION)dit(bf(tt(http-version=<string>)))
Changes the default "1.0" that is sent to the server in the initial HTTP
request. Currently it has not other effect, in particular it does not
provide any means to send a Host header.
label(OPTION_PROXYPORT)dit(bf(tt(proxyport=<TCP service>)))
Overrides the default HTTP proxy port 8080 with
link(<TCP service>)(TYPE_TCP_SERVICE).

View file

@ -7,8 +7,8 @@
# accepts and answers correct HTTP CONNECT requests on stdio, and tries to
# establish the connection to the given server.
# it is required for socats test.sh
# for TCP, use this script as:
# socat tcp-l:8080,reuseaddr,fork exec:"proxy.sh",nofork
# for TCP, use this script like:
# socat TCP-L:8080,reuseaddr,fork EXEC:"proxy.sh",nofork
# 20130622 GR allow hostnames, not only IP addresses

View file

@ -7,7 +7,9 @@
# accepts and answers correct HTTP CONNECT requests, but then just echoes data.
# it is required for test.sh
# for TCP, use this script as:
# socat tcp-l:8080,reuseaddr,crlf system:"proxyecho.sh"
# socat TCP-L:8080,reuseaddr,crlf SYSTEM:"proxyecho.sh"
# 20230423 GR Added option -V to require particular HTTP version
if type socat >/dev/null 2>&1; then
SOCAT=socat
@ -24,11 +26,12 @@ HP-UX|OSF1)
;;
esac
SPACES=" "
SPACES=" " REQVER=1.0
while [ -n "$1" ]; do
case "$1" in
-w) n="$2"; while [ "$n" -gt 0 ]; do SPACES="$SPACES "; n=$((n-1)); done
shift ;;
-V) shift; REQVER="$1" ;;
#-s) STAT="$2"; shift ;;
esac
shift
@ -36,14 +39,18 @@ done
# read and parse HTTP request
read l
if echo "$l" |egrep '^CONNECT +[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:[0-9]+ +HTTP/1.[01]$' >/dev/null
if ! echo "$l" |egrep '^CONNECT +[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:[0-9]+ +HTTP/[1-3].[0-9]$' >/dev/null
then
: go on below
else
echo "HTTP/1.0${SPACES}500 Bad Request"
echo
exit
fi
if ! echo "$l" |egrep '^CONNECT +[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:[0-9]+ +HTTP/'"$REQVER"'$' >/dev/null
then
echo "HTTP/1.0${SPACES}426 Upgrade Required"
echo
exit
fi
# read more headers until empty line
while [ -n "$l" ]; do
@ -51,7 +58,7 @@ while [ -n "$l" ]; do
done
# send status
echo "HTTP/1.0${SPACES}200 OK"
echo "HTTP/$REQVER${SPACES}200 OK"
# send empty line
echo

93
test.sh
View file

@ -4128,27 +4128,31 @@ te="$td/test$N.stderr"
tdiff="$td/test$N.diff"
da="test$N $(date) $RANDOM"; da="$da$($ECHO '\r')"
newport tcp4 # provide free port number in $PORT
#CMD2="$TRACE $SOCAT $opts tcp-l:$PORT,crlf SYSTEM:\"read; read; $ECHO \\\"HTTP/1.0 200 OK\n\\\"; cat\""
CMD2="$TRACE $SOCAT $opts tcp4-l:$PORT,reuseaddr,crlf exec:\"/usr/bin/env bash proxyecho.sh -w 2\""
CMD="$TRACE $SOCAT $opts - proxy:$LOCALHOST:127.0.0.1:1000,pf=ip4,proxyport=$PORT"
#CMD2="$TRACE $SOCAT $opts TCP-L:$PORT,crlf SYSTEM:\"read; read; $ECHO \\\"HTTP/1.0 200 OK\n\\\"; cat\""
CMD0="$TRACE $SOCAT $opts TCP4-L:$PORT,reuseaddr,crlf EXEC:\"/usr/bin/env bash proxyecho.sh -w 2\""
CMD1="$TRACE $SOCAT $opts - PROXY:$LOCALHOST:127.0.0.1:1000,pf=ip4,proxyport=$PORT"
printf "test $F_n $TEST... " $N
eval "$CMD2 2>\"${te}1\" &"
eval "$CMD0 2>\"${te}1\" &"
pid=$! # background process id
waittcp4port $PORT 1
echo "$da" |$CMD >"$tf" 2>"${te}2"
echo "$da" |$CMD1 >"$tf" 2>"${te}0"
if ! echo "$da" |diff - "$tf" >"$tdiff"; then
$PRINTF "$FAILED: $TRACE $SOCAT:\n"
echo "$CMD2 &"
echo "$CMD"
cat "${te}1"
cat "${te}2"
echo "$CMD0 &"
cat "${te}0" >&2
echo "$CMD1"
cat "${te}1" >&2
echo "diff:"
cat "$tdiff"
numFAIL=$((numFAIL+1))
listFAIL="$listFAIL $N"
else
$PRINTF "$OK\n"
if [ -n "$debug" ]; then cat "${te}1" "${te}2"; fi
numOK=$((numOK+1))
$PRINTF "$OK\n"
if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi
if [ "$debug" ]; then cat "${te}0" >&2; fi
if [ "$VERBOSE" ]; then echo "$CMD1"; fi
if [ "$debug" ]; then cat "${te}1" >&2; fi
numOK=$((numOK+1))
fi
kill $pid 2>/dev/null
wait
@ -15153,6 +15157,71 @@ fi # NUMCOND
esac
N=$((N+1))
# Test the http-version of the PROXY-CONNECT address
NAME=PROXY_HTTPVERSION
case "$TESTS" in
*%$N%*|*%functions%*|*%proxy%*|*%$NAME%*)
TEST="$NAME: PROXY-CONNECT with option http-version"
if ! eval $NUMCOND; then :;
elif ! $(type proxyecho.sh >/dev/null 2>&1); then
$PRINTF "test $F_n $TEST... ${YELLOW}proxyecho.sh not available${NORMAL}\n" $N
numCANT=$((numCANT+1))
listCANT="$listCANT $N"
elif ! F=$(testfeats IP4 TCP LISTEN EXEC STDIO PROXY); then
$PRINTF "test $F_n $TEST... ${YELLOW}Feature $F not available${NORMAL}\n" $N
numCANT=$((numCANT+1))
listCANT="$listCANT $N"
elif ! A=$(testaddrs TCP4-LISTEN EXEC STDIO PROXY-CONNECT); then
$PRINTF "test $F_n $TEST... ${YELLOW}Address $A not available in $SOCAT${NORMAL}\n" $N
numCANT=$((numCANT+1))
listCANT="$listCANT $N"
elif ! o=$(testoptions so-reuseaddr crlf pf proxyport http-version) >/dev/null; then
$PRINTF "test $F_n $TEST... ${YELLOW}Option $o not available in $SOCAT${NORMAL}\n" $N
numCANT=$((numCANT+1))
listCANT="$listCANT $N"
elif ! runsip4 >/dev/null; then
$PRINTF "test $F_n $TEST... ${YELLOW}IPv4 not available${NORMAL}\n" $N
numCANT=$((numCANT+1))
listCANT="$listCANT $N"
else
ts="$td/test$N.sh"
tf="$td/test$N.stdout"
te="$td/test$N.stderr"
tdiff="$td/test$N.diff"
da="test$N $(date) $RANDOM"; da="$da$($ECHO '\r')"
CMD0="$TRACE $SOCAT $opts TCP4-L:$PORT,reuseaddr,crlf EXEC:\"/usr/bin/env bash proxyecho.sh -V 1.1\""
CMD1="$TRACE $SOCAT $opts - PROXY:$LOCALHOST:127.0.0.1:1000,pf=ip4,proxyport=$PORT,http-version=1.1"
printf "test $F_n $TEST... " $N
eval "$CMD0 2>\"${te}1\" &"
pid=$! # background process id
waittcp4port $PORT 1
echo "$da" |$CMD1 >"$tf" 2>"${te}0"
if ! echo "$da" |diff - "$tf" >"$tdiff"; then
$PRINTF "$FAILED: $TRACE $SOCAT:\n"
echo "$CMD0 &" >&2
cat "${te}0"
echo "$CMD1" >&2
cat "${te}1"
echo "diff:"
cat "$tdiff"
numFAIL=$((numFAIL+1))
listFAIL="$listFAIL $N"
else
$PRINTF "$OK\n"
if [ "$VERBOSE" ]; then echo "$CMD0 &"; fi
if [ "$debug" ]; then cat "${te}0" >&2; fi
if [ "$VERBOSE" ]; then echo "$CMD1"; fi
if [ "$debug" ]; then cat "${te}1" >&2; fi
numOK=$((numOK+1))
fi
kill $pid 2>/dev/null
wait
fi ;; # NUMCOND, feats
esac
PORT=$((PORT+1))
# end of common tests
##################################################################################

View file

@ -27,6 +27,7 @@ static int xioopen_proxy_connect(int argc, const char *argv[], struct opt *opts,
const struct optdesc opt_proxyport = { "proxyport", NULL, OPT_PROXYPORT, GROUP_HTTP, PH_LATE, TYPE_STRING, OFUNC_SPEC };
const struct optdesc opt_ignorecr = { "ignorecr", NULL, OPT_IGNORECR, GROUP_HTTP, PH_LATE, TYPE_BOOL, OFUNC_SPEC };
const struct optdesc opt_http_version = { "http-version", NULL, OPT_HTTP_VERSION, GROUP_HTTP, PH_LATE, TYPE_STRING, OFUNC_SPEC };
const struct optdesc opt_proxy_resolve = { "proxy-resolve", "resolve", OPT_PROXY_RESOLVE, GROUP_HTTP, PH_LATE, TYPE_BOOL, OFUNC_SPEC };
const struct optdesc opt_proxy_authorization = { "proxy-authorization", "proxyauth", OPT_PROXY_AUTHORIZATION, GROUP_HTTP, PH_LATE, TYPE_STRING, OFUNC_SPEC };
const struct optdesc opt_proxy_authorization_file = { "proxy-authorization-file", "proxyauthfile", OPT_PROXY_AUTHORIZATION_FILE, GROUP_HTTP, PH_LATE, TYPE_STRING, OFUNC_SPEC };
@ -239,6 +240,7 @@ int _xioopen_proxy_prepare(struct proxyvars *proxyvars, struct opt *opts,
retropt_bool(opts, OPT_IGNORECR, &proxyvars->ignorecr);
retropt_bool(opts, OPT_PROXY_RESOLVE, &proxyvars->doresolve);
retropt_string(opts, OPT_HTTP_VERSION, &proxyvars->version);
retropt_string(opts, OPT_PROXY_AUTHORIZATION, &proxyvars->authstring);
retropt_string(opts, OPT_PROXY_AUTHORIZATION_FILE, &proxyvars->authfile);
@ -331,8 +333,11 @@ int _xioopen_proxy_connect(struct single *xfd,
ssize_t sresult;
/* generate proxy request header - points to final target */
rv = snprintf(request, CONNLEN, "CONNECT %s:%u HTTP/1.0\r\n",
proxyvars->targetaddr, proxyvars->targetport);
if (proxyvars->version == NULL) {
proxyvars->version = "1.0";
}
rv = snprintf(request, CONNLEN, "CONNECT %s:%u HTTP/%s\r\n",
proxyvars->targetaddr, proxyvars->targetport, proxyvars->version);
if (rv >= CONNLEN || rv < 0) {
Error("_xioopen_proxy_connect(): PROXY CONNECT buffer too small");
return -1;

View file

@ -8,6 +8,7 @@
struct proxyvars {
bool ignorecr;
char *version;
bool doresolve;
char *authstring;
char *authfile;
@ -17,6 +18,7 @@ struct proxyvars {
extern const struct optdesc opt_proxyport;
extern const struct optdesc opt_ignorecr;
extern const struct optdesc opt_http_version;
extern const struct optdesc opt_proxy_resolve;
extern const struct optdesc opt_proxy_authorization;
extern const struct optdesc opt_proxy_authorization_file;

View file

@ -613,6 +613,7 @@ const struct optname optionnames[] = {
#if WITH_LIBWRAP && defined(HAVE_HOSTS_DENY_TABLE)
IF_IPAPP ("hosts-deny", &opt_tcpwrap_hosts_deny_table)
#endif
IF_PROXY ("http-version", &opt_http_version)
IF_TERMIOS("hup", &opt_hupcl)
IF_TERMIOS("hupcl", &opt_hupcl)
#ifdef I_POP

View file

@ -337,6 +337,7 @@ enum e_optcode {
OPT_GROUP_EARLY,
OPT_GROUP_LATE,
OPT_HISTORY_FILE, /* readline history file */
OPT_HTTP_VERSION,
OPT_HUPCL, /* termios.c_cflag */
OPT_ICANON, /* termios.c_lflag */
OPT_ICRNL, /* termios.c_iflag */