* 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,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",
"<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.
* 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",
"<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 static void
ProcessHTTPSubscribe_upnphttp(struct upnphttp * h, const char * path) ProcessHTTPSubscribe_upnphttp(struct upnphttp * h, const char * path)
{ {
const char * sid; const char * sid;
enum event_type type;
DPRINTF(E_DEBUG, L_HTTP, "ProcessHTTPSubscribe %s\n", path); DPRINTF(E_DEBUG, L_HTTP, "ProcessHTTPSubscribe %s\n", path);
DPRINTF(E_DEBUG, L_HTTP, "Callback '%.*s' Timeout=%d\n", DPRINTF(E_DEBUG, L_HTTP, "Callback '%.*s' Timeout=%d\n",
h->req_CallbackLen, h->req_Callback, h->req_Timeout); h->req_CallbackLen, h->req_Callback, h->req_Timeout);
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);
if((!h->req_Callback && !h->req_SID) ||
strncmp(h->req_NT, "upnp:event", h->req_NTLen) != 0) { type = check_event(h);
/* Missing or invalid CALLBACK : 412 Precondition Failed. if (type == E_SUBSCRIBE)
* If CALLBACK header is missing or does not contain a valid HTTP URL, {
* the publisher must respond with HTTP error 412 Precondition Failed*/ /* - add to the subscriber list
BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0); * - respond HTTP/x.x 200 OK
SendResp_upnphttp(h); * - Send the initial event message */
CloseSocket_upnphttp(h); /* Server:, SID:; Timeout: Second-(xx|infinite) */
} else { sid = upnpevents_addSubscriber(path, h->req_Callback,
/* - add to the subscriber list h->req_CallbackLen, h->req_Timeout);
* - respond HTTP/x.x 200 OK h->respflags = FLAG_TIMEOUT;
* - Send the initial event message */ if (sid)
/* Server:, SID:; Timeout: Second-(xx|infinite) */ {
if(h->req_Callback) { DPRINTF(E_DEBUG, L_HTTP, "generated sid=%s\n", sid);
if(!h->req_NT || strncmp(h->req_NT, "upnp:event", h->req_NTLen) != 0) { h->respflags |= FLAG_SID;
BuildResp2_upnphttp(h, 400, "Bad Request", h->req_SID = sid;
"<html><body>Bad request</body></html>", 37); h->req_SIDLen = strlen(sid);
} 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);
}
} }
SendResp_upnphttp(h); BuildResp_upnphttp(h, 0, 0);
CloseSocket_upnphttp(h);
} }
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 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);
BuildResp2_upnphttp(h, 412, "Precondition Failed", 0, 0); if (type != E_INVALID)
} else { {
BuildResp_upnphttp(h, 0, 0); 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); SendResp_upnphttp(h);
CloseSocket_upnphttp(h); CloseSocket_upnphttp(h);