From 78ba3ee1d71032a1325036d5cefa8d0549d76ccd Mon Sep 17 00:00:00 2001 From: Fredrik Tolf Date: Sun, 19 Oct 2008 07:58:39 +0200 Subject: [PATCH] Handle HTTP redirections automatically. --- clients/gtk2/hublist.c | 1 + common/httest.c | 1 + common/http.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++++-- include/http.h | 1 + 4 files changed, 58 insertions(+), 2 deletions(-) diff --git a/clients/gtk2/hublist.c b/clients/gtk2/hublist.c index 74910e5..ff94161 100644 --- a/clients/gtk2/hublist.c +++ b/clients/gtk2/hublist.c @@ -200,6 +200,7 @@ void fetchhublist(char *url, regex_t *flt) msgbox(GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, _("Could not read hublist from server: %s"), strerror(errno)); return; } + hc->autoredir = 1; state = 0; settags(); gtk_widget_show(main_pubhubbarbox); diff --git a/common/httest.c b/common/httest.c index 60a67f6..a3ea649 100644 --- a/common/httest.c +++ b/common/httest.c @@ -94,6 +94,7 @@ void get(char *url) } c = htconnect(u); freeurl(u); + c->autoredir = 1; while(1) { pfd.fd = c->fd; pfd.events = htpollflags(c); diff --git a/common/http.c b/common/http.c index 33f443c..3ac3b14 100644 --- a/common/http.c +++ b/common/http.c @@ -136,6 +136,8 @@ void freehtconn(struct htconn *cn) free(cn->databuf); if(cn->resstr != NULL) free(cn->resstr); + while(cn->headers) + freestrpair(cn->headers, &cn->headers); freeurl(cn->url); freeaddrinfo(cn->ailist); if(cn->fd != -1) @@ -143,6 +145,32 @@ void freehtconn(struct htconn *cn) free(cn); } +static int resethtconn(struct htconn *cn, struct hturlinfo *ui) +{ + if(cn->fd != -1) + close(cn->fd); + if(cn->resstr != NULL) + free(cn->resstr); + freeurl(cn->url); + freeaddrinfo(cn->ailist); + while(cn->headers) + freestrpair(cn->headers, &cn->headers); + + cn->state = STATE_SYN; + cn->fd = -1; + cn->outbufdata = cn->inbufdata = cn->databufdata = 0; + cn->rescode = 0; + cn->resstr = NULL; + cn->tlen = -1; + cn->rxd = 0; + cn->chl = 0; + cn->url = dupurl(ui); + cn->ailist = resolvtcp(ui->host, ui->port); + cn->curai = NULL; + + return(htprocess(cn, 0)); +} + struct htconn *htconnect(struct hturlinfo *ui) { struct htconn *cn; @@ -257,6 +285,7 @@ int htprocess(struct htconn *cn, int pollflags) socklen_t optlen; char rxbuf[1024]; char *p, *p2, *p3; + struct hturlinfo *ui; if(cn->state == STATE_SYN) { if(cn->fd != -1) { @@ -418,8 +447,14 @@ int htprocess(struct htconn *cn, int pollflags) } if(cn->state == STATE_RXBODY) { if(ret == 0) { - HTDEBUG("EOF in body, flagging as done\n"); - cn->state = STATE_DONE; + if(cn->tlen == -1) { + HTDEBUG("EOF in body without Content-Length, flagging as done\n"); + cn->state = STATE_DONE; + } else { + HTDEBUG("got premature if in body with Content-Length, flagging EPROTO\n"); + errno = EPROTO; + return(-1); + } } else { bufcat(cn->databuf, cn->inbuf, cn->inbufdata); HTDEBUG("transferred %i bytes from inbuf to databuf, %i bytes now in databuf\n", cn->inbufdata, cn->databufdata); @@ -473,5 +508,23 @@ int htprocess(struct htconn *cn, int pollflags) } } } while(!done); + if((cn->state == STATE_DONE) && cn->autoredir) { + if((cn->rescode == 301) || (cn->rescode == 302) || (cn->rescode == 303) || (cn->rescode == 307)) { + if((p = spfind(cn->headers, "location")) == NULL) { + HTDEBUG("got redirect without Location, flagging EPROTO\n"); + errno = EPROTO; + return(-1); + } + if((ui = parseurl(p)) == NULL) { + HTDEBUG("unparsable URL in redirection (%s), flagging EPROTO\n", p); + errno = EPROTO; + return(-1); + } + HTDEBUG("autohandling redirect (%i, ->%s)\n", cn->rescode, p); + ret = resethtconn(cn, ui); + freeurl(ui); + return(ret); + } + } return((cn->state == STATE_DONE)?1:0); } diff --git a/include/http.h b/include/http.h index ca7d42f..8403e35 100644 --- a/include/http.h +++ b/include/http.h @@ -45,6 +45,7 @@ struct htconn { char *resstr; struct strpair *headers; ssize_t tlen, rxd, chl; + int autoredir; }; struct htcookie { -- 2.11.0