File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / lib / gopher.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 10:01:15 2020 UTC (5 years ago) by misho
Branches: curl, MAIN
CVS tags: v7_70_0p4, HEAD
curl

    1: /***************************************************************************
    2:  *                                  _   _ ____  _
    3:  *  Project                     ___| | | |  _ \| |
    4:  *                             / __| | | | |_) | |
    5:  *                            | (__| |_| |  _ <| |___
    6:  *                             \___|\___/|_| \_\_____|
    7:  *
    8:  * Copyright (C) 1998 - 2020, Daniel Stenberg, <daniel@haxx.se>, et al.
    9:  *
   10:  * This software is licensed as described in the file COPYING, which
   11:  * you should have received as part of this distribution. The terms
   12:  * are also available at https://curl.haxx.se/docs/copyright.html.
   13:  *
   14:  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
   15:  * copies of the Software, and permit persons to whom the Software is
   16:  * furnished to do so, under the terms of the COPYING file.
   17:  *
   18:  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
   19:  * KIND, either express or implied.
   20:  *
   21:  ***************************************************************************/
   22: 
   23: #include "curl_setup.h"
   24: 
   25: #ifndef CURL_DISABLE_GOPHER
   26: 
   27: #include "urldata.h"
   28: #include <curl/curl.h>
   29: #include "transfer.h"
   30: #include "sendf.h"
   31: #include "connect.h"
   32: #include "progress.h"
   33: #include "gopher.h"
   34: #include "select.h"
   35: #include "strdup.h"
   36: #include "url.h"
   37: #include "escape.h"
   38: #include "warnless.h"
   39: #include "curl_printf.h"
   40: #include "curl_memory.h"
   41: /* The last #include file should be: */
   42: #include "memdebug.h"
   43: 
   44: /*
   45:  * Forward declarations.
   46:  */
   47: 
   48: static CURLcode gopher_do(struct connectdata *conn, bool *done);
   49: 
   50: /*
   51:  * Gopher protocol handler.
   52:  * This is also a nice simple template to build off for simple
   53:  * connect-command-download protocols.
   54:  */
   55: 
   56: const struct Curl_handler Curl_handler_gopher = {
   57:   "GOPHER",                             /* scheme */
   58:   ZERO_NULL,                            /* setup_connection */
   59:   gopher_do,                            /* do_it */
   60:   ZERO_NULL,                            /* done */
   61:   ZERO_NULL,                            /* do_more */
   62:   ZERO_NULL,                            /* connect_it */
   63:   ZERO_NULL,                            /* connecting */
   64:   ZERO_NULL,                            /* doing */
   65:   ZERO_NULL,                            /* proto_getsock */
   66:   ZERO_NULL,                            /* doing_getsock */
   67:   ZERO_NULL,                            /* domore_getsock */
   68:   ZERO_NULL,                            /* perform_getsock */
   69:   ZERO_NULL,                            /* disconnect */
   70:   ZERO_NULL,                            /* readwrite */
   71:   ZERO_NULL,                            /* connection_check */
   72:   PORT_GOPHER,                          /* defport */
   73:   CURLPROTO_GOPHER,                     /* protocol */
   74:   PROTOPT_NONE                          /* flags */
   75: };
   76: 
   77: static CURLcode gopher_do(struct connectdata *conn, bool *done)
   78: {
   79:   CURLcode result = CURLE_OK;
   80:   struct Curl_easy *data = conn->data;
   81:   curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
   82:   char *gopherpath;
   83:   char *path = data->state.up.path;
   84:   char *query = data->state.up.query;
   85:   char *sel = NULL;
   86:   char *sel_org = NULL;
   87:   timediff_t timeout_ms;
   88:   ssize_t amount, k;
   89:   size_t len;
   90:   int what;
   91: 
   92:   *done = TRUE; /* unconditionally */
   93: 
   94:   /* path is guaranteed non-NULL */
   95:   DEBUGASSERT(path);
   96: 
   97:   if(query)
   98:     gopherpath = aprintf("%s?%s", path, query);
   99:   else
  100:     gopherpath = strdup(path);
  101: 
  102:   if(!gopherpath)
  103:     return CURLE_OUT_OF_MEMORY;
  104: 
  105:   /* Create selector. Degenerate cases: / and /1 => convert to "" */
  106:   if(strlen(gopherpath) <= 2) {
  107:     sel = (char *)"";
  108:     len = strlen(sel);
  109:     free(gopherpath);
  110:   }
  111:   else {
  112:     char *newp;
  113: 
  114:     /* Otherwise, drop / and the first character (i.e., item type) ... */
  115:     newp = gopherpath;
  116:     newp += 2;
  117: 
  118:     /* ... and finally unescape */
  119:     result = Curl_urldecode(data, newp, 0, &sel, &len, FALSE);
  120:     free(gopherpath);
  121:     if(result)
  122:       return result;
  123:     sel_org = sel;
  124:   }
  125: 
  126:   /* We use Curl_write instead of Curl_sendf to make sure the entire buffer is
  127:      sent, which could be sizeable with long selectors. */
  128:   k = curlx_uztosz(len);
  129: 
  130:   for(;;) {
  131:     result = Curl_write(conn, sockfd, sel, k, &amount);
  132:     if(!result) { /* Which may not have written it all! */
  133:       result = Curl_client_write(conn, CLIENTWRITE_HEADER, sel, amount);
  134:       if(result)
  135:         break;
  136: 
  137:       k -= amount;
  138:       sel += amount;
  139:       if(k < 1)
  140:         break; /* but it did write it all */
  141:     }
  142:     else
  143:       break;
  144: 
  145:     timeout_ms = Curl_timeleft(conn->data, NULL, FALSE);
  146:     if(timeout_ms < 0) {
  147:       result = CURLE_OPERATION_TIMEDOUT;
  148:       break;
  149:     }
  150:     if(!timeout_ms)
  151:       timeout_ms = TIMEDIFF_T_MAX;
  152: 
  153:     /* Don't busyloop. The entire loop thing is a work-around as it causes a
  154:        BLOCKING behavior which is a NO-NO. This function should rather be
  155:        split up in a do and a doing piece where the pieces that aren't
  156:        possible to send now will be sent in the doing function repeatedly
  157:        until the entire request is sent.
  158:     */
  159:     what = SOCKET_WRITABLE(sockfd, timeout_ms);
  160:     if(what < 0) {
  161:       result = CURLE_SEND_ERROR;
  162:       break;
  163:     }
  164:     else if(!what) {
  165:       result = CURLE_OPERATION_TIMEDOUT;
  166:       break;
  167:     }
  168:   }
  169: 
  170:   free(sel_org);
  171: 
  172:   if(!result)
  173:     /* We can use Curl_sendf to send the terminal \r\n relatively safely and
  174:        save allocing another string/doing another _write loop. */
  175:     result = Curl_sendf(sockfd, conn, "\r\n");
  176:   if(result) {
  177:     failf(data, "Failed sending Gopher request");
  178:     return result;
  179:   }
  180:   result = Curl_client_write(conn, CLIENTWRITE_HEADER, (char *)"\r\n", 2);
  181:   if(result)
  182:     return result;
  183: 
  184:   Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
  185:   return CURLE_OK;
  186: }
  187: #endif /*CURL_DISABLE_GOPHER*/

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>