From 8de9db65575ccd8013753bb3d23426f0da2a669a Mon Sep 17 00:00:00 2001 From: Jeremy Harris Date: Sun, 26 Feb 2017 18:53:06 +0000 Subject: [PATCH] Add option to control use of shutdown by ${readsocket }. Bug 400 --- doc/doc-docbook/spec.xfpt | 13 ++++++++++++- doc/doc-txt/NewStuff | 3 +++ src/src/expand.c | 37 +++++++++++++++++++++++------------- test/scripts/0000-Basic/0373 | 5 ++++- test/stdout/0373 | 6 ++++++ 5 files changed, 49 insertions(+), 15 deletions(-) diff --git a/doc/doc-docbook/spec.xfpt b/doc/doc-docbook/spec.xfpt index 8b20910c1..054a135b9 100644 --- a/doc/doc-docbook/spec.xfpt +++ b/doc/doc-docbook/spec.xfpt @@ -9767,7 +9767,7 @@ locks out the use of this expansion item in filter files. .vitem "&*${readsocket{*&<&'name'&>&*}{*&<&'request'&>&*}&&& - {*&<&'timeout'&>&*}{*&<&'eol&~string'&>&*}{*&<&'fail&~string'&>&*}}*&" + {*&<&'options'&>&*}{*&<&'eol&~string'&>&*}{*&<&'fail&~string'&>&*}}*&" .cindex "expansion" "inserting from a socket" .cindex "socket, use of in expansion" .cindex "&%readsocket%& expansion item" @@ -9797,6 +9797,17 @@ extend what can be done. Firstly, you can vary the timeout. For example: .code ${readsocket{/socket/name}{request string}{3s}} .endd +.new +The third argument is a list of options, of which the first element is the timeout +and must be present if the argument is given. +Further elements are options of form &'name=value'&. +One option type is currently recognised, defining whether (the default) +or not a shutdown is done on the connection after sending the request. +Example, to not do so (preferred, eg. by some webservers): +.code +${readsocket{/socket/name}{request string}{3s:shutdown=no}} +.endd +.wen A fourth argument allows you to change any newlines that are in the data that is read, in the same way as for &%readfile%& (see above). This example turns them into spaces: diff --git a/doc/doc-txt/NewStuff b/doc/doc-txt/NewStuff index 2a8e520c6..efb8592cf 100644 --- a/doc/doc-txt/NewStuff +++ b/doc/doc-txt/NewStuff @@ -12,6 +12,9 @@ Version 4.90 1. PKG_CONFIG_PATH can now be set in Local/Makefile; wildcards will be expanded, values are collapsed. + 2. The ${readsocket } expansion now takes an option to not shutdown the + connection after sending the query string. The default remains to do so. + Version 4.89 ------------ diff --git a/src/src/expand.c b/src/src/expand.c index f85ee494e..1da858997 100644 --- a/src/src/expand.c +++ b/src/src/expand.c @@ -4726,8 +4726,9 @@ while (*s != 0) struct sockaddr_un sockun; /* don't call this "sun" ! */ uschar *arg; uschar *sub_arg[4]; + BOOL do_shutdown = TRUE; - if ((expand_forbid & RDO_READSOCK) != 0) + if (expand_forbid & RDO_READSOCK) { expand_string_message = US"socket insertions are not permitted"; goto EXPAND_FAILED; @@ -4743,17 +4744,27 @@ while (*s != 0) case 3: goto EXPAND_FAILED; } - /* Sort out timeout, if given */ + /* Sort out timeout, if given. The second arg is a list with the first element + being a time value. Any more are options of form "name=value". Currently the + only option recognised is "shutdown". */ - if (sub_arg[2] != NULL) + if (sub_arg[2]) { - timeout = readconf_readtime(sub_arg[2], 0, FALSE); - if (timeout < 0) + const uschar * list = sub_arg[2]; + uschar * item; + int sep = 0; + + item = string_nextinlist(&list, &sep, NULL, 0); + if ((timeout = readconf_readtime(item, 0, FALSE)) < 0) { - expand_string_message = string_sprintf("bad time value %s", - sub_arg[2]); + expand_string_message = string_sprintf("bad time value %s", item); goto EXPAND_FAILED; } + + while ((item = string_nextinlist(&list, &sep, NULL, 0))) + if (Ustrncmp(item, US"shutdown=", 9) == 0) + if (Ustrcmp(item + 9, US"no") == 0) + do_shutdown = FALSE; } else sub_arg[3] = NULL; /* No eol if no timeout */ @@ -4867,9 +4878,9 @@ while (*s != 0) recognise that it is their turn to do some work. Just in case some system doesn't have this function, make it conditional. */ - #ifdef SHUT_WR - shutdown(fd, SHUT_WR); - #endif +#ifdef SHUT_WR + if (do_shutdown) shutdown(fd, SHUT_WR); +#endif if (running_in_test_harness) millisleep(100); @@ -4909,7 +4920,7 @@ while (*s != 0) while (isspace(*s)) s++; } - readsock_done: + READSOCK_DONE: if (*s++ != '}') { expand_string_message = US"missing '}' closing readsocket"; @@ -4921,7 +4932,7 @@ while (*s != 0) socket, or timeout on reading. If another substring follows, expand and use it. Otherwise, those conditions give expand errors. */ - SOCK_FAIL: + SOCK_FAIL: if (*s != '{') goto EXPAND_FAILED; DEBUG(D_any) debug_printf("%s\n", expand_string_message); if (!(arg = expand_string_internal(s+1, TRUE, &s, FALSE, TRUE, &resetok))) @@ -4933,7 +4944,7 @@ while (*s != 0) goto EXPAND_FAILED_CURLY; } while (isspace(*s)) s++; - goto readsock_done; + goto READSOCK_DONE; } /* Handle "run" to execute a program. */ diff --git a/test/scripts/0000-Basic/0373 b/test/scripts/0000-Basic/0373 index d5e2cb182..02cdc31fc 100644 --- a/test/scripts/0000-Basic/0373 +++ b/test/scripts/0000-Basic/0373 @@ -58,7 +58,7 @@ quit # # Tests of IPv4 sockets # -server PORT_S 10 +server PORT_S 11 QUERY-1 >LF>ANSWER-1 >*eof @@ -85,6 +85,8 @@ QUERY-9 QUERY-10 >LF>ANSWER-10 >*eof +>LF>ANSWER-11 +>*eof **** millisleep 500 exim -be @@ -98,4 +100,5 @@ exim -be 8 >>${readsocket{inet:127.0.0.1:PORT_S}{QUERY-8\n}{1s}}<< 9 >>${readsocket{inet:127.0.0.1:PORT_S}{QUERY-9\n}{1s}{}{sock error}}<< 10 >>${readsocket{inet:badloop:PORT_S}{QUERY-10\n}}<< +11 >>${readsocket{inet:thisloop:PORT_S}{QUERY-11\n}{2s:shutdown=no}}<< **** diff --git a/test/stdout/0373 b/test/stdout/0373 index 88592ffe3..b6f6f1905 100644 --- a/test/stdout/0373 +++ b/test/stdout/0373 @@ -25,6 +25,8 @@ > 9 >>sock error<< > 10 >>ANSWER-10 << +> 11 >>ANSWER-11 +<< > ******** SERVER ******** @@ -120,4 +122,8 @@ Connection request from [127.0.0.1] QUERY-10 >LF>ANSWER-10 >*eof +Listening on port 1224 ... +Connection request from [ip4.ip4.ip4.ip4] +>LF>ANSWER-11 +>*eof End of script -- 2.25.1