From 8b8772eed154a4a7c0124fd0591cbcb50d801399 Mon Sep 17 00:00:00 2001 From: Thomas Bernard Date: Fri, 28 Sep 2012 11:12:50 +0200 Subject: [PATCH] miniupnpd: Support Expect: 100-continue for POST HTTP requests --- miniupnpd/Changelog.txt | 1 + miniupnpd/upnphttp.c | 67 +++++++++++++++++++++++++++++++++++++++++ miniupnpd/upnphttp.h | 7 +++++ 3 files changed, 75 insertions(+) diff --git a/miniupnpd/Changelog.txt b/miniupnpd/Changelog.txt index 38cf786..28792b9 100644 --- a/miniupnpd/Changelog.txt +++ b/miniupnpd/Changelog.txt @@ -7,6 +7,7 @@ $Id: Changelog.txt,v 1.309 2012/09/27 16:01:10 nanard Exp $ SetDefaultConnectionService() checks its argumnents in UPNP_STRICT mode Support for Accept-Language/Content-Language HTTP headers Content-Type is now text/xml; charset="utf-8" to conform with UDA v1.1 + Support Expect: 100-continue for POST HTTP requests 2012/09/20: Cleaning code in ipfw (Jardel Weyrich) diff --git a/miniupnpd/upnphttp.c b/miniupnpd/upnphttp.c index 119ed46..248e325 100644 --- a/miniupnpd/upnphttp.c +++ b/miniupnpd/upnphttp.c @@ -129,6 +129,19 @@ ParseHttpHeaders(struct upnphttp * h) memcpy(h->accept_language, p, n); h->accept_language[n] = '\0'; } + else if(strncasecmp(line, "expect", 6) == 0) + { + p = colon; + n = 0; + while(*p == ':' || *p == ' ' || *p == '\t') + p++; + while(p[n]>=' ') + n++; + if(strncasecmp(p, "100-continue", 12) == 0) { + h->respflags |= FLAG_CONTINUE; + syslog(LOG_DEBUG, "\"Expect: 100-Continue\" header detected"); + } + } #ifdef ENABLE_EVENTS else if(strncasecmp(line, "Callback", 8)==0) { @@ -281,6 +294,7 @@ ProcessHTTPPOST_upnphttp(struct upnphttp * h) { if((h->req_buflen - h->req_contentoff) >= h->req_contentlen) { + /* the request body is received */ if(h->req_soapActionOff > 0) { /* we can process the request */ @@ -301,6 +315,20 @@ ProcessHTTPPOST_upnphttp(struct upnphttp * h) SendRespAndClose_upnphttp(h); } } + else if(h->respflags & FLAG_CONTINUE) + { + /* Sending the 100 Continue response */ + if(!h->res_buf) { + h->res_buf = malloc(256); + h->res_buf_alloclen = 256; + } + h->res_buflen = snprintf(h->res_buf, h->res_buf_alloclen, + "%s 100 Continue\r\n\r\n", h->HttpVer); + h->res_sent = 0; + h->state = ESendingContinue; + if(SendResp_upnphttp(h)) + h->state = EWaitingForHttpContent; + } else { /* waiting for remaining data */ @@ -645,6 +673,10 @@ Process_upnphttp(struct upnphttp * h) } } break; + case ESendingContinue: + if(SendResp_upnphttp(h)) + h->state = EWaitingForHttpContent; + break; case ESendingAndClosing: SendRespAndClose_upnphttp(h); break; @@ -772,6 +804,41 @@ BuildResp_upnphttp(struct upnphttp * h, BuildResp2_upnphttp(h, 200, "OK", body, bodylen); } +int +SendResp_upnphttp(struct upnphttp * h) +{ + ssize_t n; + + while (h->res_sent < h->res_buflen) + { + n = send(h->socket, h->res_buf + h->res_sent, + h->res_buflen - h->res_sent, 0); + if(n<0) + { + if(errno == EINTR) + continue; /* try again immediatly */ + if(errno == EAGAIN || errno == EWOULDBLOCK) + { + /* try again later */ + return 0; + } + syslog(LOG_ERR, "send(res_buf): %m"); + break; /* avoid infinite loop */ + } + else if(n == 0) + { + syslog(LOG_ERR, "send(res_buf): %d bytes sent (out of %d)", + h->res_sent, h->res_buflen); + break; + } + else + { + h->res_sent += n; + } + } + return 1; /* finished */ +} + void SendRespAndClose_upnphttp(struct upnphttp * h) { diff --git a/miniupnpd/upnphttp.h b/miniupnpd/upnphttp.h index bb08ecc..434aa31 100644 --- a/miniupnpd/upnphttp.h +++ b/miniupnpd/upnphttp.h @@ -34,6 +34,7 @@ enum httpStates { EWaitingForHttpRequest = 0, EWaitingForHttpContent, + ESendingContinue, ESendingAndClosing, EToDelete = 100 }; @@ -86,6 +87,9 @@ struct upnphttp { /* Include the "SID:" header in response */ #define FLAG_SID 0x02 +/* If set, the POST request included a "Expect: 100-continue" header */ +#define FLAG_CONTINUE 0x40 + /* If set, the Content-Type is set to text/xml, otherwise it is text/xml */ #define FLAG_HTML 0x80 @@ -131,6 +135,9 @@ BuildResp2_upnphttp(struct upnphttp * h, int respcode, const char * respmsg, const char * body, int bodylen); +int +SendResp_upnphttp(struct upnphttp *); + /* SendRespAndClose_upnphttp() */ void SendRespAndClose_upnphttp(struct upnphttp *);