Annotation of embedaddon/curl/lib/gopher.c, revision 1.1

1.1     ! misho       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>