diff --git a/upnphttp.c b/upnphttp.c index 92ac172..dc37b10 100644 --- a/upnphttp.c +++ b/upnphttp.c @@ -88,6 +88,12 @@ #include "icons.c" +enum event_type { + E_INVALID, + E_SUBSCRIBE, + E_RENEW +}; + struct upnphttp * New_upnphttp(int s) { @@ -210,9 +216,6 @@ ParseHttpHeaders(struct upnphttp * h) n++; h->req_Callback = p + 1; h->req_CallbackLen = MAX(0, n - 1); - /* Verify callback validity */ - if(strncmp(h->req_Callback, "http://", 7) != 0) - h->req_Callback = NULL; } else if(strncasecmp(line, "SID", 3)==0) { @@ -741,74 +744,119 @@ ProcessHTTPPOST_upnphttp(struct upnphttp * h) } } +static int +check_event(struct upnphttp *h) +{ + enum event_type type; + + if (h->req_Callback) + { + if (h->req_SID || !h->req_NT) + { + BuildResp2_upnphttp(h, 400, "Bad Request", + "Bad request", 37); + type = E_INVALID; + } + else if (strncmp(h->req_Callback, "http://", 7) != 0 || + strncmp(h->req_NT, "upnp:event", h->req_NTLen) != 0) + { + /* Missing or invalid CALLBACK : 412 Precondition Failed. + * If CALLBACK header is missing or does not contain a valid HTTP URL, + * the publisher must respond with HTTP error 412 Precondition Failed*/ + BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0); + type = E_INVALID; + } + else + type = E_SUBSCRIBE; + } + else if (h->req_SID) + { + /* subscription renew */ + if (h->req_NT) + { + BuildResp2_upnphttp(h, 400, "Bad Request", + "Bad request", 37); + type = E_INVALID; + } + else + type = E_RENEW; + } + else + { + BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0); + type = E_INVALID; + } + + return type; +} + static void ProcessHTTPSubscribe_upnphttp(struct upnphttp * h, const char * path) { const char * sid; + enum event_type type; DPRINTF(E_DEBUG, L_HTTP, "ProcessHTTPSubscribe %s\n", path); DPRINTF(E_DEBUG, L_HTTP, "Callback '%.*s' Timeout=%d\n", h->req_CallbackLen, h->req_Callback, h->req_Timeout); DPRINTF(E_DEBUG, L_HTTP, "SID '%.*s'\n", h->req_SIDLen, h->req_SID); - if((!h->req_Callback && !h->req_SID) || - strncmp(h->req_NT, "upnp:event", h->req_NTLen) != 0) { - /* Missing or invalid CALLBACK : 412 Precondition Failed. - * If CALLBACK header is missing or does not contain a valid HTTP URL, - * the publisher must respond with HTTP error 412 Precondition Failed*/ - BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0); - SendResp_upnphttp(h); - CloseSocket_upnphttp(h); - } else { - /* - add to the subscriber list - * - respond HTTP/x.x 200 OK - * - Send the initial event message */ - /* Server:, SID:; Timeout: Second-(xx|infinite) */ - if(h->req_Callback) { - if(!h->req_NT || strncmp(h->req_NT, "upnp:event", h->req_NTLen) != 0) { - BuildResp2_upnphttp(h, 400, "Bad Request", - "Bad request", 37); - } else { - sid = upnpevents_addSubscriber(path, h->req_Callback, - h->req_CallbackLen, h->req_Timeout); - h->respflags = FLAG_TIMEOUT; - if(sid) { - DPRINTF(E_DEBUG, L_HTTP, "generated sid=%s\n", sid); - h->respflags |= FLAG_SID; - h->req_SID = sid; - h->req_SIDLen = strlen(sid); - } - BuildResp_upnphttp(h, 0, 0); - } - } else { - /* subscription renew */ - /* Invalid SID -412 Precondition Failed. If a SID does not correspond to a known, -un-expired subscription, the publisher must respond -with HTTP error 412 Precondition Failed. */ - if(renewSubscription(h->req_SID, h->req_SIDLen, h->req_Timeout) < 0) { - BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0); - } else { - /* A DLNA device must enforce a 5 minute timeout */ - h->respflags = FLAG_TIMEOUT; - h->req_Timeout = 300; - h->respflags |= FLAG_SID; - BuildResp_upnphttp(h, 0, 0); - } + + type = check_event(h); + if (type == E_SUBSCRIBE) + { + /* - add to the subscriber list + * - respond HTTP/x.x 200 OK + * - Send the initial event message */ + /* Server:, SID:; Timeout: Second-(xx|infinite) */ + sid = upnpevents_addSubscriber(path, h->req_Callback, + h->req_CallbackLen, h->req_Timeout); + h->respflags = FLAG_TIMEOUT; + if (sid) + { + DPRINTF(E_DEBUG, L_HTTP, "generated sid=%s\n", sid); + h->respflags |= FLAG_SID; + h->req_SID = sid; + h->req_SIDLen = strlen(sid); } - SendResp_upnphttp(h); - CloseSocket_upnphttp(h); + BuildResp_upnphttp(h, 0, 0); } + else if (type == E_RENEW) + { + /* subscription renew */ + if (renewSubscription(h->req_SID, h->req_SIDLen, h->req_Timeout) < 0) + { + /* Invalid SID + 412 Precondition Failed. If a SID does not correspond to a known, + un-expired subscription, the publisher must respond + with HTTP error 412 Precondition Failed. */ + BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0); + } + else + { + /* A DLNA device must enforce a 5 minute timeout */ + h->respflags = FLAG_TIMEOUT; + h->req_Timeout = 300; + h->respflags |= FLAG_SID; + BuildResp_upnphttp(h, 0, 0); + } + } + SendResp_upnphttp(h); + CloseSocket_upnphttp(h); } static void ProcessHTTPUnSubscribe_upnphttp(struct upnphttp * h, const char * path) { + enum event_type type; DPRINTF(E_DEBUG, L_HTTP, "ProcessHTTPUnSubscribe %s\n", path); DPRINTF(E_DEBUG, L_HTTP, "SID '%.*s'\n", h->req_SIDLen, h->req_SID); /* Remove from the list */ - if(upnpevents_removeSubscriber(h->req_SID, h->req_SIDLen) < 0) { - BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0); - } else { - BuildResp_upnphttp(h, 0, 0); + type = check_event(h); + if (type != E_INVALID) + { + if(upnpevents_removeSubscriber(h->req_SID, h->req_SIDLen) < 0) + BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0); + else + BuildResp_upnphttp(h, 0, 0); } SendResp_upnphttp(h); CloseSocket_upnphttp(h);