* Improve error checking for UPnP events.

This commit is contained in:
Justin Maggard 2012-05-10 22:34:05 +00:00
parent 12257dff81
commit 2383bd97fe

View File

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