diff --git a/src/App.h b/src/App.h index 95ed065..8687cd1 100644 --- a/src/App.h +++ b/src/App.h @@ -116,7 +116,7 @@ public: /* This will do for now, would be better if us_socket_context_remove_server_name returned the user data */ auto *domainRouter = us_socket_context_find_server_name_userdata(SSL, (struct us_socket_context_t *) httpContext, hostname_pattern.c_str()); if (domainRouter) { - delete domainRouter; + delete (HttpRouter::RouterData>) domainRouter; } us_socket_context_remove_server_name(SSL, (struct us_socket_context_t *) httpContext, hostname_pattern.c_str()); diff --git a/src/Http3Context.h b/src/Http3Context.h index dabbdc4..53c9125 100644 --- a/src/Http3Context.h +++ b/src/Http3Context.h @@ -33,16 +33,18 @@ namespace uWS { } /* Have we written our entire backpressure, if any? */ - if (responseData->buffer.length() && (responseData->bufferOffset == (int) responseData->buffer.length())) { - printf("We got FIN and we have no backpressure, closing stream now!\n"); - us_quic_stream_close(s); - } else { - printf("We got FIN but we have data to write, so keeping connection half-closed!\n"); - } + // if (responseData->buffer.length() && (responseData->bufferOffset == (int) responseData->buffer.length())) { + // printf("We got FIN and we have no backpressure, closing stream now!\n"); + // //us_quic_stream_close(s); + // } else { + // //printf("We got FIN but we have data to write, so keeping connection half-closed!\n"); + // } }); us_quic_socket_context_on_stream_open(context, [](us_quic_stream_t *s, int is_client) { + printf("Stream open!\n"); + /* Inplace init our per stream data */ new (us_quic_stream_ext(s)) Http3ResponseData(); }); @@ -52,15 +54,18 @@ namespace uWS { us_quic_socket_context_on_stream_writable(context, [](us_quic_stream_t *s) { Http3ResponseData *responseData = (Http3ResponseData *) us_quic_stream_ext(s); - int written = us_quic_stream_write(s, responseData->buffer.data() + responseData->bufferOffset, (int) responseData->buffer.length() - responseData->bufferOffset); - responseData->bufferOffset += written; + /* Either we handle the streaming or we let the application handle it */ + if (responseData->onWritable) { + responseData->onWritable(responseData->offset); + } else { + int written = us_quic_stream_write(s, (char *) responseData->backpressure.data(), responseData->backpressure.length()); + responseData->backpressure.erase(written); - //printf("remaingin bytes: %ld\n", responseData->buffer.length() - responseData->bufferOffset); - - if ((int) responseData->buffer.length() - responseData->bufferOffset == 0) { - printf("wrote until end, shutting down now!\n"); - us_quic_stream_shutdown(s); - us_quic_stream_close(s); + if (responseData->backpressure.length() == 0) { + printf("wrote until end, shutting down now!\n"); + us_quic_stream_shutdown(s); + us_quic_stream_close(s); + } } }); us_quic_socket_context_on_stream_headers(context, [](us_quic_stream_t *s) { @@ -82,13 +87,17 @@ namespace uWS { }); us_quic_socket_context_on_stream_close(context, [](us_quic_stream_t *s) { + printf("Stream closed!\n"); + + //lsquic_stream_has_unacked_data + Http3ResponseData *responseData = (Http3ResponseData *) us_quic_stream_ext(s); if (responseData->onAborted) { responseData->onAborted(); } - printf("Freeing per stream data in on_stream_close in uws!\n"); + //printf("Freeing per stream data in on_stream_close in uws!\n"); responseData->~Http3ResponseData(); }); diff --git a/src/Http3Response.h b/src/Http3Response.h index dab80df..8545a36 100644 --- a/src/Http3Response.h +++ b/src/Http3Response.h @@ -9,44 +9,75 @@ namespace uWS { /* Is a quic stream */ struct Http3Response { - void writeStatus() { + Http3Response *writeStatus(std::string_view status) { + Http3ResponseData *responseData = (Http3ResponseData *) us_quic_stream_ext((us_quic_stream_t *) this); + /* Nothing is done if status already written */ + if (responseData->headerOffset == 0) { + us_quic_socket_context_set_header(nullptr, 0, (char *) ":status", 7, status.data(), status.length()); + responseData->headerOffset = 1; + } + + return this; } - void writeHeader() { + Http3Response *writeHeader(std::string_view key, std::string_view value) { + Http3ResponseData *responseData = (Http3ResponseData *) us_quic_stream_ext((us_quic_stream_t *) this); + writeStatus("200 OK"); + + us_quic_socket_context_set_header(nullptr, responseData->headerOffset++, key.data(), key.length(), value.data(), value.length()); + + return this; } - void tryEnd() { + std::pair tryEnd(std::string_view data, uintmax_t totalSize = 0) { + Http3ResponseData *responseData = (Http3ResponseData *) us_quic_stream_ext((us_quic_stream_t *) this); + writeStatus("200 OK"); + + us_quic_socket_context_send_headers(nullptr, (us_quic_stream_t *) this, responseData->headerOffset, data.length() > 0); + + + unsigned int written = us_quic_stream_write((us_quic_stream_t *) this, (char *) data.data(), (int) data.length()); + + if (written == data.length()) { + return {true, true}; + } else { + + responseData->offset = written; + + return {true, false}; + } + + + return {true, true}; } - void write() { + /* Idnetical */ + Http3Response *write(std::string_view data) { + + return this; } - void end(std::string_view data) { + /* Identical */ + void end(std::string_view data = {}, bool closeConnection = false) { Http3ResponseData *responseData = (Http3ResponseData *) us_quic_stream_ext((us_quic_stream_t *) this); - // if not already written status then write status - - /* Write headers */ - us_quic_socket_context_set_header(nullptr, 0, (char *) ":status", 7, "200", 3); - //us_quic_socket_context_set_header(context, 1, "content-length", 14, "11", 2); - //us_quic_socket_context_set_header(context, 2, "content-type", 12, "text/html", 9); - us_quic_socket_context_send_headers(nullptr, (us_quic_stream_t *) this, 1, 1); + /* If not already written */ + writeStatus("200 OK"); + + // has body is determined by the ending so this is perfect here + us_quic_socket_context_send_headers(nullptr, (us_quic_stream_t *) this, responseData->headerOffset, data.length() > 0); /* Write body and shutdown (unknown if content-length must be present?) */ - int written = us_quic_stream_write((us_quic_stream_t *) this, (char *) data.data(), (int) data.length()); - - printf("Wrote %d bytes out of %ld\n", written, data.length()); + unsigned int written = us_quic_stream_write((us_quic_stream_t *) this, (char *) data.data(), (int) data.length()); /* Buffer up remains */ - if (written != (int) data.length()) { - responseData->buffer.clear(); - responseData->bufferOffset = written; - responseData->buffer.append(data); + if (written != data.length()) { + responseData->backpressure.append(data.data() + written, data.length() - written); } else { /* Every request has its own stream, so we conceptually serve requests like in HTTP 1.0 */ us_quic_stream_shutdown((us_quic_stream_t *) this); @@ -62,10 +93,18 @@ namespace uWS { } /* Attach a read handler for data sent. Will be called with FIN set true if last segment. */ - void onData(MoveOnlyFunction &&handler) { + Http3Response *onData(MoveOnlyFunction &&handler) { Http3ResponseData *responseData = (Http3ResponseData *) us_quic_stream_ext((us_quic_stream_t *) this); responseData->onData = std::move(handler); + return this; + } + + Http3Response *onWritable(MoveOnlyFunction &&handler) { + Http3ResponseData *responseData = (Http3ResponseData *) us_quic_stream_ext((us_quic_stream_t *) this); + + responseData->onWritable = std::move(handler); + return this; } };