curl-library
[PATCH 4/4] Gopher using Curl_write; test suite (4 tests)
From: Cameron Kaiser <ckaiser_at_floodgap.com>
Date: Mon, 23 Aug 2010 14:30:59 -0700
Date: Mon, 23 Aug 2010 14:30:59 -0700
---
lib/gopher.c | 25 +++++++++++++++++++++----
tests/data/Makefile.am | 2 +-
tests/data/test1200 | 40 ++++++++++++++++++++++++++++++++++++++++
tests/data/test1201 | 40 ++++++++++++++++++++++++++++++++++++++++
tests/data/test1202 | 41 +++++++++++++++++++++++++++++++++++++++++
tests/data/test1203 | 41 +++++++++++++++++++++++++++++++++++++++++
tests/ftp.pm | 2 +-
tests/ftpserver.pl | 44 ++++++++++++++++++++++++++++++++++++++++----
tests/runtests.pl | 36 +++++++++++++++++++++++++++++++++---
tests/serverhelp.pm | 9 +++++----
10 files changed, 263 insertions(+), 17 deletions(-)
create mode 100644 tests/data/test1200
create mode 100644 tests/data/test1201
create mode 100644 tests/data/test1202
create mode 100644 tests/data/test1203
diff --git a/lib/gopher.c b/lib/gopher.c
index d1ca440..2fab6da 100644
--- a/lib/gopher.c
+++ b/lib/gopher.c
@@ -121,8 +121,8 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done)
curl_off_t *bytecount = &data->req.bytecount;
char *path = data->state.path;
-
char *sel;
+ ssize_t amount, k;
*done = TRUE; /* unconditionally */
@@ -149,12 +149,29 @@ static CURLcode gopher_do(struct connectdata *conn, bool *done)
return CURLE_OUT_OF_MEMORY;
}
- result = Curl_sendf(sockfd, conn, "%s\r\n", sel);
-
- if(result) {
+ /* We use Curl_write instead of Curl_sendf to make sure the entire buffer
+ is sent, which could be sizeable with long selectors. */
+ k = strlen(sel);
+ for(;;) {
+ result = Curl_write(conn, sockfd, sel, k, &amount);
+ if (CURLE_OK == result) { /* Which may not have written it all! */
+ k -= amount;
+ sel += amount;
+ if (k < 1)
+ break; /* but it did write it all */
+ } else {
+ failf(data, "Failed sending Gopher request");
+ return result;
+ }
+ }
+ /* We can use Curl_sendf to send the terminal \r\n relatively safely and
+ save allocing another string/doing another _write loop. */
+ result = Curl_sendf(sockfd, conn, "\r\n");
+ if (result != CURLE_OK) {
failf(data, "Failed sending Gopher request");
return result;
}
+
Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
-1, NULL); /* no upload */
return CURLE_OK;
diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am
index 61b1b48..7922000 100644
--- a/tests/data/Makefile.am
+++ b/tests/data/Makefile.am
@@ -67,7 +67,7 @@ EXTRA_DIST = test1 test108 test117 test127 test20 test27 test34 test46 \
test312 test1105 test565 test800 test1106 test801 test566 test802 test803 \
test1107 test1108 test1109 test1110 test1111 test1112 test129 test567 \
test568 test569 test570 test571 test572 test804 test805 test806 test807 \
- test573 test313 test1115
+ test573 test313 test1115 test1200 test1201 test1202 test1203
filecheck:
@mkdir test-place; \
diff --git a/tests/data/test1200 b/tests/data/test1200
new file mode 100644
index 0000000..9432720
--- /dev/null
+++ b/tests/data/test1200
@@ -0,0 +1,40 @@
+# Gopher directory fetch
+<testcase>
+<info>
+<keywords>
+GOPHER
+INDEX
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+<datacheck>
+iMenu results error.host 1
+0Selector /bar bar.foo.invalid 70
+.
+</datacheck>
+</reply>
+
+# Client-side
+<client>
+<server>
+gopher
+</server>
+ <name>
+Gopher index
+ </name>
+ <command>
+gopher://%HOSTIP:%GOPHERPORT
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<protocol>
+
+</protocol>
+</verify>
+</testcase>
diff --git a/tests/data/test1201 b/tests/data/test1201
new file mode 100644
index 0000000..bb3ccc5
--- /dev/null
+++ b/tests/data/test1201
@@ -0,0 +1,40 @@
+# Gopher selector fetch
+<testcase>
+<info>
+<keywords>
+GOPHER
+SELECTOR
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+<datacheck>
+iMenu results error.host 1
+0Selector /selector/SELECTOR /bar bar.foo.invalid 70
+.
+</datacheck>
+</reply>
+
+# Client-side
+<client>
+<server>
+gopher
+</server>
+ <name>
+Gopher selector
+ </name>
+ <command>
+gopher://%HOSTIP:%GOPHERPORT/1/selector/SELECTOR
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<protocol>
+/selector/SELECTOR
+</protocol>
+</verify>
+</testcase>
diff --git a/tests/data/test1202 b/tests/data/test1202
new file mode 100644
index 0000000..8b8502d
--- /dev/null
+++ b/tests/data/test1202
@@ -0,0 +1,41 @@
+# Gopher query fetch
+<testcase>
+<info>
+<keywords>
+GOPHER
+QUERY
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+<datacheck>
+iSearch results error.host 1
+0Query query succeeded /foo foo.bar.invalid 70
+0Selector /the/search/engine /bar bar.foo.invalid 70
+.
+</datacheck>
+</reply>
+
+# Client-side
+<client>
+<server>
+gopher
+</server>
+ <name>
+Gopher query
+ </name>
+ <command>
+gopher://%HOSTIP:%GOPHERPORT/7/the/search/engine?query%20succeeded
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<protocol>
+/the/search/engine query succeeded
+</protocol>
+</verify>
+</testcase>
diff --git a/tests/data/test1203 b/tests/data/test1203
new file mode 100644
index 0000000..c639512
--- /dev/null
+++ b/tests/data/test1203
@@ -0,0 +1,41 @@
+# Gopher IPv6 connectivity test
+<testcase>
+<info>
+<keywords>
+GOPHER-ipv6
+IPv6
+INDEX
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+<datacheck>
+iMenu results error.host 1
+0Selector /bar bar.foo.invalid 70
+.
+</datacheck>
+</reply>
+
+# Client-side
+<client>
+<server>
+gopher-ipv6
+</server>
+ <name>
+Gopher IPv6 index
+ </name>
+ <command>
+-g "gopher://%HOSTIP:%GOPHER6PORT"
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<protocol>
+
+</protocol>
+</verify>
+</testcase>
diff --git a/tests/ftp.pm b/tests/ftp.pm
index 6a46e76..535075a 100644
--- a/tests/ftp.pm
+++ b/tests/ftp.pm
@@ -181,7 +181,7 @@ sub killsockfilters {
my $pidfile;
my $pid;
- return if($proto !~ /^(ftp|imap|pop3|smtp)$/);
+ return if($proto !~ /^(ftp|imap|pop3|smtp|gopher)$/);
die "unsupported sockfilter: $which"
if($which && ($which !~ /^(main|data)$/));
diff --git a/tests/ftpserver.pl b/tests/ftpserver.pl
index ed2a832..03d9334 100755
--- a/tests/ftpserver.pl
+++ b/tests/ftpserver.pl
@@ -29,6 +29,9 @@
# protocol per invoke. You need to start mulitple servers to support multiple
# protocols simultaneously.
#
+# The gopher protocol test server also lives here, borrowing some of the
+# routines.
+#
# It is meant to exercise curl, it is not meant to be a fully working
# or even very standard compliant server.
#
@@ -341,6 +344,7 @@ sub senddata {
# for the given protocol. References to protocol command callbacks are
# stored in 'commandfunc' hash, and text which will be returned to the
# client before the command callback runs is stored in 'displaytext'.
+# Gopher is not handled here, however (it has a separate routine).
#
sub protocolsetup {
my $proto = $_[0];
@@ -1294,7 +1298,7 @@ while(@ARGV) {
}
}
elsif($ARGV[0] eq '--proto') {
- if($ARGV[1] && ($ARGV[1] =~ /^(ftp|imap|pop3|smtp)$/)) {
+ if($ARGV[1] && ($ARGV[1] =~ /^(ftp|imap|pop3|smtp|gopher)$/)) {
$proto = $1;
shift @ARGV;
}
@@ -1421,7 +1425,7 @@ while(1) {
&customize(); # read test control instructions
- sendcontrol @welcome;
+ sendcontrol @welcome unless ($proto eq 'gopher');
#remove global variables from last connection
if($ftplistparserstate) {
@@ -1474,7 +1478,39 @@ while(1) {
my $FTPCMD;
my $FTPARG;
my $full=$_;
- if($proto eq "imap") {
+
+ if($proto eq 'gopher') {
+ # Gopher protocol support lives right here and we handle it
+ # right here and now, since there will only ever be one selector
+ # and no other commands.
+
+ my $sel = $_;
+ my $query = '';
+ my @response = ();
+ ($sel, $query) = split(/\x09/, $_) if (/\x09/);
+
+ if($sel eq 'erifiedserver') {
+ # NOT verifiedserver, the first character is the item type in
+ # a Gopher URL!
+ push(@response, "iWE ROOLZ: $$\x09\x09error.host\x091\r\n");
+ }
+ if (length($query)) { # fake Veronica, gin up search results
+ push(@response, "iSearch results\x09\x09error.host\x091\r\n");
+ push(@response,
+ "0Query $query\x09/foo\x09foo.bar.invalid\x0970\r\n");
+ } else { # fake selector, gin up a menu
+ push(@response, "iMenu results\x09\x09error.host\x091\r\n");
+ }
+ push(@response,
+ "0Selector $sel\x09/bar\x09bar.foo.invalid\x0970\r\n");
+ push(@response, ".\r\n");
+ sendcontrol @response;
+
+ # disconnect the client now, no command.
+ $FTPCMD = $FTPARG = '';
+ print SFWRITE "DISC\n";
+ }
+ elsif($proto eq "imap") {
# IMAP is different with its identifier first on the command line
unless (m/^([^ ]+) ([^ ]+) (.*)/ ||
m/^([^ ]+) ([^ ]+)/) {
@@ -1550,7 +1586,7 @@ while(1) {
}
}
- if($check) {
+ if($check && $proto ne 'gopher') {
logmsg "$FTPCMD wasn't handled!\n";
sendcontrol "500 $FTPCMD is not dealt with!\r\n";
}
diff --git a/tests/runtests.pl b/tests/runtests.pl
index 9ddccc0..556ba2a 100755
--- a/tests/runtests.pl
+++ b/tests/runtests.pl
@@ -133,6 +133,8 @@ my $SMTPPORT; # SMTP
my $SMTP6PORT; # SMTP IPv6 server port
my $RTSPPORT; # RTSP
my $RTSP6PORT; # RTSP IPv6 server port
+my $GOPHERPORT; # Gopher
+my $GOPHER6PORT; # Gopher IPv6 server port
my $srcdir = $ENV{'srcdir'} || '.';
my $CURL="../src/curl".exe_ext(); # what curl executable to run on the tests
@@ -193,6 +195,7 @@ my $has_idn; # set if libcurl is built with IDN support
my $http_ipv6; # set if HTTP server has IPv6 support
my $ftp_ipv6; # set if FTP server has IPv6 support
my $tftp_ipv6; # set if TFTP server has IPv6 support
+my $gopher_ipv6; # set if Gopher server has IPv6 support
my $has_ipv6; # set if libcurl is built with IPv6 support
my $has_libz; # set if libcurl is built with libz support
my $has_getrlimit; # set if system has getrlimit()
@@ -329,7 +332,7 @@ sub init_serverpidfile_hash {
}
}
}
- for my $proto (('tftp', 'sftp', 'socks', 'ssh', 'rtsp')) {
+ for my $proto (('tftp', 'sftp', 'socks', 'ssh', 'rtsp', 'gopher')) {
for my $ipvnum ((4, 6)) {
for my $idnum ((1, 2)) {
my $serv = servername_id($proto, $ipvnum, $idnum);
@@ -988,7 +991,8 @@ my %protofunc = ('http' => \&verifyhttp,
'ftps' => \&verifyftp,
'tftp' => \&verifyftp,
'ssh' => \&verifyssh,
- 'socks' => \&verifysocks);
+ 'socks' => \&verifysocks,
+ 'gopher' => \&verifyftp);
sub verifyserver {
my ($proto, $ipvnum, $idnum, $ip, $port) = @_;
@@ -1180,7 +1184,7 @@ sub runhttpsserver {
}
#######################################################################
-# start the pingpong server (FTP, POP3, IMAP, SMTP)
+# start the pingpong server (FTP, POP3, IMAP, SMTP, GOPHER)
#
sub runpingpongserver {
my ($proto, $id, $verbose, $ipv6) = @_;
@@ -1211,6 +1215,9 @@ sub runpingpongserver {
elsif($proto eq "smtp") {
$port = ($ipvnum==6) ? $SMTP6PORT : $SMTPPORT;
}
+ elsif($proto eq "gopher") {
+ $port = ($ipvnum==6) ? $GOPHER6PORT : $GOPHERPORT;
+ }
else {
print STDERR "Unsupported protocol $proto!!\n";
return 0;
@@ -1263,6 +1270,7 @@ sub runpingpongserver {
$doesntrun{$pidfile} = 1;
return (0,0);
}
+
$pid2 = $pid3;
if($verbose) {
@@ -2039,7 +2047,9 @@ sub checksystem {
@sws = `server/sockfilt --version`;
if($sws[0] =~ /IPv6/) {
# FTP server has ipv6 support!
+ # and since the Gopher server descends from it, we have it too!
$ftp_ipv6 = 1;
+ $gopher_ipv6 = 1;
}
}
@@ -2098,6 +2108,10 @@ sub checksystem {
if($tftp_ipv6) {
logmsg sprintf("TFTP-IPv6/%d ", $TFTP6PORT);
}
+ logmsg sprintf("\n* GOPHER/%d ", $GOPHERPORT);
+ if($gopher_ipv6) {
+ logmsg sprintf("GOPHER-IPv6/%d", $GOPHERPORT);
+ }
logmsg sprintf("\n* SSH/%d ", $SSHPORT);
logmsg sprintf("SOCKS/%d ", $SOCKSPORT);
logmsg sprintf("POP3/%d ", $POP3PORT);
@@ -2147,6 +2161,8 @@ sub subVariables {
$$thing =~ s/%CLIENT6IP/$CLIENT6IP/g;
$$thing =~ s/%RTSPPORT/$RTSPPORT/g;
$$thing =~ s/%RTSP6PORT/$RTSP6PORT/g;
+ $$thing =~ s/%GOPHERPORT/$GOPHERPORT/g;
+ $$thing =~ s/%GOPHER6PORT/$GOPHER6PORT/g;
# The purpose of FTPTIME2 and FTPTIME3 is to provide times that can be
# used for time-out tests and that whould work on most hosts as these
@@ -3211,6 +3227,7 @@ sub startservers {
if(($what eq "pop3") ||
($what eq "ftp") ||
($what eq "imap") ||
+ ($what eq "gopher") ||
($what eq "smtp")) {
if(!$run{$what}) {
($pid, $pid2) = runpingpongserver($what, "", $verbose);
@@ -3242,6 +3259,17 @@ sub startservers {
$run{'ftp-ipv6'}="$pid $pid2";
}
}
+ elsif($what eq "gopher-ipv6") {
+ if(!$run{'gopher-ipv6'}) {
+ ($pid, $pid2) = runpingpongserver("gopher","",$verbose,"ipv6");
+ if($pid <= 0) {
+ return "failed starting GOPHER-IPv6 server";
+ }
+ logmsg sprintf("* pid gopher-ipv6 => %d %d\n", $pid,
+ $pid2) if($verbose);
+ $run{'gopher-ipv6'}="$pid $pid2";
+ }
+ }
elsif($what eq "http") {
if(!$run{'http'}) {
($pid, $pid2) = runhttpserver($verbose);
@@ -3821,6 +3849,8 @@ $SMTPPORT = $base++;
$SMTP6PORT = $base++;
$RTSPPORT = $base++;
$RTSP6PORT = $base++;
+$GOPHERPORT =$base++;
+$GOPHER6PORT=$base++;
#######################################################################
# clear and create logging directory:
diff --git a/tests/serverhelp.pm b/tests/serverhelp.pm
index 4b3b505..8429b40 100644
--- a/tests/serverhelp.pm
+++ b/tests/serverhelp.pm
@@ -96,7 +96,7 @@ sub servername_str {
$proto = uc($proto) if($proto);
die "unsupported protocol: $proto" unless($proto &&
- ($proto =~ /^(((FTP|HTTP|IMAP|POP3|SMTP)S?)|(TFTP|SFTP|SOCKS|SSH|RTSP))$/));
+ ($proto =~ /^(((FTP|HTTP|IMAP|POP3|SMTP)S?)|(TFTP|SFTP|SOCKS|SSH|RTSP|GOPHER))$/));
$ipver = (not $ipver) ? 'ipv4' : lc($ipver);
die "unsupported IP version: $ipver" unless($ipver &&
@@ -148,7 +148,8 @@ sub server_pidfilename {
sub server_logfilename {
my ($logdir, $proto, $ipver, $idnum) = @_;
my $trailer = '_server.log';
- $trailer = '_stunnel.log' if(lc($proto) =~ /^(ftp|http|imap|pop3|smtp)s$/);
+ $trailer = '_stunnel.log' if(lc($proto) =~ /^(ftp|http|imap|pop3|smtp)s$/||
+ lc($proto) eq 'gopher');
return "${logdir}/". servername_canon($proto, $ipver, $idnum) ."$trailer";
}
@@ -189,7 +190,7 @@ sub server_outputfilename {
sub mainsockf_pidfilename {
my ($proto, $ipver, $idnum) = @_;
die "unsupported protocol: $proto" unless($proto &&
- (lc($proto) =~ /^(ftp|imap|pop3|smtp)s?$/));
+ ((lc($proto) =~ /^(ftp|imap|pop3|smtp)s?$/) || lc($proto) eq 'gopher'));
my $trailer = (lc($proto) =~ /^ftps?$/) ? '_sockctrl.pid':'_sockfilt.pid';
return '.'. servername_canon($proto, $ipver, $idnum) ."$trailer";
}
@@ -201,7 +202,7 @@ sub mainsockf_pidfilename {
sub mainsockf_logfilename {
my ($logdir, $proto, $ipver, $idnum) = @_;
die "unsupported protocol: $proto" unless($proto &&
- (lc($proto) =~ /^(ftp|imap|pop3|smtp)s?$/));
+ ((lc($proto) =~ /^(ftp|imap|pop3|smtp)s?$/) || lc($proto) eq 'gopher'));
my $trailer = (lc($proto) =~ /^ftps?$/) ? '_sockctrl.log':'_sockfilt.log';
return "${logdir}/". servername_canon($proto, $ipver, $idnum) ."$trailer";
}
--
1.7.1
--ELM1282599678-19722-0_
Content-Type: text/plain; charset="us-ascii"
MIME-Version: 1.0
Content-Transfer-Encoding: 7bit
Content-Disposition: inline
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette: http://curl.haxx.se/mail/etiquette.html
--ELM1282599678-19722-0_--
Received on 2001-09-17