From 90a1b857f3fddf5cf1a25b73d6bdbe6c40471076 Mon Sep 17 00:00:00 2001 From: Ben Burwell Date: Sat, 6 Jun 2020 22:42:17 -0400 Subject: WIP: Add support for gemini meta headers --- include/curl/curl.h | 3 ++ lib/gemini.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++- lib/setopt.c | 3 ++ src/tool_cfgable.h | 1 + 4 files changed, 110 insertions(+), 1 deletion(-) diff --git a/include/curl/curl.h b/include/curl/curl.h index 71695538d..78f5e1e9a 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -1968,6 +1968,9 @@ typedef enum { CURLOPT(CURLOPT_PROXY_SSLKEY_BLOB, CURLOPTTYPE_BLOB, 294), CURLOPT(CURLOPT_ISSUERCERT_BLOB, CURLOPTTYPE_BLOB, 295), + /* set the gemini request meta */ + CURLOPT(CURLOPT_META, CURLOPTTYPE_STRINGPOINT, 296), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; diff --git a/lib/gemini.c b/lib/gemini.c index bd1953d82..31560ac8d 100644 --- a/lib/gemini.c +++ b/lib/gemini.c @@ -49,6 +49,8 @@ static CURLcode gemini_do(struct connectdata *conn, bool *done); static CURLcode gemini_connecting(struct connectdata *conn, bool *done); CURLcode Curl_gemini_connect(struct connectdata *conn, bool *done); +void Curl_setup_gemini_transfer(struct Curl_easy *data, int sockindex, + curl_off_t size, bool getheader, int writesockindex); /* * Gemini protocol handler. @@ -144,7 +146,15 @@ static CURLcode gemini_do(struct connectdata *conn, bool *done) } } - Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1); + printf("include header: %d\n", data->set.include_header); + printf("verbose: %d\n", data->set.verbose); + printf("follow location: %d\n", data->set.http_follow_location); + + /* if (data->set.include_header) { */ + Curl_setup_gemini_transfer(data, FIRSTSOCKET, -1, FALSE, -1); + /* } else { */ + /* Curl_setup_transfer(data, FIRSTSOCKET, -1, TRUE, -1); */ + /* } */ return CURLE_OK; } @@ -176,4 +186,96 @@ CURLcode Curl_gemini_connect(struct connectdata *conn, bool *done) return CURLE_OK; } + +/* + * Curl_setup_gemini_transfer() is called to setup some basic properties for the + * upcoming transfer. + */ +void +Curl_setup_gemini_transfer( + struct Curl_easy *data, /* transfer */ + int sockindex, /* socket index to read from or -1 */ + curl_off_t size, /* -1 if unknown at this point */ + bool getheader, /* TRUE if header parsing is wanted */ + int writesockindex /* socket index to write to, it may very well be + the same we read from. -1 disables */ + ) +{ + struct SingleRequest *k = &data->req; + struct connectdata *conn = data->conn; + struct HTTP *http = data->req.protop; + bool httpsending = ((conn->handler->protocol&PROTO_FAMILY_HTTP) && + (http->sending == HTTPSEND_REQUEST)); + DEBUGASSERT(conn != NULL); + DEBUGASSERT((sockindex <= 1) && (sockindex >= -1)); + + if(conn->bits.multiplex || conn->httpversion == 20 || httpsending) { + /* when multiplexing, the read/write sockets need to be the same! */ + conn->sockfd = sockindex == -1 ? + ((writesockindex == -1 ? CURL_SOCKET_BAD : conn->sock[writesockindex])) : + conn->sock[sockindex]; + conn->writesockfd = conn->sockfd; + if(httpsending) + /* special and very HTTP-specific */ + writesockindex = FIRSTSOCKET; + } + else { + conn->sockfd = sockindex == -1 ? + CURL_SOCKET_BAD : conn->sock[sockindex]; + conn->writesockfd = writesockindex == -1 ? + CURL_SOCKET_BAD:conn->sock[writesockindex]; + } + k->getheader = getheader; + + k->size = size; + + /* The code sequence below is placed in this function just because all + necessary input is not always known in do_complete() as this function may + be called after that */ + + if(!k->getheader) { + k->header = FALSE; + if(size > 0) + Curl_pgrsSetDownloadSize(data, size); + } + /* we want header and/or body, if neither then don't do this! */ + if(k->getheader || !data->set.opt_no_body) { + + if(sockindex != -1) + k->keepon |= KEEP_RECV; + + if(writesockindex != -1) { + /* HTTP 1.1 magic: + + Even if we require a 100-return code before uploading data, we might + need to write data before that since the REQUEST may not have been + finished sent off just yet. + + Thus, we must check if the request has been sent before we set the + state info where we wait for the 100-return code + */ + if((data->state.expect100header) && + (conn->handler->protocol&PROTO_FAMILY_HTTP) && + (http->sending == HTTPSEND_BODY)) { + /* /1* wait with write until we either got 100-continue or a timeout *1/ */ + /* k->exp100 = EXP100_AWAITING_CONTINUE; */ + /* k->start100 = Curl_now(); */ + + /* /1* Set a timeout for the multi interface. Add the inaccuracy margin so */ + /* that we don't fire slightly too early and get denied to run. *1/ */ + /* Curl_expire(data, data->set.expect_100_timeout, EXPIRE_100_TIMEOUT); */ + } + else { + if(data->state.expect100header) + /* when we've sent off the rest of the headers, we must await a + 100-continue but first finish sending the request */ + k->exp100 = EXP100_SENDING_REQUEST; + + /* enable the write bit when we're not waiting for continue */ + k->keepon |= KEEP_SEND; + } + } /* if(writesockindex != -1) */ + } /* if(k->getheader || !data->set.opt_no_body) */ + +} #endif /*CURL_DISABLE_GEMINI*/ diff --git a/lib/setopt.c b/lib/setopt.c index 4570cc06a..80332a510 100644 --- a/lib/setopt.c +++ b/lib/setopt.c @@ -2831,6 +2831,9 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param) return result; break; #endif + case CURLOPT_META: + result = Curl_setstropt(&data->set.gemini_meta, va_arg(param, char *)); + break; default: /* unknown tag and its companion, just ignore: */ result = CURLE_UNKNOWN_OPTION; diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h index 4a90d0b72..42a827388 100644 --- a/src/tool_cfgable.h +++ b/src/tool_cfgable.h @@ -280,6 +280,7 @@ struct OperationConfig { 0 is valid. default: CURL_HET_DEFAULT. */ bool haproxy_protocol; /* whether to send HAProxy protocol v1 */ bool disallow_username_in_url; /* disallow usernames in URLs */ + char *meta; /* gemini request meta */ struct GlobalConfig *global; struct OperationConfig *prev; struct OperationConfig *next; /* Always last in the struct */ -- cgit v1.2.3