* 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"
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",
"<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
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",
"<html><body>Bad request</body></html>", 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);