NPT_Result SetupResponse(NPT_HttpRequest& /*request*/, const NPT_HttpRequestContext& /*context*/, NPT_HttpResponse& response) { NPT_HttpEntity* entity = response.GetEntity(); entity->SetContentType("text/html"); return NPT_SUCCESS; }
NPT_Result SetupResponse(NPT_HttpRequest& /*request*/, const NPT_HttpRequestContext& /*context*/, NPT_HttpResponse& response) { NPT_HttpEntity* entity = response.GetEntity(); entity->SetContentType("text/html"); entity->SetTransferEncoding("chunked"); response.SetProtocol(NPT_HTTP_PROTOCOL_1_1); return NPT_SUCCESS; }
NPT_Result SetupResponse(NPT_HttpRequest& /*request*/, const NPT_HttpRequestContext& /*context*/, NPT_HttpResponse& response) { NPT_HttpEntity* entity = response.GetEntity(); entity->SetContentType("text/html"); entity->SetInputStream("<html><body>Bye Bye!</body></html>"); KillRequest = true; return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | CUPnPRenderer::ProcessHttpRequest +---------------------------------------------------------------------*/ NPT_Result CUPnPRenderer::ProcessHttpGetRequest(NPT_HttpRequest& request, const NPT_HttpRequestContext& context, NPT_HttpResponse& response) { // get the address of who sent us some data back NPT_String ip_address = context.GetRemoteAddress().GetIpAddress().ToString(); NPT_String method = request.GetMethod(); NPT_String protocol = request.GetProtocol(); NPT_HttpUrl url = request.GetUrl(); if (url.GetPath() == "/thumb") { NPT_HttpUrlQuery query(url.GetQuery()); NPT_String filepath = query.GetField("path"); if (!filepath.IsEmpty()) { NPT_HttpEntity* entity = response.GetEntity(); if (entity == NULL) return NPT_ERROR_INVALID_STATE; // check the method if (request.GetMethod() != NPT_HTTP_METHOD_GET && request.GetMethod() != NPT_HTTP_METHOD_HEAD) { response.SetStatus(405, "Method Not Allowed"); return NPT_SUCCESS; } // prevent hackers from accessing files outside of our root if ((filepath.Find("/..") >= 0) || (filepath.Find("\\..") >=0)) { return NPT_FAILURE; } #if 1 std::string path; //url #else // open the file CStdString path = CURL::Decode((const char*) filepath); #endif NPT_File file(path.c_str()); NPT_Result result = file.Open(NPT_FILE_OPEN_MODE_READ); if (NPT_FAILED(result)) { response.SetStatus(404, "Not Found"); return NPT_SUCCESS; } NPT_InputStreamReference stream; file.GetInputStream(stream); entity->SetContentType(GetMimeType(filepath)); entity->SetInputStream(stream, true); return NPT_SUCCESS; } } return PLT_MediaRenderer::ProcessHttpGetRequest(request, context, response); }
/*---------------------------------------------------------------------- | NPT_HttpLoggerConfigurator::SetupResponse +---------------------------------------------------------------------*/ NPT_Result NPT_HttpLoggerConfigurator::SetupResponse(NPT_HttpRequest& request, const NPT_HttpRequestContext& /*context*/, NPT_HttpResponse& response) { // we only support GET here if (request.GetMethod() != NPT_HTTP_METHOD_GET) return NPT_ERROR_HTTP_METHOD_NOT_SUPPORTED; // construct the response message NPT_String msg; msg = "<ul>"; NPT_List<NPT_LogConfigEntry>& config = LogManager.GetConfig(); NPT_List<NPT_LogConfigEntry>::Iterator cit = config.GetFirstItem(); for (; cit; ++cit) { NPT_LogConfigEntry& entry = (*cit); msg += "<li>"; msg += entry.m_Key; msg += "="; msg += entry.m_Value; msg += "</li>"; } msg += "</ul>"; msg += "<ul>"; NPT_List<NPT_Logger*>& loggers = LogManager.GetLoggers(); NPT_List<NPT_Logger*>::Iterator lit = loggers.GetFirstItem(); for (;lit;++lit) { NPT_Logger* logger = (*lit); msg += "<li>"; msg += logger->GetName(); msg += ", level="; msg += NPT_String::FromInteger(logger->GetLevel()); NPT_List<NPT_LogHandler*>& handlers = logger->GetHandlers(); NPT_List<NPT_LogHandler*>::Iterator hit = handlers.GetFirstItem(); msg += ", handlers="; for (;hit;++hit) { NPT_LogHandler* handler = (*hit); msg += handler->ToString(); } msg += "</li>"; } msg += "</ul>"; // setup the response body NPT_HttpEntity* entity = response.GetEntity(); entity->SetContentType("text/html"); entity->SetInputStream(msg); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_HttpServerSocketTask::RespondToClient +---------------------------------------------------------------------*/ NPT_Result PLT_HttpServerSocketTask::RespondToClient(NPT_HttpRequest& request, const NPT_HttpRequestContext& context, NPT_HttpResponse*& response) { NPT_Result result = NPT_ERROR_NO_SUCH_ITEM; // reset output params first response = NULL; // prepare the response body NPT_HttpEntity* body = new NPT_HttpEntity(); response = new NPT_HttpResponse(200, "OK", NPT_HTTP_PROTOCOL_1_1); response->SetEntity(body); // ask to setup the response result = SetupResponse(request, context, *response); // handle result if (result == NPT_ERROR_NO_SUCH_ITEM) { body->SetInputStream(PLT_HTTP_DEFAULT_404_HTML); body->SetContentType("text/html"); response->SetStatus(404, "Not Found"); } else if (result == NPT_ERROR_PERMISSION_DENIED) { body->SetInputStream(PLT_HTTP_DEFAULT_403_HTML); body->SetContentType("text/html"); response->SetStatus(403, "Forbidden"); } else if (result == NPT_ERROR_TERMINATED) { // mark that we want to exit delete response; response = NULL; } else if (NPT_FAILED(result)) { body->SetInputStream(PLT_HTTP_DEFAULT_500_HTML); body->SetContentType("text/html"); response->SetStatus(500, "Internal Error"); } return NPT_SUCCESS; }
// NPT_HttpRequetsHandler methods virtual NPT_Result SetupResponse(NPT_HttpRequest& request, const NPT_HttpRequestContext& context, NPT_HttpResponse& response) { NPT_COMPILER_UNUSED(request); NPT_COMPILER_UNUSED(context); NPT_HttpEntity* entity = response.GetEntity(); if (entity == NULL) return NPT_ERROR_INVALID_STATE; entity->SetContentType(m_MimeType); entity->SetInputStream(m_Body); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_MediaConnect::ProcessGetSCPD +---------------------------------------------------------------------*/ NPT_Result PLT_MediaConnect::ProcessGetSCPD(PLT_Service* service, NPT_HttpRequest& request, const NPT_HttpRequestContext& context, NPT_HttpResponse& response) { PLT_DeviceSignature signature = PLT_HttpHelper::GetDeviceSignature(request); // Override SCPD response by providing an SCPD without a Search action // to all devices except XBox or WMP which need it if (service->GetServiceType() == "urn:schemas-upnp-org:service:ContentDirectory:1" && signature != PLT_DEVICE_XBOX && signature != PLT_DEVICE_WMP && signature != PLT_DEVICE_SONOS) { NPT_HttpEntity* entity; PLT_HttpHelper::SetBody(response, (const char*) MS_ContentDirectorySCPD, &entity); entity->SetContentType("text/xml; charset=\"utf-8\""); return NPT_SUCCESS; } return PLT_MediaServer::ProcessGetSCPD(service, request, context, response); }
NPT_Result SetupResponse(NPT_HttpRequest& request, NPT_HttpResponse& response, NPT_SocketInfo& /*info*/) { NPT_String msg = "<HTML>"; msg += "PATH="; msg += request.GetUrl().GetPath(); msg += " <P><UL>"; if (request.GetUrl().HasQuery()) { NPT_HttpUrlQuery query(request.GetUrl().GetQuery()); for (NPT_List<NPT_HttpUrlQuery::Field>::Iterator it = query.GetFields().GetFirstItem(); it; ++it) { NPT_HttpUrlQuery::Field& field = *it; msg += "<LI>"; msg += field.m_Name; msg += " = "; msg += field.m_Value; msg += " </LI>"; } } msg += "</UL></HTML>"; if (request.GetMethod() == NPT_HTTP_METHOD_POST) { NPT_DataBuffer request_body; request.GetEntity()->Load(request_body); NPT_Debug("REQUEST: body = %d bytes\n", request_body.GetDataSize()); NPT_Debug("REQUEST: content type = %s\n", request.GetEntity()->GetContentType().GetChars()); if (request.GetEntity()->GetContentType().StartsWith("text") || request.GetEntity()->GetContentType() == "application/x-www-form-urlencoded") { NPT_String body_string; body_string.Assign((char*)request_body.GetData(), request_body.GetDataSize()); NPT_Debug("%s", body_string.GetChars()); } } NPT_HttpEntity* entity = response.GetEntity(); entity->SetContentType("text/html"); entity->SetInputStream(msg); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_HttpStreamRequestHandler::SetupResponse +---------------------------------------------------------------------*/ NPT_Result PLT_HttpStreamRequestHandler::SetupResponse(NPT_HttpRequest& request, const NPT_HttpRequestContext& context, NPT_HttpResponse& response) { PLT_LOG_HTTP_REQUEST(NPT_LOG_LEVEL_FINE, "PLT_HttpStreamRequestHandler::SetupResponse:", &request); if (request.GetMethod().Compare("GET") && request.GetMethod().Compare("HEAD")) { return NPT_FAILURE; } NPT_Reference<PLT_FrameBuffer> buffer; if (!m_StreamValidator.OnNewRequestAccept(request, context, response, buffer)) { return NPT_ERROR_NO_SUCH_ITEM; } response.SetProtocol(NPT_HTTP_PROTOCOL_1_0); response.GetHeaders().SetHeader(NPT_HTTP_HEADER_CONNECTION, "close"); response.GetHeaders().SetHeader("Cache-Control", "no-store, no-cache, must-revalidate, pre-check=0, post-check=0, max-age=0"); response.GetHeaders().SetHeader("Pragma", "no-cache"); response.GetHeaders().SetHeader("Expires", "Tue, 4 Jan 2000 02:43:05 GMT"); // HEAD request has no entity or if status code is not 2xx if (!request.GetMethod().Compare("HEAD") || response.GetStatusCode()/100 != 2) return NPT_SUCCESS; NPT_HttpEntity* entity = response.GetEntity(); NPT_CHECK_POINTER_FATAL(entity); entity->SetContentType("multipart/x-mixed-replace;boundary=" BOUNDARY); NPT_InputStreamReference body(new PLT_InputFrameStream(buffer, BOUNDARY)); entity->SetInputStream(body, false); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_HttpServer::ServeStream +---------------------------------------------------------------------*/ NPT_Result PLT_HttpServer::ServeStream(const NPT_HttpRequest& request, const NPT_HttpRequestContext& context, NPT_HttpResponse& response, NPT_InputStreamReference& body, const char* content_type) { if (body.IsNull()) return NPT_FAILURE; // set date NPT_TimeStamp now; NPT_System::GetCurrentTimeStamp(now); response.GetHeaders().SetHeader("Date", NPT_DateTime(now).ToString(NPT_DateTime::FORMAT_RFC_1123), true); // get entity NPT_HttpEntity* entity = response.GetEntity(); NPT_CHECK_POINTER_FATAL(entity); // set the content type entity->SetContentType(content_type); // check for range requests const NPT_String* range_spec = request.GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_RANGE); // setup entity body NPT_CHECK(NPT_HttpFileRequestHandler::SetupResponseBody(response, body, range_spec)); // set some default headers if (response.GetEntity()->GetTransferEncoding() != NPT_HTTP_TRANSFER_ENCODING_CHUNKED) { // set but don't replace Accept-Range header only if body is seekable NPT_Position offset; if (NPT_SUCCEEDED(body->Tell(offset)) && NPT_SUCCEEDED(body->Seek(offset))) { response.GetHeaders().SetHeader(NPT_HTTP_HEADER_ACCEPT_RANGES, "bytes", false); } } // set getcontentFeatures.dlna.org const NPT_String* value = request.GetHeaders().GetHeaderValue("getcontentFeatures.dlna.org"); if (value) { PLT_HttpRequestContext tmp_context(request, context); const char* dlna = PLT_ProtocolInfo::GetDlnaExtension(entity->GetContentType(), &tmp_context); if (dlna) response.GetHeaders().SetHeader("ContentFeatures.DLNA.ORG", dlna, false); } // transferMode.dlna.org value = request.GetHeaders().GetHeaderValue("transferMode.dlna.org"); if (value) { // Interactive mode not supported? /*if (value->Compare("Interactive", true) == 0) { response.SetStatus(406, "Not Acceptable"); return NPT_SUCCESS; }*/ response.GetHeaders().SetHeader("TransferMode.DLNA.ORG", value->GetChars(), false); } else { response.GetHeaders().SetHeader("TransferMode.DLNA.ORG", "Streaming", false); } if (request.GetHeaders().GetHeaderValue("TimeSeekRange.dlna.org")) { response.SetStatus(406, "Not Acceptable"); return NPT_SUCCESS; } return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | BtPlayerServer::SetupResponse +---------------------------------------------------------------------*/ NPT_Result BtPlayerServer::SetupResponse(NPT_HttpRequest& request, const NPT_HttpRequestContext& /*context*/, NPT_HttpResponse& response) { const NPT_Url& url = request.GetUrl(); const NPT_String& path = url.GetPath(); NPT_UrlQuery query; // parse the query part, if any if (url.HasQuery()) { query.Parse(url.GetQuery()); } // lock the player NPT_AutoLock lock(m_Lock); // handle form requests if (path == "/") { response.GetHeaders().SetHeader("Location", "/control/ajax"); response.SetStatus(301, "Moved Permanently"); return BLT_SUCCESS; } // handle form requests if (path == "/control/form") { return SendControlForm(response, NULL); } // handle status requests if (path == "/player/status") { return SendStatus(response, query); } // handle commands const char* mode_field = query.GetField("mode"); const char* form_msg = "OK"; bool use_form = false; if (mode_field && NPT_StringsEqual(mode_field, "form")) { use_form = true; } if (path == "/player/set-input") { const char* name_field = query.GetField("name"); if (name_field) { NPT_String name = NPT_UrlQuery::UrlDecode(name_field); m_Player.SetInput(name); } else { form_msg = "INVALID PARAMETERS"; } } else if (path == "/player/set-output") { const char* name_field = query.GetField("name"); if (name_field) { NPT_String name = NPT_UrlQuery::UrlDecode(name_field); m_Player.SetOutput(name); } else { form_msg = "INVALID PARAMETERS"; } } else if (path == "/player/play") { m_Player.Play(); } else if (path == "/player/pause") { m_Player.Pause(); } else if (path == "/player/stop") { m_Player.Stop(); } else if (path == "/player/seek") { const char* timecode_field = query.GetField("timecode"); const char* position_field = query.GetField("position"); if (timecode_field) { NPT_String timecode = NPT_UrlQuery::UrlDecode(timecode_field); DoSeekToTimecode(timecode); } else if (position_field) { unsigned int position; if (NPT_SUCCEEDED(NPT_ParseInteger(position_field, position))) { m_Player.SeekToPosition(position, 100); } } else { form_msg = "INVALID PARAMETER"; } } else if (path == "/player/set-volume") { const char* volume_field = query.GetField("volume"); if (volume_field) { unsigned int volume; if (NPT_SUCCEEDED(NPT_ParseInteger(volume_field, volume))) { m_Player.SetVolume((float)volume/100.0f); } } else { form_msg = "INVALID PARAMETER"; } } if (use_form) { return SendControlForm(response, form_msg); } else { NPT_HttpEntity* entity = response.GetEntity(); entity->SetContentType("application/json"); entity->SetInputStream("{}"); return NPT_SUCCESS; } printf("BtPlayerServer::SetupResponse - command not found\n"); response.SetStatus(404, "Command Not Found"); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | BtPlayerServer::SendControlForm +---------------------------------------------------------------------*/ NPT_Result BtPlayerServer::SendControlForm(NPT_HttpResponse& response, const char* msg) { // create the html document NPT_String html = "<html>"; // optional message if (msg && msg[0]) { html += "<"; html += msg; html += "><p>"; } // status html += "<p><b>State: </b>"; switch (m_DecoderState) { case BLT_DecoderServer::STATE_STOPPED: html += "[STOPPED]"; break; case BLT_DecoderServer::STATE_PLAYING: html += "[PLAYING]"; break; case BLT_DecoderServer::STATE_PAUSED: html += "[PAUSED]"; break; case BLT_DecoderServer::STATE_EOS: html += "[END OF STREAM]"; break; default: html += "[UNKNOWN]"; break; } html += "</p><p><b>Time Code: </b>"; html += NPT_String::Format("\"%02d:%02d:%02d\"", m_DecoderTimecode.h, m_DecoderTimecode.m, m_DecoderTimecode.s); html += "</p>"; html += "<p>"; html += "<b>Content Format: </b>"; if (m_StreamInfo.data_type) { html += m_StreamInfo.data_type; } html += "<br>"; // control form html += BT_CONTROL_FORM; html += "</html>"; // send the html document NPT_HttpEntity* entity = response.GetEntity(); entity->SetContentType("text/html"); entity->SetInputStream(html); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | BtPlayerServer::SendStatus +---------------------------------------------------------------------*/ NPT_Result BtPlayerServer::SendStatus(NPT_HttpResponse& response, NPT_UrlQuery& query) { NPT_String json; // json start const char* json_callback = query.GetField("callback"); if (json_callback) { json += NPT_UrlQuery::UrlDecode(json_callback)+'('; } json += '{'; // state json += "\"state\": "; switch (m_DecoderState) { case BLT_DecoderServer::STATE_STOPPED: json += "\"STOPPED\""; break; case BLT_DecoderServer::STATE_PLAYING: json += "\"PLAYING\""; break; case BLT_DecoderServer::STATE_PAUSED: json += "\"PAUSED\""; break; case BLT_DecoderServer::STATE_EOS: json += "\"END OF STREAM\""; break; default: json += "\"UNKNOWN\""; break; } json += ','; // timecode json += NPT_String::Format("\"timecode\": \"%02d:%02d:%02d\", ", m_DecoderTimecode.h, m_DecoderTimecode.m, m_DecoderTimecode.s); // position json += NPT_String::Format("\"position\": %f, ", m_DecoderPosition); // stream info json += "\"streamInfo\": {"; if (m_StreamInfo.mask & BLT_STREAM_INFO_MASK_NOMINAL_BITRATE) { json += NPT_String::Format("\"nominalBitrate\": %d, ", m_StreamInfo.nominal_bitrate); } if (m_StreamInfo.mask & BLT_STREAM_INFO_MASK_AVERAGE_BITRATE) { json += NPT_String::Format("\"averageBitrate\": %d, ", m_StreamInfo.average_bitrate); } if (m_StreamInfo.mask & BLT_STREAM_INFO_MASK_INSTANT_BITRATE) { json += NPT_String::Format("\"instantBitrate\": %d, ", m_StreamInfo.instant_bitrate); } if (m_StreamInfo.mask & BLT_STREAM_INFO_MASK_SIZE) { json += NPT_String::Format("\"size\": %d, ", m_StreamInfo.size); } if (m_StreamInfo.mask & BLT_STREAM_INFO_MASK_DURATION) { unsigned int seconds = m_StreamInfo.duration/1000; json += NPT_String::Format("\"duration\": \"%02d:%02d:%02d\", ", (seconds)/36000, (seconds%3600)/60, (seconds%60)); } if (m_StreamInfo.mask & BLT_STREAM_INFO_MASK_SAMPLE_RATE) { json += NPT_String::Format("\"sampleRate\": %d, ", m_StreamInfo.sample_rate); } if (m_StreamInfo.mask & BLT_STREAM_INFO_MASK_CHANNEL_COUNT) { json += NPT_String::Format("\"channelCount\": %d, ", m_StreamInfo.channel_count); } if (m_StreamInfo.mask & BLT_STREAM_INFO_MASK_DATA_TYPE) { json += NPT_String::Format("\"dataType\": \"%s\", ", m_StreamInfo.data_type); } json += "},"; // stream properties // json end json += '}'; if (json_callback) { json += ')'; } // send the html document NPT_HttpEntity* entity = response.GetEntity(); entity->SetContentType("application/json"); entity->SetInputStream(json); NPT_LOG_FINE_1("status: %s", json.GetChars()); return NPT_SUCCESS; }
NPT_Result SetupResponse(NPT_HttpRequest& request, const NPT_HttpRequestContext& context, NPT_HttpResponse& response) { NPT_String msg = "<HTML>"; msg += "PATH="; msg += request.GetUrl().GetPath(); msg += "<P><B>Local Address:</B> "; msg += context.GetLocalAddress().ToString(); msg += "<P>"; msg += "<B>Remote Address:</B> "; msg += context.GetRemoteAddress().ToString(); msg += "<P><UL>"; if (request.GetUrl().HasQuery()) { NPT_UrlQuery query(request.GetUrl().GetQuery()); for (NPT_List<NPT_UrlQuery::Field>::Iterator it = query.GetFields().GetFirstItem(); it; ++it) { NPT_UrlQuery::Field& field = *it; msg += "<LI>"; msg += field.m_Name; msg += " = "; msg += field.m_Value; msg += " </LI>"; // check for a 'delay' field if (field.m_Name == "delay") { NPT_UInt32 delay = 0; field.m_Value.ToInteger(delay); NPT_Debug("DELAY: %d seconds\n", delay); NPT_System::Sleep(NPT_TimeInterval((float)delay)); } } } msg += "</UL></HTML>"; if (request.GetMethod() == NPT_HTTP_METHOD_POST) { NPT_DataBuffer request_body; request.GetEntity()->Load(request_body); NPT_Debug("REQUEST: body = %d bytes\n", request_body.GetDataSize()); NPT_Debug("REQUEST: content type = %s\n", request.GetEntity()->GetContentType().GetChars()); if (request.GetEntity()->GetContentType().StartsWith("text") || request.GetEntity()->GetContentType() == "application/x-www-form-urlencoded") { NPT_String body_string; body_string.Assign((char*)request_body.GetData(), request_body.GetDataSize()); NPT_Debug("%s", body_string.GetChars()); } } NPT_HttpEntity* entity = response.GetEntity(); entity->SetContentType("text/html"); NPT_MemoryStreamReference memory_stream( new NPT_MemoryStream((const void*)msg.GetChars(), msg.GetLength())); entity->SetInputStream(memory_stream, !m_Chunked); if (m_Chunked) { entity->SetTransferEncoding(NPT_HTTP_TRANSFER_ENCODING_CHUNKED); } return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_EventSubscriber::Notify +---------------------------------------------------------------------*/ NPT_Result PLT_EventSubscriber::Notify(NPT_List<PLT_StateVariable*>& vars) { // verify we have eventable variables bool foundVars = false; NPT_XmlElementNode* propertyset = new NPT_XmlElementNode("e", "propertyset"); NPT_CHECK_SEVERE(propertyset->SetNamespaceUri( "e", "urn:schemas-upnp-org:event-1-0")); NPT_List<PLT_StateVariable*>::Iterator var = vars.GetFirstItem(); while (var) { if ((*var)->IsSendingEvents()) { NPT_XmlElementNode* property = new NPT_XmlElementNode("e", "property"); propertyset->AddChild(property); PLT_XmlHelper::AddChildText(property, (*var)->GetName(), (*var)->GetValue()); foundVars = true; } ++var; } // no eventable state variables found! if (foundVars == false) { delete propertyset; return NPT_FAILURE; } // format the body with the xml NPT_String xml; if (NPT_FAILED(PLT_XmlHelper::Serialize(*propertyset, xml))) { delete propertyset; NPT_CHECK_FATAL(NPT_FAILURE); } delete propertyset; // parse the callback url NPT_HttpUrl url(m_CallbackURLs[0]); if (!url.IsValid()) { NPT_CHECK_FATAL(NPT_FAILURE); } // format request NPT_HttpRequest* request = new NPT_HttpRequest(url, "NOTIFY", NPT_HTTP_PROTOCOL_1_1); NPT_HttpEntity* entity; PLT_HttpHelper::SetBody(*request, xml, &entity); // add the extra headers entity->SetContentType("text/xml; charset=\"utf-8\""); PLT_UPnPMessageHelper::SetNT(*request, "upnp:event"); PLT_UPnPMessageHelper::SetNTS(*request, "upnp:propchange"); PLT_UPnPMessageHelper::SetSID(*request, m_SID); PLT_UPnPMessageHelper::SetSeq(*request, m_EventKey); // wrap around sequence to 1 if (++m_EventKey == 0) m_EventKey = 1; // start the task now if not started already if (!m_SubscriberTask) { // TODO: the subscriber task should inform subscriber if // a notification failed to be received so it can be removed // from the list of subscribers inside the device host m_SubscriberTask = new PLT_HttpClientSocketTask(request, true); // short connection time out in case subscriber is not alive NPT_HttpClient::Config config; config.m_ConnectionTimeout = 2000; m_SubscriberTask->SetHttpClientConfig(config); // add initial delay to make sure ctrlpoint receives response to subscription // before our first NOTIFY. Also make sure task is not auto-destroy // since we want to destroy it manually when the subscriber goes away. NPT_TimeInterval delay(0.05f); NPT_CHECK_FATAL(m_TaskManager->StartTask(m_SubscriberTask, NULL /*&delay*/, false)); } else { m_SubscriberTask->AddRequest(request); } return NPT_SUCCESS; }