aboutsummaryrefslogtreecommitdiff
path: root/lib/vquic/quiche.c
diff options
context:
space:
mode:
authorDaniel Stenberg <daniel@haxx.se>2019-08-05 15:17:31 +0200
committerDaniel Stenberg <daniel@haxx.se>2019-08-06 07:39:21 +0200
commitdc35631ef7fe314c227ba0b8529a4e0f5f383f79 (patch)
tree828a024aba273587cbecad74ccfe0fbc6b39e8dc /lib/vquic/quiche.c
parenta42b0957ab31c971a79bfe5542b3017fd834ac49 (diff)
quiche: first working HTTP/3 request
- enable debug log - fix use of quiche API - use download buffer - separate header/body Closes #4193
Diffstat (limited to 'lib/vquic/quiche.c')
-rw-r--r--lib/vquic/quiche.c100
1 files changed, 77 insertions, 23 deletions
diff --git a/lib/vquic/quiche.c b/lib/vquic/quiche.c
index 2ccee1142..a70fb2237 100644
--- a/lib/vquic/quiche.c
+++ b/lib/vquic/quiche.c
@@ -38,7 +38,7 @@
#include "curl_memory.h"
#include "memdebug.h"
-#define DEBUG_HTTP3
+/* #define DEBUG_HTTP3 */
#ifdef DEBUG_HTTP3
#define H3BUGF(x) x
#else
@@ -198,10 +198,12 @@ static CURLcode process_ingress(struct connectdata *conn, int sockfd)
{
ssize_t recvd;
struct quicsocket *qs = &conn->quic;
- static uint8_t buf[65535];
+ struct Curl_easy *data = conn->data;
+ uint8_t *buf = (uint8_t *)data->state.buffer;
+ size_t bufsize = data->set.buffer_size;
do {
- recvd = recv(sockfd, buf, sizeof(buf), 0);
+ recvd = recv(sockfd, buf, bufsize, 0);
if((recvd < 0) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)))
break;
@@ -245,13 +247,33 @@ static CURLcode flush_egress(struct connectdata *conn, int sockfd)
return CURLE_OK;
}
+struct h3h1header {
+ char *dest;
+ size_t destlen; /* left to use */
+ size_t nlen; /* used */
+};
+
static int cb_each_header(uint8_t *name, size_t name_len,
uint8_t *value, size_t value_len,
void *argp)
{
- (void)argp;
- fprintf(stderr, "got HTTP header: %.*s=%.*s\n",
- (int) name_len, name, (int) value_len, value);
+ struct h3h1header *headers = (struct h3h1header *)argp;
+ size_t olen = 0;
+
+ if((name_len == 7) && !strncmp(":status", (char *)name, 7)) {
+ msnprintf(headers->dest,
+ headers->destlen, "HTTP/3 %.*s\n",
+ (int) value_len, value);
+ }
+ else {
+ msnprintf(headers->dest,
+ headers->destlen, "%.*s: %.*s\n",
+ (int)name_len, name, (int) value_len, value);
+ }
+ olen = strlen(headers->dest);
+ headers->destlen -= olen;
+ headers->nlen += olen;
+ headers->dest += olen;
return 0;
}
@@ -261,60 +283,80 @@ static ssize_t h3_stream_recv(struct connectdata *conn,
size_t buffersize,
CURLcode *curlcode)
{
- bool fin;
- ssize_t recvd;
+ ssize_t recvd = -1;
+ ssize_t rcode;
struct quicsocket *qs = &conn->quic;
curl_socket_t sockfd = conn->sock[sockindex];
quiche_h3_event *ev;
int rc;
+ struct h3h1header headers;
+ struct HTTP *stream = conn->data->req.protop;
+ headers.dest = buf;
+ headers.destlen = buffersize;
+ headers.nlen = 0;
if(process_ingress(conn, sockfd)) {
+ infof(conn->data, "h3_stream_recv returns on ingress\n");
*curlcode = CURLE_RECV_ERROR;
return -1;
}
- recvd = quiche_conn_stream_recv(qs->conn, 0, (uint8_t *) buf, buffersize,
- &fin);
- if(recvd == QUICHE_ERR_DONE) {
- *curlcode = CURLE_AGAIN;
- return -1;
- }
-
- infof(conn->data, "%zd bytes of H3 to deal with\n", recvd);
-
- while(1) {
+ while(recvd < 0) {
int64_t s = quiche_h3_conn_poll(qs->h3c, qs->conn, &ev);
if(s < 0)
/* nothing more to do */
break;
+ infof(conn->data, "quiche_h3_conn_poll got something: %zd\n", s);
+
switch(quiche_h3_event_type(ev)) {
case QUICHE_H3_EVENT_HEADERS:
- rc = quiche_h3_event_for_each_header(ev, cb_each_header, NULL);
+ infof(conn->data, "quiche says HEADERS\n");
+ rc = quiche_h3_event_for_each_header(ev, cb_each_header, &headers);
if(rc) {
fprintf(stderr, "failed to process headers");
/* what do we do about this? */
}
+ recvd = headers.nlen;
break;
case QUICHE_H3_EVENT_DATA:
- recvd = quiche_h3_recv_body(qs->h3c, qs->conn, s, (unsigned char *)buf,
+ infof(conn->data, "quiche says DATA\n");
+ if(!stream->firstbody) {
+ /* add a header-body separator CRLF */
+ buf[0] = '\r';
+ buf[1] = '\n';
+ buf += 2;
+ buffersize = 2;
+ stream->firstbody = TRUE;
+ recvd = 2; /* two bytes already */
+ }
+ else
+ recvd = 0;
+ rcode = quiche_h3_recv_body(qs->h3c, qs->conn, s, (unsigned char *)buf,
buffersize);
- if(recvd <= 0) {
+ if(rcode <= 0) {
+ recvd = -1;
break;
}
+ recvd += rcode;
break;
case QUICHE_H3_EVENT_FINISHED:
+ infof(conn->data, "quiche says FINISHED\n");
if(quiche_conn_close(qs->conn, true, 0, NULL, 0) < 0) {
fprintf(stderr, "failed to close connection\n");
}
break;
+ default:
+ infof(conn->data, "quiche says UNKNOWN\n");
+ break;
}
quiche_h3_event_free(ev);
}
- *curlcode = CURLE_OK;
+ *curlcode = (-1 == recvd)? CURLE_AGAIN : CURLE_OK;
+ infof(conn->data, "h3_stream_recv returns %zd\n", recvd);
return recvd;
}
@@ -334,7 +376,7 @@ static ssize_t h3_stream_send(struct connectdata *conn,
*curlcode = CURLE_SEND_ERROR;
return -1;
}
- return len;
+ sent = len;
}
else {
sent = quiche_conn_stream_send(qs->conn, 0, mem, len, true);
@@ -362,6 +404,14 @@ int Curl_quic_ver(char *p, size_t len)
return msnprintf(p, len, " quiche");
}
+#ifdef DEBUG_HTTP3
+static void debug_log(const char *line, void *argp)
+{
+ (void)argp;
+ fprintf(stderr, "%s\n", line);
+}
+#endif
+
/* Index where :authority header field will appear in request header
field list. */
#define AUTHORITY_DST_IDX 3
@@ -381,6 +431,10 @@ static CURLcode http_request(struct connectdata *conn, const void *mem,
quiche_h3_header *nva = NULL;
struct quicsocket *qs = &conn->quic;
+#ifdef DEBUG_HTTP3
+ quiche_enable_debug_logging(debug_log, NULL);
+#endif
+
qs->config = quiche_h3_config_new(0, 1024, 0, 0);
/* TODO: handle failure */