From: Fredrik Tolf Date: Wed, 18 May 2016 01:03:43 +0000 (+0200) Subject: htparser: Added support for full-duplex requests. X-Git-Url: http://www.dolda2000.com/gitweb/?p=ashd.git;a=commitdiff_plain;h=a68db17def8493b7f338541d57bcb7ca0de64618 htparser: Added support for full-duplex requests. --- diff --git a/src/htparser.c b/src/htparser.c index 73d9404..bb23539 100644 --- a/src/htparser.c +++ b/src/htparser.c @@ -305,14 +305,57 @@ done: return(ret); } -void serve(struct bufio *in, struct conn *conn) +static void passduplex(struct bufio *a, int afd, struct bufio *b, int bfd) +{ + struct selected pfd[4], sel; + struct bufio *sio; + int n, ev; + + while(!bioeof(a) && !bioeof(b)) { + biocopybuf(b, a); + biocopybuf(a, b); + n = 0; + if(!a->eof) { + ev = 0; + if(biorspace(a)) + ev |= EV_READ; + if(biowdata(a)) + ev |= EV_WRITE; + if(ev) + pfd[n++] = (struct selected){.fd = afd, .ev = ev}; + } + if(!b->eof) { + ev = 0; + if(!b->eof && biorspace(b)) + ev |= EV_READ; + if(biowdata(b)) + ev |= EV_WRITE; + if(ev) + pfd[n++] = (struct selected){.fd = bfd, .ev = ev}; + } + sel = mblock(600, n, pfd); + if(sel.fd == afd) + sio = a; + else if(sel.fd == bfd) + sio = b; + else + break; + if((sel.ev & EV_READ) && (biofillsome(sio) < 0)) + break; + if((sel.ev & EV_WRITE) && (bioflushsome(sio) < 0)) + break; + } +} + +void serve(struct bufio *in, int infd, struct conn *conn) { int pfds[2]; - struct bufio *out; + struct bufio *out, *dout; + struct stdiofd *outi; struct hthead *req, *resp; char *hd, *id; off_t dlen; - int keep; + int keep, duplex; id = connid(); out = NULL; @@ -335,7 +378,7 @@ void serve(struct bufio *in, struct conn *conn) if(sendreq(plex, req, pfds[0])) break; close(pfds[0]); - out = mtbioopen(pfds[1], 1, 600, "r+", NULL); + out = mtbioopen(pfds[1], 1, 600, "r+", &outi); if(getheader(req, "content-type") != NULL) { if((hd = getheader(req, "content-length")) != NULL) { @@ -363,8 +406,20 @@ void serve(struct bufio *in, struct conn *conn) if(!getheader(resp, "server")) headappheader(resp, "Server", sprintf3("ashd/%s", VERSION)); + duplex = hasheader(resp, "x-ash-switch", "duplex"); + trimx(resp); - if(!strcasecmp(req->ver, "HTTP/1.0")) { + if(duplex) { + if(outi->rights < 0) + break; + writerespb(in, resp); + bioprintf(in, "\r\n"); + dout = mtbioopen(outi->rights, 1, 600, "r+", NULL); + passduplex(in, infd, dout, outi->rights); + outi->rights = -1; + bioclose(dout); + break; + } else if(!strcasecmp(req->ver, "HTTP/1.0")) { if(!strcasecmp(req->method, "head")) { keep = http10keep(req, resp); writerespb(in, resp); diff --git a/src/htparser.h b/src/htparser.h index 91652e6..d9f014d 100644 --- a/src/htparser.h +++ b/src/htparser.h @@ -11,7 +11,7 @@ struct mtbuf { size_t s, d; }; -void serve(struct bufio *in, struct conn *conn); +void serve(struct bufio *in, int infd, struct conn *conn); int listensock4(int port); int listensock6(int port); diff --git a/src/plaintcp.c b/src/plaintcp.c index de99dcd..56fc81c 100644 --- a/src/plaintcp.c +++ b/src/plaintcp.c @@ -162,7 +162,7 @@ void servetcp(struct muth *muth, va_list args) tcp.fd = fd; tcp.name = name; tcp.port = stcp; - serve(in, &conn); + serve(in, fd, &conn); } static void listenloop(struct muth *muth, va_list args) diff --git a/src/ssl-gnutls.c b/src/ssl-gnutls.c index 642c661..7aa1df0 100644 --- a/src/ssl-gnutls.c +++ b/src/ssl-gnutls.c @@ -344,7 +344,7 @@ static void servessl(struct muth *muth, va_list args) ssl.name = name; ssl.sess = sess; bufinit(ssl.in); - serve(bioopen(&ssl, &iofuns), &conn); + serve(bioopen(&ssl, &iofuns), fd, &conn); out: gnutls_deinit(sess);