static void ProcessHTTPSubscribe_upnphttp(struct upnphttp * h, const char * path) { const char * sid; syslog(LOG_DEBUG, "ProcessHTTPSubscribe %s", path); syslog(LOG_DEBUG, "Callback '%.*s' Timeout=%d", h->req_CallbackLen, h->req_Callback, h->req_Timeout); syslog(LOG_DEBUG, "SID '%.*s'", h->req_SIDLen, h->req_SID); if(!h->req_Callback && !h->req_SID) { /* 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) */ /* Check that the callback URL is on the same IP as * the request, and not on the internet, nor on ourself (DOS attack ?) */ if(h->req_Callback) { if(checkCallbackURL(h)) { sid = upnpevents_addSubscriber(path, h->req_Callback, h->req_CallbackLen, h->req_Timeout); h->respflags = FLAG_TIMEOUT; if(sid) { syslog(LOG_DEBUG, "generated sid=%s", sid); h->respflags |= FLAG_SID; h->req_SID = sid; h->req_SIDLen = strlen(sid); } BuildResp_upnphttp(h, 0, 0); } else { syslog(LOG_WARNING, "Invalid Callback in SUBSCRIBE %.*s", h->req_CallbackLen, h->req_Callback); BuildResp2_upnphttp(h, 412, "Precondition Failed", 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 { h->respflags = FLAG_TIMEOUT; BuildResp_upnphttp(h, 0, 0); } } SendResp_upnphttp(h); CloseSocket_upnphttp(h); } }
/* ProcessHTTPPOST_upnphttp() * executes the SOAP query if it is possible */ static void ProcessHTTPPOST_upnphttp(struct upnphttp * h) { if((h->req_buflen - h->req_contentoff) >= h->req_contentlen) { if(h->req_soapAction) { /* we can process the request */ syslog(LOG_INFO, "SOAPAction: %.*s", h->req_soapActionLen, h->req_soapAction); ExecuteSoapAction(h, h->req_soapAction, h->req_soapActionLen); } else { static const char err400str[] = "<html><body>Bad request</body></html>"; syslog(LOG_INFO, "No SOAPAction in HTTP headers"); h->respflags = FLAG_HTML; BuildResp2_upnphttp(h, 400, "Bad Request", err400str, sizeof(err400str) - 1); SendResp_upnphttp(h); CloseSocket_upnphttp(h); } } else { /* waiting for remaining data */ h->state = 1; } }
/* very minimalistic 501 error message */ static void Send501(struct upnphttp * h) { /* static const char error501[] = "HTTP/1.1 501 Not Implemented\r\n" "Connection: close\r\n" "Content-type: text/html\r\n" "\r\n" "<HTML><HEAD><TITLE>501 Not Implemented</TITLE></HEAD>" "<BODY><H1>Not Implemented</H1>The HTTP Method " "is not implemented by this server.</BODY></HTML>\r\n"; int n; n = send(h->socket, error501, sizeof(error501) - 1, 0); if(n < 0) { syslog(LOG_ERR, "Send501: send(http): %m"); } */ static const char body501[] = "<HTML><HEAD><TITLE>501 Not Implemented</TITLE></HEAD>" "<BODY><H1>Not Implemented</H1>The HTTP Method " "is not implemented by this server.</BODY></HTML>\r\n"; h->respflags = FLAG_HTML; BuildResp2_upnphttp(h, 501, "Not Implemented", body501, sizeof(body501) - 1); SendResp_upnphttp(h); CloseSocket_upnphttp(h); }
/* very minimalistic 404 error message */ static void Send404(struct upnphttp * h) { /* static const char error404[] = "HTTP/1.1 404 Not found\r\n" "Connection: close\r\n" "Content-type: text/html\r\n" "\r\n" "<HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD>" "<BODY><H1>Not Found</H1>The requested URL was not found" " on this server.</BODY></HTML>\r\n"; int n; n = send(h->socket, error404, sizeof(error404) - 1, 0); if(n < 0) { syslog(LOG_ERR, "Send404: send(http): %m"); }*/ static const char body404[] = "<HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD>" "<BODY><H1>Not Found</H1>The requested URL was not found" " on this server.</BODY></HTML>\r\n"; h->respflags = FLAG_HTML; BuildResp2_upnphttp(h, 404, "Not Found", body404, sizeof(body404) - 1); SendResp_upnphttp(h); CloseSocket_upnphttp(h); }
void SendRootContainer(struct upnphttp * h) { char * resp; int len; len = asprintf(&resp, "<?xml version='1.0' encoding='UTF-8' ?>\n" "<TiVoContainer>" "<Details>" "<ContentType>x-container/tivo-server</ContentType>" "<SourceFormat>x-container/folder</SourceFormat>" "<TotalDuration>0</TotalDuration>" "<TotalItems>3</TotalItems>" "<Title>%s</Title>" "</Details>" "<ItemStart>0</ItemStart>" "<ItemCount>2</ItemCount>" "<Item>" "<Details>" "<ContentType>x-container/tivo-photos</ContentType>" "<SourceFormat>x-container/folder</SourceFormat>" "<Title>Pictures on %s</Title>" "</Details>" "<Links>" "<Content>" "<Url>/TiVoConnect?Command=QueryContainer&Container=3</Url>" "</Content>" "</Links>" "</Item>" "<Item>" "<Details>" "<ContentType>x-container/tivo-music</ContentType>" "<SourceFormat>x-container/folder</SourceFormat>" "<Title>Music on %s</Title>" "</Details>" "<Links>" "<Content>" "<Url>/TiVoConnect?Command=QueryContainer&Container=1</Url>" "</Content>" "</Links>" "</Item>" "<Item>" "<Details>" "<ContentType>x-container/tivo-videos</ContentType>" "<SourceFormat>x-container/folder</SourceFormat>" "<Title>Videos on %s</Title>" "</Details>" "<Links>" "<Content>" "<Url>/TiVoConnect?Command=QueryContainer&Container=2</Url>" "<ContentType>x-container/tivo-videos</ContentType>" "</Content>" "</Links>" "</Item>" "</TiVoContainer>", friendly_name, friendly_name, friendly_name, friendly_name); BuildResp_upnphttp(h, resp, len); free(resp); SendResp_upnphttp(h); }
static void ProcessHTTPUnSubscribe_upnphttp(struct upnphttp * h, const char * path) { syslog(LOG_DEBUG, "ProcessHTTPUnSubscribe %s", path); syslog(LOG_DEBUG, "SID '%.*s'", 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); } SendResp_upnphttp(h); CloseSocket_upnphttp(h); }
static void sendDummyDesc(struct upnphttp * h) { static const char xml_desc[] = "<?xml version=\"1.0\"?>\r\n" "<scpd xmlns=\"urn:schemas-upnp-org:service-1-0\">" " <specVersion>" " <major>1</major>" " <minor>0</minor>" " </specVersion>" " <actionList />" " <serviceStateTable />" "</scpd>\r\n"; BuildResp_upnphttp(h, xml_desc, sizeof(xml_desc)-1); SendResp_upnphttp(h); CloseSocket_upnphttp(h); }
/* ProcessHTTPPOST_upnphttp() * executes the SOAP query if it is possible */ static void 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 */ syslog(LOG_INFO, "SOAPAction: %.*s", h->req_soapActionLen, h->req_buf + h->req_soapActionOff); ExecuteSoapAction(h, h->req_buf + h->req_soapActionOff, h->req_soapActionLen); } else { static const char err400str[] = "<html><body>Bad request</body></html>"; syslog(LOG_INFO, "No SOAPAction in HTTP headers"); h->respflags = FLAG_HTML; BuildResp2_upnphttp(h, 400, "Bad Request", err400str, sizeof(err400str) - 1); 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 */ h->state = EWaitingForHttpContent; } }
/* Sends the description generated by the parameter */ static void sendXMLdesc(struct upnphttp * h, char * (f)(int *)) { char * desc; int len; desc = f(&len); if(!desc) { static const char error500[] = "<HTML><HEAD><TITLE>Error 500</TITLE>" "</HEAD><BODY>Internal Server Error</BODY></HTML>\r\n"; syslog(LOG_ERR, "Failed to generate XML description"); h->respflags = FLAG_HTML; BuildResp2_upnphttp(h, 500, "Internal Server Error", error500, sizeof(error500)-1); } else { BuildResp_upnphttp(h, desc, len); } SendResp_upnphttp(h); CloseSocket_upnphttp(h); free(desc); }
void Process_upnphttp(struct upnphttp * h) { char * h_tmp; char buf[2048]; int n; if(!h) return; switch(h->state) { case EWaitingForHttpRequest: #ifdef ENABLE_HTTPS if(h->ssl) { n = SSL_read(h->ssl, buf, sizeof(buf)); } else { n = recv(h->socket, buf, sizeof(buf), 0); } #else n = recv(h->socket, buf, sizeof(buf), 0); #endif if(n<0) { #ifdef ENABLE_HTTPS if(h->ssl) { int err; err = SSL_get_error(h->ssl, n); if(err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) { syslog(LOG_ERR, "SSL_read() failed"); syslogsslerr(); h->state = EToDelete; } } else { #endif if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) { syslog(LOG_ERR, "recv (state0): %m"); h->state = EToDelete; } /* if errno is EAGAIN, EWOULDBLOCK or EINTR, try again later */ #ifdef ENABLE_HTTPS } #endif } else if(n==0) { syslog(LOG_WARNING, "HTTP Connection closed unexpectedly"); h->state = EToDelete; } else { const char * endheaders; /* if 1st arg of realloc() is null, * realloc behaves the same as malloc() */ h_tmp = (char *)realloc(h->req_buf, n + h->req_buflen + 1); if (h_tmp == NULL) { syslog(LOG_WARNING, "Unable to allocate new memory for h->req_buf)"); h->state = EToDelete; } else { h->req_buf = h_tmp; memcpy(h->req_buf + h->req_buflen, buf, n); h->req_buflen += n; h->req_buf[h->req_buflen] = '\0'; } /* search for the string "\r\n\r\n" */ endheaders = findendheaders(h->req_buf, h->req_buflen); if(endheaders) { /* at this point, the request buffer (h->req_buf) * is guaranteed to contain the \r\n\r\n character sequence */ h->req_contentoff = endheaders - h->req_buf + 4; ProcessHttpQuery_upnphttp(h); } } break; case EWaitingForHttpContent: #ifdef ENABLE_HTTPS if(h->ssl) { n = SSL_read(h->ssl, buf, sizeof(buf)); } else { n = recv(h->socket, buf, sizeof(buf), 0); } #else n = recv(h->socket, buf, sizeof(buf), 0); #endif if(n<0) { #ifdef ENABLE_HTTPS if(h->ssl) { int err; err = SSL_get_error(h->ssl, n); if(err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE) { syslog(LOG_ERR, "SSL_read() failed"); syslogsslerr(); h->state = EToDelete; } } else { #endif if(errno != EAGAIN && errno != EWOULDBLOCK && errno != EINTR) { syslog(LOG_ERR, "recv (state1): %m"); h->state = EToDelete; } /* if errno is EAGAIN, EWOULDBLOCK or EINTR, try again later */ #ifdef ENABLE_HTTPS } #endif } else if(n==0) { syslog(LOG_WARNING, "HTTP Connection closed inexpectedly"); h->state = EToDelete; } else { void * tmp = realloc(h->req_buf, n + h->req_buflen); if(!tmp) { syslog(LOG_ERR, "memory allocation error %m"); h->state = EToDelete; } else { h->req_buf = tmp; memcpy(h->req_buf + h->req_buflen, buf, n); h->req_buflen += n; if((h->req_buflen - h->req_contentoff) >= h->req_contentlen) { ProcessHTTPPOST_upnphttp(h); } } } break; case ESendingContinue: if(SendResp_upnphttp(h)) h->state = EWaitingForHttpContent; break; case ESendingAndClosing: SendRespAndClose_upnphttp(h); break; default: syslog(LOG_WARNING, "Unexpected state: %d", h->state); } }