gopher.c
Go to the documentation of this file.
1 /***************************************************************************
2  * _ _ ____ _
3  * Project ___| | | | _ \| |
4  * / __| | | | |_) | |
5  * | (__| |_| | _ <| |___
6  * \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2017, 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 "progress.h"
32 #include "gopher.h"
33 #include "select.h"
34 #include "url.h"
35 #include "escape.h"
36 #include "warnless.h"
37 #include "curl_memory.h"
38 /* The last #include file should be: */
39 #include "memdebug.h"
40 
41 /*
42  * Forward declarations.
43  */
44 
45 static CURLcode gopher_do(struct connectdata *conn, bool *done);
46 
47 /*
48  * Gopher protocol handler.
49  * This is also a nice simple template to build off for simple
50  * connect-command-download protocols.
51  */
52 
54  "GOPHER", /* scheme */
55  ZERO_NULL, /* setup_connection */
56  gopher_do, /* do_it */
57  ZERO_NULL, /* done */
58  ZERO_NULL, /* do_more */
59  ZERO_NULL, /* connect_it */
60  ZERO_NULL, /* connecting */
61  ZERO_NULL, /* doing */
62  ZERO_NULL, /* proto_getsock */
63  ZERO_NULL, /* doing_getsock */
64  ZERO_NULL, /* domore_getsock */
65  ZERO_NULL, /* perform_getsock */
66  ZERO_NULL, /* disconnect */
67  ZERO_NULL, /* readwrite */
68  ZERO_NULL, /* connection_check */
69  PORT_GOPHER, /* defport */
70  CURLPROTO_GOPHER, /* protocol */
71  PROTOPT_NONE /* flags */
72 };
73 
74 static CURLcode gopher_do(struct connectdata *conn, bool *done)
75 {
77  struct Curl_easy *data = conn->data;
78  curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
79 
80  curl_off_t *bytecount = &data->req.bytecount;
81  char *path = data->state.path;
82  char *sel = NULL;
83  char *sel_org = NULL;
84  ssize_t amount, k;
85  size_t len;
86 
87  *done = TRUE; /* unconditionally */
88 
89  /* Create selector. Degenerate cases: / and /1 => convert to "" */
90  if(strlen(path) <= 2) {
91  sel = (char *)"";
92  len = (int)strlen(sel);
93  }
94  else {
95  char *newp;
96  size_t j, i;
97 
98  /* Otherwise, drop / and the first character (i.e., item type) ... */
99  newp = path;
100  newp += 2;
101 
102  /* ... then turn ? into TAB for search servers, Veronica, etc. ... */
103  j = strlen(newp);
104  for(i = 0; i<j; i++)
105  if(newp[i] == '?')
106  newp[i] = '\x09';
107 
108  /* ... and finally unescape */
109  result = Curl_urldecode(data, newp, 0, &sel, &len, FALSE);
110  if(result)
111  return result;
112  sel_org = sel;
113  }
114 
115  /* We use Curl_write instead of Curl_sendf to make sure the entire buffer is
116  sent, which could be sizeable with long selectors. */
117  k = curlx_uztosz(len);
118 
119  for(;;) {
120  result = Curl_write(conn, sockfd, sel, k, &amount);
121  if(!result) { /* Which may not have written it all! */
122  result = Curl_client_write(conn, CLIENTWRITE_HEADER, sel, amount);
123  if(result)
124  break;
125 
126  k -= amount;
127  sel += amount;
128  if(k < 1)
129  break; /* but it did write it all */
130  }
131  else
132  break;
133 
134  /* Don't busyloop. The entire loop thing is a work-around as it causes a
135  BLOCKING behavior which is a NO-NO. This function should rather be
136  split up in a do and a doing piece where the pieces that aren't
137  possible to send now will be sent in the doing function repeatedly
138  until the entire request is sent.
139 
140  Wait a while for the socket to be writable. Note that this doesn't
141  acknowledge the timeout.
142  */
143  if(SOCKET_WRITABLE(sockfd, 100) < 0) {
144  result = CURLE_SEND_ERROR;
145  break;
146  }
147  }
148 
149  free(sel_org);
150 
151  if(!result)
152  /* We can use Curl_sendf to send the terminal \r\n relatively safely and
153  save allocing another string/doing another _write loop. */
154  result = Curl_sendf(sockfd, conn, "\r\n");
155  if(result) {
156  failf(data, "Failed sending Gopher request");
157  return result;
158  }
159  result = Curl_client_write(conn, CLIENTWRITE_HEADER, (char *)"\r\n", 2);
160  if(result)
161  return result;
162 
163  Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
164  -1, NULL); /* no upload */
165  return CURLE_OK;
166 }
167 #endif /*CURL_DISABLE_GOPHER*/
#define free(ptr)
Definition: curl_memory.h:130
CURLcode Curl_urldecode(struct Curl_easy *data, const char *string, size_t length, char **ostring, size_t *olen, bool reject_ctrl)
Definition: escape.c:146
#define FIRSTSOCKET
Definition: urldata.h:487
#define PORT_GOPHER
Definition: urldata.h:51
#define failf
Definition: sendf.h:48
const struct Curl_handler Curl_handler_gopher
Definition: gopher.c:53
CURLcode
Definition: curl.h:454
#define CURLPROTO_GOPHER
Definition: curl.h:869
ssize_t curlx_uztosz(size_t uznum)
Definition: warnless.c:328
UNITTEST_START int result
Definition: unit1304.c:49
int j
unsigned int i
Definition: unit1303.c:79
size_t len
Definition: curl_sasl.c:55
#define ZERO_NULL
Definition: curlx.c:131
void Curl_setup_transfer(struct connectdata *conn, int sockindex, curl_off_t size, bool getheader, curl_off_t *bytecountp, int writesockindex, curl_off_t *writecountp)
Definition: transfer.c:1989
#define FALSE
struct SingleRequest req
Definition: urldata.h:1761
Curl_done_func done
Definition: urldata.h:630
#define SOCKET_WRITABLE(x, z)
Definition: select.h:81
CURL_TYPEOF_CURL_OFF_T curl_off_t
Definition: system.h:420
#define CLIENTWRITE_HEADER
Definition: sendf.h:51
static CURLcode gopher_do(struct connectdata *conn, bool *done)
Definition: gopher.c:74
CURLcode Curl_write(struct connectdata *conn, curl_socket_t sockfd, const void *mem, size_t len, ssize_t *written)
Definition: sendf.c:318
char * path
Definition: urldata.h:1329
Definition: curl.h:455
CURLcode Curl_client_write(struct connectdata *conn, int type, char *ptr, size_t len)
Definition: sendf.c:624
#define PROTOPT_NONE
Definition: urldata.h:699
struct UrlState state
Definition: urldata.h:1769
#define ssize_t
Definition: config-win32.h:382
curl_socket_t sock[2]
Definition: urldata.h:876
CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn, const char *fmt,...)
Definition: sendf.c:266
#define TRUE
int curl_socket_t
Definition: curl.h:130
curl_off_t bytecount
Definition: urldata.h:526
Definition: debug.c:29
const char * path
Definition: util.c:192
struct Curl_easy * data
Definition: urldata.h:791


rc_tagdetect_client
Author(s): Monika Florek-Jasinska , Raphael Schaller
autogenerated on Sat Feb 13 2021 03:42:09