Okay, here we go. This is gopher for cURL round 2: -- Curl_write() now used for the critical portion in lib/gopher.c -- ftpserver.pl modified to serve Gopher over IPv4 and IPv6 -- four base tests for gopher, including index, selector, query and IPv6
-- ------------------------------------ personal: http://www.cameronkaiser.com/ -- Cameron Kaiser * Floodgap Systems * www.floodgap.com * [email protected] -- Proudly running on the Apple Network Server 500/200 ------------------------
>From 6c721a51bbb30c653fa9563f808c9c3278499300 Mon Sep 17 00:00:00 2001 From: Cameron Kaiser <[email protected]> Date: Thu, 12 Aug 2010 07:55:48 -0700 Subject: [PATCH 1/4] Gopher protocol support (initial release) --- configure.ac | 19 ++++++ include/curl/curl.h | 1 + lib/Makefile.inc | 3 +- lib/gopher.c | 162 +++++++++++++++++++++++++++++++++++++++++++++++++++ lib/gopher.h | 29 +++++++++ lib/url.c | 8 +++ lib/urldata.h | 9 ++- lib/version.c | 3 + src/main.c | 1 + 9 files changed, 231 insertions(+), 4 deletions(-) create mode 100644 lib/gopher.c create mode 100644 lib/gopher.h diff --git a/configure.ac b/configure.ac index db04447..1e64246 100644 --- a/configure.ac +++ b/configure.ac @@ -570,6 +570,22 @@ AC_HELP_STRING([--disable-smtp],[Disable SMTP support]), AC_MSG_RESULT(yes) ) +AC_MSG_CHECKING([whether to support gopher]) +AC_ARG_ENABLE(gopher, +AC_HELP_STRING([--enable-gopher],[Enable Gopher support]) +AC_HELP_STRING([--disable-gopher],[Disable Gopher support]), +[ case "$enableval" in + no) + AC_MSG_RESULT(no) + AC_DEFINE(CURL_DISABLE_GOPHER, 1, [to disable Gopher]) + AC_SUBST(CURL_DISABLE_GOPHER, [1]) + ;; + *) AC_MSG_RESULT(yes) + ;; + esac ], + AC_MSG_RESULT(yes) +) + dnl ********************************************************************** dnl Check for built-in manual @@ -2738,6 +2754,9 @@ fi if test "x$CURL_DISABLE_TFTP" != "x1"; then SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS TFTP" fi +if test "x$CURL_DISABLE_GOPHER" != "x1"; then + SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS GOPHER" +fi if test "x$CURL_DISABLE_POP3" != "x1"; then SUPPORT_PROTOCOLS="$SUPPORT_PROTOCOLS POP3" if test "x$SSL_ENABLED" = "x1"; then diff --git a/include/curl/curl.h b/include/curl/curl.h index b19828f..cb9d0fb 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -722,6 +722,7 @@ typedef enum { #define CURLPROTO_RTMPTE (1<<22) #define CURLPROTO_RTMPS (1<<23) #define CURLPROTO_RTMPTS (1<<24) +#define CURLPROTO_GOPHER (1<<25) #define CURLPROTO_ALL (~0) /* enable everything */ /* long may be 32 or 64 bits, but we should never depend on anything else diff --git a/lib/Makefile.inc b/lib/Makefile.inc index bfd3abe..33b5765 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -20,7 +20,8 @@ CSOURCES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ strdup.c socks.c ssh.c nss.c qssl.c rawstr.c curl_addrinfo.c \ socks_gssapi.c socks_sspi.c curl_sspi.c slist.c nonblock.c \ curl_memrchr.c imap.c pop3.c smtp.c pingpong.c rtsp.c curl_threads.c \ - warnless.c hmac.c polarssl.c curl_rtmp.c openldap.c curl_gethostname.c + warnless.c hmac.c polarssl.c curl_rtmp.c openldap.c curl_gethostname.c\ + gopher.c HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h \ progress.h formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h \ diff --git a/lib/gopher.c b/lib/gopher.c new file mode 100644 index 0000000..d1ca440 --- /dev/null +++ b/lib/gopher.c @@ -0,0 +1,162 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2010, Daniel Stenberg, <[email protected]>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "setup.h" + +#ifndef CURL_DISABLE_GOPHER + +/* -- WIN32 approved -- */ +#include <stdio.h> +#include <string.h> +#include <stdarg.h> +#include <stdlib.h> +#include <ctype.h> + +#ifdef WIN32 +#include <time.h> +#include <io.h> +#else +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#include <netinet/in.h> +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#include <netdb.h> +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#ifdef HAVE_NET_IF_H +#include <net/if.h> +#endif +#ifdef HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif + +#ifdef HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif + +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif + + +#endif + +#include "urldata.h" +#include <curl/curl.h> +#include "transfer.h" +#include "sendf.h" + +#include "progress.h" +#include "strequal.h" +#include "gopher.h" +#include "rawstr.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include <curl/mprintf.h> + +/* The last #include file should be: */ +#include "memdebug.h" + + +/* + * Forward declarations. + */ + +static CURLcode gopher_do(struct connectdata *conn, bool *done); + +/* + * Gopher protocol handler. + * This is also a nice simple template to build off for simple + * connect-command-download protocols. + */ + +const struct Curl_handler Curl_handler_gopher = { + "GOPHER", /* scheme */ + ZERO_NULL, /* setup_connection */ + gopher_do, /* do_it */ + ZERO_NULL, /* done */ + ZERO_NULL, /* do_more */ + ZERO_NULL, /* connect_it */ + ZERO_NULL, /* connecting */ + ZERO_NULL, /* doing */ + ZERO_NULL, /* proto_getsock */ + ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* perform_getsock */ + ZERO_NULL, /* disconnect */ + PORT_GOPHER, /* defport */ + PROT_GOPHER /* protocol */ +}; + +static CURLcode gopher_do(struct connectdata *conn, bool *done) +{ + CURLcode result=CURLE_OK; + struct SessionHandle *data=conn->data; + curl_socket_t sockfd = conn->sock[FIRSTSOCKET]; + + curl_off_t *bytecount = &data->req.bytecount; + char *path = data->state.path; + + char *sel; + + *done = TRUE; /* unconditionally */ + + /* Create selector. Degenerate cases: / and /1 => convert to "" */ + if (strlen(path) <= 2) + sel = (char *)""; + else { + char *newp; + int i, j, len; + + /* Otherwise, drop / and the first character (i.e., item type) ... */ + newp = path; + newp+=2; + + /* ... then turn ? into TAB for search servers, Veronica, etc. ... */ + j = strlen(newp); + if (j) + for(i=0; i<j; i++) + newp[i] = ((newp[i] == '?') ? '\x09' : newp[i]); + + /* ... and finally unescape */ + sel = curl_easy_unescape(data, newp, 0, &len); + if (!sel) + return CURLE_OUT_OF_MEMORY; + } + + result = Curl_sendf(sockfd, conn, "%s\r\n", sel); + + if(result) { + failf(data, "Failed sending Gopher request"); + return result; + } + Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount, + -1, NULL); /* no upload */ + return CURLE_OK; +} +#endif /*CURL_DISABLE_GOPHER*/ diff --git a/lib/gopher.h b/lib/gopher.h new file mode 100644 index 0000000..38bbc4b --- /dev/null +++ b/lib/gopher.h @@ -0,0 +1,29 @@ +#ifndef HEADER_CURL_GOPHER_H +#define HEADER_CURL_GOPHER_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2009, Daniel Stenberg, <[email protected]>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#ifndef CURL_DISABLE_GOPHER +extern const struct Curl_handler Curl_handler_gopher; +#endif + +#endif /* HEADER_CURL_GOPHER_H */ diff --git a/lib/url.c b/lib/url.c index fd6443a..abc349a 100644 --- a/lib/url.c +++ b/lib/url.c @@ -138,6 +138,7 @@ void idn_free (void *ptr); /* prototype from idn-free.h, not provided by #include "socks.h" #include "rtsp.h" #include "curl_rtmp.h" +#include "gopher.h" #define _MPRINTF_REPLACE /* use our functions only */ #include <curl/mprintf.h> @@ -227,6 +228,10 @@ static const struct Curl_handler * const protocols[] = { &Curl_handler_rtsp, #endif +#ifndef CURL_DISABLE_GOPHER + &Curl_handler_gopher, +#endif + #ifdef USE_LIBRTMP &Curl_handler_rtmp, &Curl_handler_rtmpt, @@ -3474,8 +3479,11 @@ static CURLcode findprotocol(struct SessionHandle *data, if(Curl_raw_equal(p->scheme, protostr)) { /* Protocol found in table. Check if allowed */ if(!(data->set.allowed_protocols & p->protocol)) +{ /* nope, get out */ + fprintf(stderr, "well, shit\n"); break; +} /* it is allowed for "normal" request, now do an extra check if this is the result of a redirect */ diff --git a/lib/urldata.h b/lib/urldata.h index 7919921..1eaca68 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -46,6 +46,7 @@ #define PORT_RTMP 1935 #define PORT_RTMPT PORT_HTTP #define PORT_RTMPS PORT_HTTPS +#define PORT_GOPHER 70 #define DICT_MATCH "/MATCH:" #define DICT_MATCH2 "/M:" @@ -715,11 +716,13 @@ struct connectdata { #define PROT_RTMPTE CURLPROTO_RTMPTE #define PROT_RTMPS CURLPROTO_RTMPS #define PROT_RTMPTS CURLPROTO_RTMPTS +#define PROT_GOPHER CURLPROTO_GOPHER -/* (1<<24) is currently the highest used bit in the public bitmask. We make - sure we use "private bits" above the public ones to make things easier. */ +/* (1<<25) is currently the highest used bit in the public bitmask. We make + sure we use "private bits" above the public ones to make things easier; + Gopher will not conflict with the current bit 25. */ -#define PROT_EXTMASK 0xffffff +#define PROT_EXTMASK 0x03ffffff #define PROT_SSL (1<<29) /* protocol requires SSL */ diff --git a/lib/version.c b/lib/version.c index 9a336a3..9ba2e33 100644 --- a/lib/version.c +++ b/lib/version.c @@ -158,6 +158,9 @@ static const char * const protocols[] = { #if defined(USE_SSL) && !defined(CURL_DISABLE_FTP) "ftps", #endif +#ifndef CURL_DISABLE_GOPHER + "gopher", +#endif #ifndef CURL_DISABLE_HTTP "http", #endif diff --git a/src/main.c b/src/main.c index 5585c17..2971342 100644 --- a/src/main.c +++ b/src/main.c @@ -1539,6 +1539,7 @@ static long proto2num(struct Configurable *config, long *val, const char *str) { "smtp", CURLPROTO_SMTP }, { "smtps", CURLPROTO_SMTPS }, { "rtsp", CURLPROTO_RTSP }, + { "gopher", CURLPROTO_GOPHER }, { NULL, 0 } }; -- 1.7.1
>From 3993c54c809cdf4d0f33040860cbae43239390ec Mon Sep 17 00:00:00 2001 From: Cameron Kaiser <[email protected]> Date: Thu, 12 Aug 2010 08:32:00 -0700 Subject: [PATCH 2/4] Forgot gopher.h in Makefile.inc --- lib/Makefile.inc | 3 ++- 1 files changed, 2 insertions(+), 1 deletions(-) diff --git a/lib/Makefile.inc b/lib/Makefile.inc index 33b5765..41ab827 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -35,5 +35,6 @@ HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h \ tftp.h sockaddr.h splay.h strdup.h setup_once.h socks.h ssh.h nssg.h \ curl_base64.h rawstr.h curl_addrinfo.h curl_sspi.h slist.h nonblock.h \ curl_memrchr.h imap.h pop3.h smtp.h pingpong.h rtsp.h curl_threads.h \ - warnless.h curl_hmac.h polarssl.h curl_rtmp.h curl_gethostname.h + warnless.h curl_hmac.h polarssl.h curl_rtmp.h curl_gethostname.h \ + gopher.h -- 1.7.1
>From 4730844b7bad8081e517423539260b3218079083 Mon Sep 17 00:00:00 2001 From: Cameron Kaiser <[email protected]> Date: Thu, 12 Aug 2010 09:25:43 -0700 Subject: [PATCH 3/4] Remove url.c test --- lib/url.c | 3 --- 1 files changed, 0 insertions(+), 3 deletions(-) diff --git a/lib/url.c b/lib/url.c index abc349a..ed01cc7 100644 --- a/lib/url.c +++ b/lib/url.c @@ -3479,11 +3479,8 @@ static CURLcode findprotocol(struct SessionHandle *data, if(Curl_raw_equal(p->scheme, protostr)) { /* Protocol found in table. Check if allowed */ if(!(data->set.allowed_protocols & p->protocol)) -{ /* nope, get out */ - fprintf(stderr, "well, shit\n"); break; -} /* it is allowed for "normal" request, now do an extra check if this is the result of a redirect */ -- 1.7.1
>From 892fb7aac331f23393cbc4a7a5f7ac83b5d91302 Mon Sep 17 00:00:00 2001 From: Cameron Kaiser <[email protected]> Date: Mon, 23 Aug 2010 14:30:59 -0700 Subject: [PATCH 4/4] Gopher using Curl_write; test suite (4 tests) --- 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
------------------------------------------------------------------- List admin: http://cool.haxx.se/list/listinfo/curl-library Etiquette: http://curl.haxx.se/mail/etiquette.html
