mirror of
https://github.com/owasp-modsecurity/ModSecurity.git
synced 2025-09-29 19:24:29 +03:00
More regression testing updates.
This commit is contained in:
@@ -135,7 +135,7 @@
|
||||
),
|
||||
match_log => {
|
||||
-error => [ qr/ModSecurity: /, 1 ],
|
||||
# ENH: No message, but should have data. Is this intended?
|
||||
# No message, but should have data. This may need changed
|
||||
audit => [ qr/-H--\s+Stopwatch: /s, 1 ],
|
||||
},
|
||||
match_response => {
|
||||
|
@@ -190,7 +190,7 @@
|
||||
SecDebugLogLevel 9
|
||||
SecRequestBodyAccess On
|
||||
SecRequestBodyLimit 1000
|
||||
SecRequestBodyInMemoryLimit 266
|
||||
SecRequestBodyInMemoryLimit 276
|
||||
),
|
||||
match_log => {
|
||||
-debug => [ qr/Input filter: Request too large to store in memory, switching to disk\./, 1 ],
|
||||
@@ -198,22 +198,32 @@
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => qq(
|
||||
POST /test.txt HTTP/1.1
|
||||
Host: $ENV{SERVER_NAME}:$ENV{SERVER_PORT}
|
||||
User-Agent: $ENV{USER_AGENT}
|
||||
Content-Type: multipart/form-data; boundary=---------------------------69343412719991675451336310646
|
||||
Transfer-Encoding: chunked
|
||||
request => normalize_raw_request_data(
|
||||
qq(
|
||||
POST /test.txt HTTP/1.1
|
||||
Host: $ENV{SERVER_NAME}:$ENV{SERVER_PORT}
|
||||
User-Agent: $ENV{USER_AGENT}
|
||||
Content-Type: multipart/form-data; boundary=---------------------------69343412719991675451336310646
|
||||
Transfer-Encoding: chunked
|
||||
|
||||
) . encode_chunked(q(-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data; name="a"
|
||||
),
|
||||
)
|
||||
.encode_chunked(
|
||||
normalize_raw_request_data(
|
||||
q(
|
||||
-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data; name="a"
|
||||
|
||||
1
|
||||
-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data; name="b"
|
||||
1
|
||||
-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data; name="b"
|
||||
|
||||
2
|
||||
-----------------------------69343412719991675451336310646--), 1024),
|
||||
2
|
||||
-----------------------------69343412719991675451336310646--
|
||||
)
|
||||
),
|
||||
1024
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "config",
|
||||
@@ -232,22 +242,32 @@ Content-Disposition: form-data; name="b"
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => qq(
|
||||
POST /test.txt HTTP/1.1
|
||||
Host: $ENV{SERVER_NAME}:$ENV{SERVER_PORT}
|
||||
User-Agent: $ENV{USER_AGENT}
|
||||
Content-Type: multipart/form-data; boundary=---------------------------69343412719991675451336310646
|
||||
Transfer-Encoding: chunked
|
||||
request => normalize_raw_request_data(
|
||||
qq(
|
||||
POST /test.txt HTTP/1.1
|
||||
Host: $ENV{SERVER_NAME}:$ENV{SERVER_PORT}
|
||||
User-Agent: $ENV{USER_AGENT}
|
||||
Content-Type: multipart/form-data; boundary=---------------------------69343412719991675451336310646
|
||||
Transfer-Encoding: chunked
|
||||
|
||||
) . encode_chunked(q(-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data; name="a"
|
||||
),
|
||||
)
|
||||
.encode_chunked(
|
||||
normalize_raw_request_data(
|
||||
q(
|
||||
-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data; name="a"
|
||||
|
||||
1
|
||||
-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data; name="b"
|
||||
1
|
||||
-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data; name="b"
|
||||
|
||||
2
|
||||
-----------------------------69343412719991675451336310646--), 1024),
|
||||
2
|
||||
-----------------------------69343412719991675451336310646--
|
||||
)
|
||||
),
|
||||
1024
|
||||
),
|
||||
},
|
||||
|
||||
# SecCookieFormat
|
||||
|
361
apache2/t/regression/misc/00-multipart-parser.t
Normal file
361
apache2/t/regression/misc/00-multipart-parser.t
Normal file
@@ -0,0 +1,361 @@
|
||||
### Multipart parser tests
|
||||
|
||||
# Final CRLF or not, we should still work
|
||||
{
|
||||
type => "misc",
|
||||
comment => "multipart parser (final CRLF)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRequestBodyAccess On
|
||||
SecRule MULTIPART_STRICT_ERROR "\@eq 1" "phase:2,deny"
|
||||
SecRule MULTIPART_UNMATCHED_BOUNDARY "\@eq 1" "phase:2,deny"
|
||||
SecRule REQBODY_PROCESSOR_ERROR "\@eq 1" "phase:2,deny"
|
||||
),
|
||||
match_log => {
|
||||
debug => [ qr/Adding request argument \(BODY\): name "a", value "1".*Adding request argument \(BODY\): name "b", value "2"/s, 1 ],
|
||||
-debug => [ qr/Multipart error:/, 1 ],
|
||||
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "multipart/form-data; boundary=---------------------------69343412719991675451336310646",
|
||||
],
|
||||
normalize_raw_request_data(
|
||||
q(
|
||||
-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data; name="a"
|
||||
|
||||
1
|
||||
-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data; name="b"
|
||||
|
||||
2
|
||||
-----------------------------69343412719991675451336310646--
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "misc",
|
||||
comment => "multipart parser (no final CRLF)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRequestBodyAccess On
|
||||
SecRule MULTIPART_STRICT_ERROR "\@eq 1" "phase:2,deny"
|
||||
SecRule MULTIPART_UNMATCHED_BOUNDARY "\@eq 1" "phase:2,deny"
|
||||
SecRule REQBODY_PROCESSOR_ERROR "\@eq 1" "phase:2,deny"
|
||||
),
|
||||
match_log => {
|
||||
debug => [ qr/Adding request argument \(BODY\): name "a", value "1".*Adding request argument \(BODY\): name "b", value "2"/s, 1 ],
|
||||
-debug => [ qr/Multipart error:/, 1 ],
|
||||
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "multipart/form-data; boundary=---------------------------69343412719991675451336310646",
|
||||
],
|
||||
normalize_raw_request_data(
|
||||
q(
|
||||
-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data; name="a"
|
||||
|
||||
1
|
||||
-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data; name="b"
|
||||
|
||||
2
|
||||
-----------------------------69343412719991675451336310646--),
|
||||
),
|
||||
),
|
||||
},
|
||||
|
||||
# Should work with a boundary of "boundary"
|
||||
{
|
||||
type => "misc",
|
||||
comment => "multipart parser (boundary contains \"boundary\")",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRequestBodyAccess On
|
||||
SecRule MULTIPART_STRICT_ERROR "\@eq 1" "phase:2,deny"
|
||||
SecRule MULTIPART_UNMATCHED_BOUNDARY "\@eq 1" "phase:2,deny"
|
||||
SecRule REQBODY_PROCESSOR_ERROR "\@eq 1" "phase:2,deny"
|
||||
),
|
||||
match_log => {
|
||||
debug => [ qr/Adding request argument \(BODY\): name "a", value "1".*Adding request argument \(BODY\): name "b", value "2"/s, 1 ],
|
||||
-debug => [ qr/Multipart error:/, 1 ],
|
||||
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "multipart/form-data; boundary=------------------------------------------------boundary",
|
||||
],
|
||||
normalize_raw_request_data(
|
||||
q(
|
||||
--------------------------------------------------boundary
|
||||
Content-Disposition: form-data; name="a"
|
||||
|
||||
1
|
||||
--------------------------------------------------boundary
|
||||
Content-Disposition: form-data; name="b"
|
||||
|
||||
2
|
||||
--------------------------------------------------boundary--
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "misc",
|
||||
comment => "multipart parser (boundary contains \"BoUnDaRy\")",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRequestBodyAccess On
|
||||
SecRule MULTIPART_STRICT_ERROR "\@eq 1" "phase:2,deny"
|
||||
SecRule MULTIPART_UNMATCHED_BOUNDARY "\@eq 1" "phase:2,deny"
|
||||
SecRule REQBODY_PROCESSOR_ERROR "\@eq 1" "phase:2,deny"
|
||||
),
|
||||
match_log => {
|
||||
debug => [ qr/Adding request argument \(BODY\): name "a", value "1".*Adding request argument \(BODY\): name "b", value "2"/s, 1 ],
|
||||
-debug => [ qr/Multipart error:/, 1 ],
|
||||
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "multipart/form-data; boundary=------------------------------------------------BoUnDaRy",
|
||||
],
|
||||
normalize_raw_request_data(
|
||||
q(
|
||||
--------------------------------------------------BoUnDaRy
|
||||
Content-Disposition: form-data; name="a"
|
||||
|
||||
1
|
||||
--------------------------------------------------BoUnDaRy
|
||||
Content-Disposition: form-data; name="b"
|
||||
|
||||
2
|
||||
--------------------------------------------------BoUnDaRy--
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
|
||||
# We should handle data starting with a "--"
|
||||
{
|
||||
type => "misc",
|
||||
comment => "multipart parser (data contains \"--\")",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRequestBodyAccess On
|
||||
SecRule MULTIPART_STRICT_ERROR "\@eq 1" "phase:2,deny"
|
||||
SecRule REQBODY_PROCESSOR_ERROR "\@eq 1" "phase:2,deny"
|
||||
),
|
||||
match_log => {
|
||||
debug => [ qr/Adding request argument \(BODY\): name "a", value "--test".*Adding request argument \(BODY\): name "b", value "--"/s, 1 ],
|
||||
-debug => [ qr/Multipart error:/, 1 ],
|
||||
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "multipart/form-data; boundary=---------------------------69343412719991675451336310646",
|
||||
],
|
||||
normalize_raw_request_data(
|
||||
q(
|
||||
-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data; name="a"
|
||||
|
||||
--test
|
||||
-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data; name="b"
|
||||
|
||||
--
|
||||
-----------------------------69343412719991675451336310646--),
|
||||
),
|
||||
),
|
||||
},
|
||||
|
||||
# We should emit warnings for parsing errors
|
||||
{
|
||||
type => "misc",
|
||||
comment => "multipart parser error (no final boundary)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRequestBodyAccess On
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecAuditEngine RelevantOnly
|
||||
),
|
||||
match_log => {
|
||||
audit => [ qr/Final boundary missing/, 1 ],
|
||||
debug => [ qr/Final boundary missing/, 1 ],
|
||||
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "multipart/form-data; boundary=---------------------------69343412719991675451336310646",
|
||||
],
|
||||
normalize_raw_request_data(
|
||||
q(
|
||||
-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data; name="a"
|
||||
|
||||
1
|
||||
-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data; name="b"
|
||||
|
||||
2
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "misc",
|
||||
comment => "multipart parser error (no disposition)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRequestBodyAccess On
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecAuditEngine RelevantOnly
|
||||
),
|
||||
match_log => {
|
||||
-debug => [ qr/Multipart error:/, 1 ],
|
||||
audit => [ qr/Part missing Content-Disposition header/, 1 ],
|
||||
debug => [ qr/Part missing Content-Disposition header/, 1 ],
|
||||
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "multipart/form-data; boundary=---------------------------69343412719991675451336310646",
|
||||
],
|
||||
normalize_raw_request_data(
|
||||
q(
|
||||
-----------------------------69343412719991675451336310646
|
||||
|
||||
1
|
||||
-----------------------------69343412719991675451336310646
|
||||
|
||||
2
|
||||
-----------------------------69343412719991675451336310646--
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "misc",
|
||||
comment => "multipart parser error (bad disposition)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRequestBodyAccess On
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecAuditEngine RelevantOnly
|
||||
),
|
||||
match_log => {
|
||||
audit => [ qr/Invalid Content-Disposition header/, 1 ],
|
||||
debug => [ qr/Invalid Content-Disposition header/, 1 ],
|
||||
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "multipart/form-data; boundary=---------------------------69343412719991675451336310646",
|
||||
],
|
||||
normalize_raw_request_data(
|
||||
q(
|
||||
-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data name="a"
|
||||
|
||||
1
|
||||
-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data name="b"
|
||||
|
||||
2
|
||||
-----------------------------69343412719991675451336310646--
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
||||
{
|
||||
type => "misc",
|
||||
comment => "multipart parser error (no disposition name)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
SecDebugLog $ENV{DEBUG_LOG}
|
||||
SecDebugLogLevel 9
|
||||
SecRequestBodyAccess On
|
||||
SecAuditLog "$ENV{AUDIT_LOG}"
|
||||
SecAuditEngine RelevantOnly
|
||||
),
|
||||
match_log => {
|
||||
-debug => [ qr/Multipart error:/, 1 ],
|
||||
audit => [ qr/Content-Disposition header missing name field/, 1 ],
|
||||
debug => [ qr/Content-Disposition header missing name field/, 1 ],
|
||||
|
||||
},
|
||||
match_response => {
|
||||
status => qr/^200$/,
|
||||
},
|
||||
request => new HTTP::Request(
|
||||
POST => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
[
|
||||
"Content-Type" => "multipart/form-data; boundary=---------------------------69343412719991675451336310646",
|
||||
],
|
||||
normalize_raw_request_data(
|
||||
q(
|
||||
-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data;
|
||||
|
||||
1
|
||||
-----------------------------69343412719991675451336310646
|
||||
Content-Disposition: form-data;
|
||||
|
||||
2
|
||||
-----------------------------69343412719991675451336310646--
|
||||
),
|
||||
),
|
||||
),
|
||||
},
|
@@ -2,7 +2,7 @@
|
||||
|
||||
# SecAction
|
||||
{
|
||||
type => "config",
|
||||
type => "rule",
|
||||
comment => "SecAction (override default)",
|
||||
conf => qq(
|
||||
SecRuleEngine On
|
||||
|
@@ -370,7 +370,51 @@
|
||||
),
|
||||
},
|
||||
|
||||
# TODO: AUTH_TYPE
|
||||
# AUTH_TYPE
|
||||
#{
|
||||
# type => "target",
|
||||
# comment => "AUTH_TYPE",
|
||||
# conf => qq(
|
||||
# <IfVersion >= 2.2>
|
||||
# <IfModule !mod_authn_file.c>
|
||||
# LoadModule authn_file_module modules/mod_authn_file.so
|
||||
# </IfModule>
|
||||
# </IfVersion>
|
||||
## <IfVersion ~ ^2.0.>
|
||||
## <IfModule !mod_auth.c>
|
||||
## LoadModule auth_module modules/mod_auth.so
|
||||
## </IfModule>
|
||||
## </IfVersion>
|
||||
# <Location />
|
||||
# AuthType Basic
|
||||
# AuthName Test
|
||||
# AuthUserFile "$ENV{CONF_DIR}/htpasswd"
|
||||
# Require user nobody
|
||||
# </Location>
|
||||
# SecRuleEngine On
|
||||
# SecRequestBodyAccess On
|
||||
# SecResponseBodyAccess On
|
||||
# SecResponseBodyMimeType null
|
||||
## SecDebugLog $ENV{DEBUG_LOG}
|
||||
## SecDebugLogLevel 9
|
||||
# SecRule REQUEST_HEADERS:Authorization "Basic (.*)" "phase:2,log,pass,capture,chain"
|
||||
# SecRule TX:1 "nobody:test" "t:none,t:base64Decode,chain"
|
||||
# SecRule AUTH_TYPE "Basic"
|
||||
# ),
|
||||
# match_log => {
|
||||
# error => [ qr/Pattern match "Basic" at AUTH_TYPE/s, 1 ],
|
||||
# },
|
||||
# match_response => {
|
||||
# status => qr/^200$/,
|
||||
# },
|
||||
# request => new HTTP::Request(
|
||||
# GET => "http://$ENV{SERVER_NAME}:$ENV{SERVER_PORT}/test.txt",
|
||||
# [
|
||||
# "Authorization" => "Basic bm9ib2R5OnRlc3Q="
|
||||
# ],
|
||||
# ),
|
||||
#},
|
||||
|
||||
# TODO: ENV
|
||||
# TODO: FILES
|
||||
# TODO: FILES_COMBINED_SIZE
|
||||
|
@@ -21,7 +21,7 @@ use Data::Dumper;
|
||||
use IO::Socket;
|
||||
use LWP::UserAgent;
|
||||
|
||||
my @TYPES = qw(config action target rule);
|
||||
my @TYPES = qw(config misc action target rule);
|
||||
my $SCRIPT = basename($0);
|
||||
my $SCRIPT_DIR = File::Spec->rel2abs(dirname($0));
|
||||
my $REG_DIR = "$SCRIPT_DIR/regression";
|
||||
@@ -324,6 +324,23 @@ sub runfile {
|
||||
msg(sprintf("Passed: %2d; Failed: %2d", $pass, $testnum ? (1 - $pass) : ($n - $pass)));
|
||||
}
|
||||
|
||||
# Take out any indenting and translate LF -> CRLF
|
||||
sub normalize_raw_request_data {
|
||||
my $r = $_[0];
|
||||
|
||||
# Allow for indenting in test file
|
||||
$r =~ s/^[ \t]*\x0d?\x0a//s;
|
||||
my($indention) = ($r =~ m/^([ \t]*)/s); # indention taken from first line
|
||||
$r =~ s/^$indention//mg;
|
||||
$r =~ s/(\x0d?\x0a)[ \t]+$/$1/s;
|
||||
|
||||
# Translate LF to CRLF
|
||||
$r =~ s/^\x0a/\x0d\x0a/mg;
|
||||
$r =~ s/([^\x0d])\x0a/$1\x0d\x0a/mg;
|
||||
|
||||
return $r;
|
||||
}
|
||||
|
||||
sub do_raw_request {
|
||||
my $sock = new IO::Socket::INET(
|
||||
Proto => "tcp",
|
||||
@@ -332,15 +349,14 @@ sub do_raw_request {
|
||||
) or msg("Failed to connect to localhost:$opt{p}: $@");
|
||||
return unless ($sock);
|
||||
|
||||
my $r = "@_";
|
||||
$r =~ s/^[^A-Z]+//s;
|
||||
$r =~ s/^[ \t]+//mg;
|
||||
$r =~ s/^\x0a/\x0d\x0a/mg;
|
||||
$r =~ s/([^\x0d])\x0a/$1\x0d\x0a/mg;
|
||||
# Join togeather the request
|
||||
my $r = join("", @_);
|
||||
|
||||
# Write to socket
|
||||
print $sock "$r";
|
||||
$sock->shutdown(1);
|
||||
|
||||
# Read from socket
|
||||
my @resp = <$sock>;
|
||||
$sock->close();
|
||||
|
||||
|
Reference in New Issue
Block a user