/*---------------------------------------------------------------------- | PLT_HttpClient::WaitForResponse +---------------------------------------------------------------------*/ NPT_Result PLT_HttpClient::WaitForResponse(NPT_InputStreamReference& input_stream, NPT_HttpRequest& request, NPT_SocketInfo& info, NPT_HttpResponse*& response) { NPT_COMPILER_UNUSED(info); // create a buffered stream for this connection stream NPT_BufferedInputStreamReference buffered_input_stream(new NPT_BufferedInputStream(input_stream)); // parse the response NPT_CHECK(NPT_HttpResponse::Parse(*buffered_input_stream, response)); // unbuffer the stream buffered_input_stream->SetBufferSize(0); // create an entity if one is expected in the response if (request.GetMethod() == NPT_HTTP_METHOD_GET || request.GetMethod() == NPT_HTTP_METHOD_POST) { NPT_HttpEntity* response_entity = new NPT_HttpEntity(response->GetHeaders()); // Transfer-Encoding: chunked ? if (response_entity->GetTransferEncoding() == "chunked") { NPT_InputStreamReference body_stream(new NPT_HttpChunkedDecoderInputStream(buffered_input_stream)); response_entity->SetInputStream((NPT_InputStreamReference)body_stream); } else { response_entity->SetInputStream((NPT_InputStreamReference)buffered_input_stream); } response->SetEntity(response_entity); } return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_HttpHelper::GetDeviceSignature +---------------------------------------------------------------------*/ PLT_DeviceSignature PLT_HttpHelper::GetDeviceSignature(const NPT_HttpRequest& request) { const NPT_String* agent = request.GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_USER_AGENT); const NPT_String* hdr = request.GetHeaders().GetHeaderValue("X-AV-Client-Info"); const NPT_String* server = request.GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_SERVER); if ((agent && (agent->Find("XBox", 0, true) >= 0 || agent->Find("Xenon", 0, true) >= 0)) || (server && server->Find("Xbox", 0, true) >= 0)) { return PLT_DEVICE_XBOX; } else if (agent && (agent->Find("Windows Media Player", 0, true) >= 0 || agent->Find("Windows-Media-Player", 0, true) >= 0 || agent->Find("Mozilla/4.0", 0, true) >= 0 || agent->Find("WMFSDK", 0, true) >= 0)) { return PLT_DEVICE_WMP; } else if (agent && (agent->Find("Sonos", 0, true) >= 0)) { return PLT_DEVICE_SONOS; } else if ((agent && agent->Find("PLAYSTATION 3", 0, true) >= 0) || (hdr && hdr->Find("PLAYSTATION 3", 0, true) >= 0)) { return PLT_DEVICE_PS3; } else if (agent && agent->Find("Windows", 0, true) >= 0) { return PLT_DEVICE_WINDOWS; } else if (agent && (agent->Find("Mac", 0, true) >= 0 || agent->Find("OS X", 0, true) >= 0 || agent->Find("OSX", 0, true) >= 0)) { return PLT_DEVICE_MAC; } else { NPT_LOG_FINE_1("Unknown device signature (ua=%s)", agent?agent->GetChars():"none"); } return PLT_DEVICE_UNKNOWN; }
/*---------------------------------------------------------------------- | PLT_SsdpSender::SendSsdp +---------------------------------------------------------------------*/ NPT_Result PLT_SsdpSender::SendSsdp(NPT_HttpRequest& request, const char* usn, const char* target, NPT_UdpSocket& socket, bool notify, const NPT_SocketAddress* addr /* = NULL */) { NPT_CHECK_SEVERE(FormatPacket(request, usn, target, socket, notify)); // logging NPT_String prefix = NPT_String::Format("Sending SSDP %s packet for %s", (const char*)request.GetMethod(), usn); PLT_LOG_HTTP_MESSAGE(NPT_LOG_LEVEL_FINER, prefix, &request); // use a memory stream to write all the data NPT_MemoryStream stream; NPT_Result res = request.Emit(stream); NPT_CHECK(res); // copy stream into a data packet and send it NPT_LargeSize size; stream.GetSize(size); if (size != (NPT_Size)size) NPT_CHECK(NPT_ERROR_OUT_OF_RANGE); NPT_DataBuffer packet(stream.GetData(), (NPT_Size)size); NPT_CHECK_WARNING(socket.Send(packet, addr)); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | CMediaCrawler::ProcessFileRequest +---------------------------------------------------------------------*/ NPT_Result CMediaCrawler::ProcessFileRequest(NPT_HttpRequest& request, NPT_HttpResponse& response, NPT_SocketInfo& info) { NPT_COMPILER_UNUSED(info); NPT_LOG_FINE("CMediaCrawler::ProcessFileRequest Received Request:"); PLT_LOG_HTTP_MESSAGE(NPT_LOG_LEVEL_FINE, &request); if (request.GetMethod().Compare("GET") && request.GetMethod().Compare("HEAD")) { response.SetStatus(500, "Internal Server Error"); return NPT_SUCCESS; } // add the user agent header, some stupid media servers like YME needs it if (!request.GetHeaders().GetHeader(NPT_HTTP_HEADER_USER_AGENT)) { request.GetHeaders().SetHeader(NPT_HTTP_HEADER_USER_AGENT, "Platinum/" PLT_PLATINUM_VERSION_STRING); } // File requested NPT_HttpResponse* out_response = NULL; NPT_HttpUrlQuery query(request.GetUrl().GetQuery()); const char* url = query.GetField("url"); if (url) { // look for handler CStreamHandler* handler = NULL; NPT_ContainerFind(m_StreamHandlers, CStreamHandlerFinder(NULL, url), handler); if (handler && NPT_SUCCEEDED(handler->ProcessFileRequest(request, out_response)) && out_response) { // copy response code and reason response.SetStatus(out_response->GetStatusCode(), out_response->GetReasonPhrase()); // copy headers NPT_List<NPT_HttpHeader*>::Iterator headers = out_response->GetHeaders().GetHeaders().GetFirstItem(); while (headers) { response.GetHeaders().SetHeader((*headers)->GetName(), (*headers)->GetValue()); ++headers; } response.SetEntity(new NPT_HttpEntity(response.GetHeaders())); // update inputstream NPT_HttpEntity* out_entity; if ((out_entity = out_response->GetEntity()) != NULL) { NPT_InputStreamReference inputstream; out_entity->GetInputStream(inputstream); if (!inputstream.IsNull()) { // set the stream but do not update the content length response.GetEntity()->SetInputStream(inputstream, false); } } delete out_response; return NPT_SUCCESS; } } response.SetStatus(404, "File Not Found"); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_HttpServer::ServeFile +---------------------------------------------------------------------*/ NPT_Result PLT_HttpServer::ServeFile(const NPT_HttpRequest& request, const NPT_HttpRequestContext& context, NPT_HttpResponse& response, NPT_String file_path) { NPT_InputStreamReference stream; NPT_File file(file_path); NPT_FileInfo file_info; // prevent hackers from accessing files outside of our root if ((file_path.Find("/..") >= 0) || (file_path.Find("\\..") >= 0) || NPT_FAILED(NPT_File::GetInfo(file_path, &file_info))) { return NPT_ERROR_NO_SUCH_ITEM; } // check for range requests const NPT_String* range_spec = request.GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_RANGE); // handle potential 304 only if range header not set NPT_DateTime date; NPT_TimeStamp timestamp; if (NPT_SUCCEEDED(PLT_UPnPMessageHelper::GetIfModifiedSince((NPT_HttpMessage&)request, date)) && !range_spec) { date.ToTimeStamp(timestamp); NPT_LOG_INFO_5("File %s timestamps: request=%d (%s) vs file=%d (%s)", (const char*)request.GetUrl().GetPath(), (NPT_UInt32)timestamp.ToSeconds(), (const char*)date.ToString(), (NPT_UInt32)file_info.m_ModificationTime, (const char*)NPT_DateTime(file_info.m_ModificationTime).ToString()); if (timestamp >= file_info.m_ModificationTime) { // it's a match NPT_LOG_FINE_1("Returning 304 for %s", request.GetUrl().GetPath().GetChars()); response.SetStatus(304, "Not Modified", NPT_HTTP_PROTOCOL_1_1); return NPT_SUCCESS; } } // open file if (NPT_FAILED(file.Open(NPT_FILE_OPEN_MODE_READ)) || NPT_FAILED(file.GetInputStream(stream)) || stream.IsNull()) { return NPT_ERROR_NO_SUCH_ITEM; } // set Last-Modified and Cache-Control headers if (file_info.m_ModificationTime) { NPT_DateTime last_modified = NPT_DateTime(file_info.m_ModificationTime); response.GetHeaders().SetHeader("Last-Modified", last_modified.ToString(NPT_DateTime::FORMAT_RFC_1123), true); response.GetHeaders().SetHeader("Cache-Control", "max-age=0,must-revalidate", true); //response.GetHeaders().SetHeader("Cache-Control", "max-age=1800", true); } PLT_HttpRequestContext tmp_context(request, context); return ServeStream(request, context, response, stream, PLT_MimeType::GetMimeType(file_path, &tmp_context)); }
/*---------------------------------------------------------------------- | PLT_HttpServerSocketTask::DoRun +---------------------------------------------------------------------*/ void PLT_HttpServerSocketTask::DoRun() { NPT_BufferedInputStreamReference buffered_input_stream; NPT_HttpRequestContext context; NPT_Result res = NPT_SUCCESS; bool headers_only; bool keep_alive = false; // create a buffered input stream to parse HTTP request NPT_InputStreamReference input_stream; NPT_CHECK_LABEL_SEVERE(GetInputStream(input_stream), done); NPT_CHECK_POINTER_LABEL_FATAL(input_stream.AsPointer(), done); buffered_input_stream = new NPT_BufferedInputStream(input_stream); while (!IsAborting(0)) { NPT_HttpRequest* request = NULL; NPT_HttpResponse* response = NULL; // reset keep-alive to exit task on read failure keep_alive = false; // wait for a request res = Read(buffered_input_stream, request, &context); if (NPT_FAILED(res) || (request == NULL)) goto cleanup; // process request and setup response res = RespondToClient(*request, context, response); if (NPT_FAILED(res) || (response == NULL)) goto cleanup; // check if client requested keep-alive keep_alive = PLT_HttpHelper::IsConnectionKeepAlive(*request); headers_only = request->GetMethod() == NPT_HTTP_METHOD_HEAD; // send response, pass keep-alive request from client // (it can be overridden if response handler did not allow it) res = Write(response, keep_alive, headers_only); // on write error, reset keep_alive so we can close this connection if (NPT_FAILED(res)) keep_alive = false; cleanup: // cleanup delete request; delete response; if (!keep_alive && !m_StayAliveForever) { return; } } done: return; }
/*---------------------------------------------------------------------- | PLT_FileMediaServer::ProcessFileRequest +---------------------------------------------------------------------*/ NPT_Result PLT_FileMediaServer::ProcessFileRequest(NPT_HttpRequest& request, NPT_HttpResponse& response, NPT_SocketInfo& client_info) { NPT_COMPILER_UNUSED(client_info); NPT_LOG_FINE("PLT_FileMediaServer::ProcessFileRequest Received Request:"); PLT_LOG_HTTP_MESSAGE(NPT_LOG_LEVEL_FINE, &request); response.GetHeaders().SetHeader("Accept-Ranges", "bytes"); if (request.GetMethod().Compare("GET") && request.GetMethod().Compare("HEAD")) { response.SetStatus(500, "Internal Server Error"); return NPT_SUCCESS; } // File requested NPT_String path = m_FileBaseUri.GetPath(); NPT_String strUri = NPT_Uri::PercentDecode(request.GetUrl().GetPath()); NPT_HttpUrlQuery query(request.GetUrl().GetQuery()); NPT_String file_path = query.GetField("path"); // hack for XBMC support for 360, we urlencoded the ? to that the 360 doesn't strip out the query // but then the query ends being parsed as part of the path int index = strUri.Find("path="); if (index>0) file_path = strUri.Right(strUri.GetLength()-index-5); if (file_path.GetLength() == 0) goto failure; // HACK for wmp: somehow they inverse our slashes ! // do it only if we're on windows if (m_DirDelimiter == "\\") { file_path.Replace('/', '\\'); } if (path.Compare(strUri.Left(path.GetLength()), true) == 0) { NPT_Integer start, end; PLT_HttpHelper::GetRange(&request, start, end); return PLT_FileServer::ServeFile(m_Path + file_path, &response, start, end, !request.GetMethod().Compare("HEAD")); } // Album Art requested path = m_AlbumArtBaseUri.GetPath(); if (path.Compare(strUri.Left(path.GetLength()), true) == 0) { return OnAlbumArtRequest(m_Path + file_path, response); } failure: response.SetStatus(404, "File Not Found"); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_MediaConnect::ProcessGetDescription +---------------------------------------------------------------------*/ NPT_Result PLT_MediaConnect::ProcessGetDescription(NPT_HttpRequest& request, const NPT_HttpRequestContext& context, NPT_HttpResponse& response) { NPT_String m_OldModelName = m_ModelName; NPT_String m_OldModelNumber = m_ModelNumber; NPT_String m_OldModelURL = m_ModelURL; NPT_String m_OldManufacturerURL = m_ManufacturerURL; NPT_String m_OldDlnaDoc = m_DlnaDoc; NPT_String m_OldDlnaCap = m_DlnaCap; NPT_String m_OldAggregationFlags = m_AggregationFlags; // change some things based on User-Agent header NPT_HttpHeader* user_agent = request.GetHeaders().GetHeader(NPT_HTTP_HEADER_USER_AGENT); if (user_agent && user_agent->GetValue().Find("Xbox", 0, true)>=0) { m_ModelName = "Windows Media Connect"; m_ModelNumber = "2.0"; m_ModelURL = "http://www.microsoft.com/"; m_ManufacturerURL = "http://www.microsoft.com/"; m_DlnaDoc = ""; m_DlnaCap = ""; m_AggregationFlags = ""; if (m_FriendlyName.Find(":") == -1) m_FriendlyName += ": 1"; if (!m_FriendlyName.EndsWith(": Windows Media Connect")) m_FriendlyName += ": Windows Media Connect"; } else if (user_agent && user_agent->GetValue().Find("Sonos", 0, true)>=0) { m_ModelName = "Windows Media Player Sharing"; m_ModelNumber = "3.0"; } // PS3 NPT_HttpHeader* client_info = request.GetHeaders().GetHeader("X-AV-Client-Info"); if (client_info && client_info->GetValue().Find("PLAYSTATION 3", 0, true)>=0) { m_DlnaDoc = "DMS-1.50"; m_DlnaCap = "av-upload,image-upload,audio-upload"; m_AggregationFlags = "10"; } NPT_Result res = PLT_FileMediaServer::ProcessGetDescription(request, context, response); // reset to old values now m_ModelName = m_OldModelName; m_ModelNumber = m_OldModelNumber; m_ModelURL = m_OldModelURL; m_ManufacturerURL = m_OldManufacturerURL; m_DlnaDoc = m_OldDlnaDoc; m_DlnaCap = m_OldDlnaCap; m_AggregationFlags = m_OldAggregationFlags; return res; }
/*---------------------------------------------------------------------- | 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); }
/*---------------------------------------------------------------------- | PLT_FileMediaServer::ProcessHttpRequest +---------------------------------------------------------------------*/ NPT_Result PLT_FileMediaServer::ProcessHttpRequest(NPT_HttpRequest& request, const NPT_HttpRequestContext& context, NPT_HttpResponse& response) { if (request.GetUrl().GetPath().StartsWith(m_FileBaseUri.GetPath()) || request.GetUrl().GetPath().StartsWith(m_AlbumArtBaseUri.GetPath())) { return ProcessFileRequest(request, context, response); } return PLT_MediaServer::ProcessHttpRequest(request, context, response); }
/*---------------------------------------------------------------------- | PLT_HttpClient::Connect +---------------------------------------------------------------------*/ NPT_Result PLT_HttpClient::Connect(NPT_Socket* connection, NPT_HttpRequest& request, NPT_Timeout timeout) { // get the address of the server NPT_IpAddress server_address; NPT_CHECK_SEVERE(server_address.ResolveName(request.GetUrl().GetHost(), timeout)); NPT_SocketAddress address(server_address, request.GetUrl().GetPort()); // connect to the server NPT_LOG_FINER_2("Connecting to %s:%d\n", (const char*)request.GetUrl().GetHost(), request.GetUrl().GetPort()); NPT_CHECK_SEVERE(connection->Connect(address, timeout)); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_HttpHelper::GetRange +---------------------------------------------------------------------*/ NPT_Result PLT_HttpHelper::GetRange(const NPT_HttpRequest& request, NPT_Position& start, NPT_Position& end) { start = (NPT_Position)-1; end = (NPT_Position)-1; const NPT_String* range = request.GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_RANGE); NPT_CHECK_POINTER(range); char s[32], e[32]; s[0] = '\0'; e[0] = '\0'; int ret = sscanf(*range, "bytes=%31[^-]-%31s", s, e); if (ret < 1) { return NPT_FAILURE; } if (s[0] != '\0') { NPT_ParseInteger64(s, start); } if (e[0] != '\0') { NPT_ParseInteger64(e, end); } return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_FileMediaServer::ServeFile +---------------------------------------------------------------------*/ NPT_Result PLT_FileMediaServer::ServeFile(NPT_HttpRequest& request, const NPT_HttpRequestContext& context, NPT_HttpResponse& response, const NPT_String& uri_path, const NPT_String& file_path) { NPT_COMPILER_UNUSED(context); // prevent hackers from accessing files outside of our root if ((file_path.Find("/..") >= 0) || (file_path.Find("\\..") >= 0)) { return NPT_FAILURE; } // File requested NPT_String path = m_FileBaseUri.GetPath(); if (path.Compare(uri_path.Left(path.GetLength()), true) == 0) { NPT_Position start, end; PLT_HttpHelper::GetRange(request, start, end); return PLT_FileServer::ServeFile(response, NPT_FilePath::Create(m_Path, file_path), start, end, !request.GetMethod().Compare("HEAD")); } // Album Art requested path = m_AlbumArtBaseUri.GetPath(); if (path.Compare(uri_path.Left(path.GetLength()), true) == 0) { return OnAlbumArtRequest(response, m_Path + file_path); } return NPT_FAILURE; }
/*---------------------------------------------------------------------- | PLT_FileMediaServer::ProcessGetDescription +---------------------------------------------------------------------*/ NPT_Result PLT_FileMediaServer::ProcessGetDescription(NPT_HttpRequest& request, const NPT_HttpRequestContext& context, NPT_HttpResponse& response) { NPT_String m_OldModelName = m_ModelName; NPT_String m_OldModelNumber = m_ModelNumber; // change some things based on User-Agent header NPT_HttpHeader* user_agent = request.GetHeaders().GetHeader(NPT_HTTP_HEADER_USER_AGENT); if (user_agent && user_agent->GetValue().Find("Sonos", 0, true)>=0) { // Force "Rhapsody" so that Sonos is happy to find us m_ModelName = "Rhapsody"; m_ModelNumber = "3.0"; // return modified description NPT_String doc; NPT_Result res = GetDescription(doc); // reset to old values now m_ModelName = m_OldModelName; m_ModelNumber = m_OldModelNumber; NPT_CHECK_FATAL(res); PLT_HttpHelper::SetBody(response, doc); PLT_HttpHelper::SetContentType(response, "text/xml"); return NPT_SUCCESS; } return PLT_MediaServer::ProcessGetDescription(request, context, response); }
/*---------------------------------------------------------------------- | PLT_SsdpSender::SendSsdp +---------------------------------------------------------------------*/ NPT_Result PLT_SsdpSender::SendSsdp(NPT_HttpRequest& request, const char* usn, const char* target, NPT_UdpSocket& socket, bool notify, const NPT_SocketAddress* addr /* = NULL */) { NPT_CHECK_SEVERE(FormatPacket(request, usn, target, socket, notify)); // logging NPT_LOG_FINE("Sending SSDP:"); PLT_LOG_HTTP_MESSAGE(NPT_LOG_LEVEL_FINE, &request); // use a memory stream to write all the data NPT_MemoryStream stream; NPT_Result res = request.Emit(stream); if (NPT_FAILED(res)) return res; // copy stream into a data packet and send it NPT_LargeSize size; stream.GetSize(size); if (size != (NPT_Size)size) return NPT_ERROR_OUT_OF_RANGE; NPT_DataBuffer packet(stream.GetData(), (NPT_Size)size); return socket.Send(packet, addr); }
/*---------------------------------------------------------------------- | PLT_HttpHelper::ToLog +---------------------------------------------------------------------*/ NPT_Result PLT_HttpHelper::ToLog(NPT_LoggerReference logger, int level, const NPT_HttpRequest& request) { NPT_COMPILER_UNUSED(logger); NPT_COMPILER_UNUSED(level); NPT_StringOutputStreamReference stream(new NPT_StringOutputStream); NPT_OutputStreamReference output = stream; request.GetHeaders().GetHeaders().Apply(NPT_HttpHeaderPrinter(output)); NPT_LOG_L4(logger, level, "\n%s %s %s\n%s", (const char*)request.GetMethod(), (const char*)request.GetUrl().ToRequestString(true), (const char*)request.GetProtocol(), (const char*)stream->GetString()); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_HttpHelper::SetBasicAuthorization +---------------------------------------------------------------------*/ void PLT_HttpHelper::SetBasicAuthorization(NPT_HttpRequest& request, const char* username, const char* password) { NPT_String encoded; NPT_String cred = NPT_String(username) + ":" + password; NPT_Base64::Encode((const NPT_Byte *)cred.GetChars(), cred.GetLength(), encoded); request.GetHeaders().SetHeader(NPT_HTTP_HEADER_AUTHORIZATION, NPT_String("Basic " + encoded)); }
/*---------------------------------------------------------------------- | PLT_FileMediaServer::ProcessFileRequest +---------------------------------------------------------------------*/ NPT_Result PLT_FileMediaServer::ProcessFileRequest(NPT_HttpRequest& request, const NPT_HttpRequestContext& context, NPT_HttpResponse& response) { NPT_LOG_FINE("PLT_FileMediaServer::ProcessFileRequest Received Request:"); PLT_LOG_HTTP_MESSAGE(NPT_LOG_LEVEL_FINE, &request); response.GetHeaders().SetHeader("Accept-Ranges", "bytes"); if (request.GetMethod().Compare("GET") && request.GetMethod().Compare("HEAD")) { response.SetStatus(500, "Internal Server Error"); return NPT_SUCCESS; } // Extract uri path from url NPT_String uri_path = NPT_Uri::PercentDecode(request.GetUrl().GetPath()); // extract file path from query NPT_HttpUrlQuery query(request.GetUrl().GetQuery()); NPT_String file_path = query.GetField("path"); // hack for XBMC support for 360, we urlencoded the ? to that the 360 doesn't strip out the query // but then the query ends being parsed as part of the path int index = uri_path.Find("path="); if (index>0) file_path = uri_path.Right(uri_path.GetLength()-index-5); if (file_path.GetLength() == 0) goto failure; NPT_CHECK_LABEL_WARNING(ServeFile(request, context, response, uri_path, file_path), failure); return NPT_SUCCESS; failure: response.SetStatus(404, "File Not Found"); return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | PLT_HttpHelper::GetHost +---------------------------------------------------------------------*/ NPT_Result PLT_HttpHelper::GetHost(const NPT_HttpRequest& request, NPT_String& value) { value = ""; const NPT_String* val = request.GetHeaders().GetHeaderValue(NPT_HTTP_HEADER_HOST); NPT_CHECK_POINTER(val); value = *val; return NPT_SUCCESS; }
/*---------------------------------------------------------------------- | 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; }
NPT_Result CHttpServer::SetupResponse(NPT_HttpRequest& request, const NPT_HttpRequestContext& context, NPT_HttpResponse& response) { NPT_String prefix = NPT_String::Format("PLT_HttpServer::SetupResponse %s request from %s for \"%s\"", (const char*) request.GetMethod(), (const char*) context.GetRemoteAddress().ToString(), (const char*) request.GetUrl().ToString()); NPT_List<NPT_HttpRequestHandler*> handlers = FindRequestHandlers(request); if (handlers.GetItemCount() == 0) return NPT_ERROR_NO_SUCH_ITEM; // ask the handler to setup the response NPT_Result result = (*handlers.GetFirstItem())->SetupResponse(request, context, response); // DLNA compliance UPNPMessageHelper::SetDate(response); if (request.GetHeaders().GetHeader("Accept-Language")) { response.GetHeaders().SetHeader("Content-Language", "en"); } return result; }
/*---------------------------------------------------------------------- | PLT_HttpHelper::SetRange +---------------------------------------------------------------------*/ void PLT_HttpHelper::SetRange(NPT_HttpRequest& request, NPT_Position start, NPT_Position end) { NPT_String range = "bytes="; if (start != (NPT_Position)-1) { range += NPT_String::FromIntegerU(start); } range += '-'; if (end != (NPT_Position)-1) { range += NPT_String::FromIntegerU(end); } request.GetHeaders().SetHeader(NPT_HTTP_HEADER_RANGE, range); }
/*---------------------------------------------------------------------- | 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; }
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_MediaServer::ProcessGetDescription +---------------------------------------------------------------------*/ NPT_Result PLT_MediaServer::ProcessGetDescription(NPT_HttpRequest& request, const NPT_HttpRequestContext& context, NPT_HttpResponse& response) { NPT_String m_OldModelName = m_ModelName; NPT_String m_OldModelNumber = m_ModelNumber; /* change some things based on User-Agent header */ NPT_HttpHeader* user_agent = request.GetHeaders().GetHeader(NPT_HTTP_HEADER_USER_AGENT); if (user_agent && user_agent->GetValue().Find("Sonos", 0, true)>=0) { /* Force "Rhapsody" so that Sonos doesn't reject us */ m_ModelName = "Rhapsody"; m_ModelNumber = "3.0"; } NPT_Result res = PLT_DeviceHost::ProcessGetDescription(request, context, response); /* reset back to old values now */ m_ModelName = m_OldModelName; m_ModelNumber = m_OldModelNumber; return res; }
/*---------------------------------------------------------------------- | 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; }
/*---------------------------------------------------------------------- | PLT_HttpClient::SendRequest +---------------------------------------------------------------------*/ NPT_Result PLT_HttpClient::SendRequest(NPT_OutputStreamReference& output_stream, NPT_HttpRequest& request, NPT_Timeout timeout) { NPT_COMPILER_UNUSED(timeout); // connect to the server NPT_LOG_FINE("Sending:"); PLT_LOG_HTTP_MESSAGE(NPT_LOG_LEVEL_FINE, &request); // add any headers that may be missing NPT_HttpHeaders& headers = request.GetHeaders(); //headers.SetHeader(NPT_HTTP_HEADER_CONNECTION, "close"); if (!headers.GetHeader(NPT_HTTP_HEADER_USER_AGENT)) { headers.SetHeader(NPT_HTTP_HEADER_USER_AGENT, "Platinum/" PLT_PLATINUM_VERSION_STRING); } // set host only if not already set if (!headers.GetHeader(NPT_HTTP_HEADER_HOST)) { NPT_String host = request.GetUrl().GetHost(); if (request.GetUrl().GetPort() != NPT_HTTP_DEFAULT_PORT) { host += ":"; host += NPT_String::FromInteger(request.GetUrl().GetPort()); } headers.SetHeader(NPT_HTTP_HEADER_HOST, host); } // get the request entity to set additional headers NPT_InputStreamReference body_stream; NPT_HttpEntity* entity = request.GetEntity(); if (entity && NPT_SUCCEEDED(entity->GetInputStream(body_stream))) { // content length headers.SetHeader(NPT_HTTP_HEADER_CONTENT_LENGTH, NPT_String::FromInteger(entity->GetContentLength())); // content type NPT_String content_type = entity->GetContentType(); if (!content_type.IsEmpty()) { headers.SetHeader(NPT_HTTP_HEADER_CONTENT_TYPE, content_type); } // content encoding NPT_String content_encoding = entity->GetContentEncoding(); if (!content_encoding.IsEmpty()) { headers.SetHeader(NPT_HTTP_HEADER_CONTENT_ENCODING, content_encoding); } } else { // force content length to 0 is there is no message body headers.SetHeader(NPT_HTTP_HEADER_CONTENT_LENGTH, "0"); } // create a memory stream to buffer the headers NPT_MemoryStream header_stream; // emit the request headers into the header buffer request.Emit(header_stream); // send the headers NPT_CHECK_SEVERE(output_stream->WriteFully(header_stream.GetData(), header_stream.GetDataSize())); // send request body if (!body_stream.IsNull() && entity->GetContentLength()) { NPT_CHECK_SEVERE(NPT_StreamToStreamCopy(*body_stream.AsPointer(), *output_stream.AsPointer())); } // flush the output stream so that everything is sent to the server output_stream->Flush(); 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; }
void FrontEnd::httpConnectorOnNewClient(HttpServerTask *task, Interface *intf, NPT_Socket *client) { NPT_Result nr; NPT_InputStreamReference inputStream0; nr = client->GetInputStream(inputStream0); if (NPT_FAILED(nr)) { return; } NPT_OutputStreamReference outputStream; nr = client->GetOutputStream(outputStream); if (NPT_FAILED(nr)) { return; } NPT_BufferedInputStreamReference inputStream(new NPT_BufferedInputStream(inputStream0)); NPT_HttpRequest *req; nr = NPT_HttpRequest::Parse(*inputStream.AsPointer(), NULL, req); if (NPT_FAILED(nr)) { return; } // TODO: validate "HOST" ??? RequestContext reqCtx; reqCtx.clientHint = CH_Unknown; reqCtx.transferMode = TM_None; reqCtx.getcontentFeaturesReq = false; NPT_HttpHeader *hdrUserAgent = req->GetHeaders().GetHeader(NPT_HTTP_HEADER_USER_AGENT); if (hdrUserAgent) { if (hdrUserAgent->GetValue().Find("xbox", 0, true) >= 0) { NPT_LOG_INFO_1("XBox found [User-Agent: %s]", hdrUserAgent->GetValue().GetChars()); reqCtx.clientHint = CH_XBox; } } NPT_HttpHeader *hdrTransferMode = req->GetHeaders().GetHeader("transferMode.dlna.org"); if (hdrTransferMode) { const NPT_String& transferMode = hdrTransferMode->GetValue(); if (transferMode.Compare("Streaming", true) == 0) { reqCtx.transferMode = TM_Streaming; } else if (transferMode.Compare("Interactive", true) == 0) { reqCtx.transferMode = TM_Interactive; } else if (transferMode.Compare("Background", true) == 0) { reqCtx.transferMode = TM_Background; } else { reqCtx.transferMode = TM_Unknown; } } NPT_HttpHeader *hdrGetContentFeatures = req->GetHeaders().GetHeader("getcontentFeatures.dlna.org"); if (hdrGetContentFeatures) { NPT_String getContentFeatures = hdrGetContentFeatures->GetValue(); if (getContentFeatures.Trim().Compare("1") == 0) { reqCtx.getcontentFeaturesReq = true; } } NPT_SocketInfo si; client->GetInfo(si); onHttpRequestHeader(si, req); PtrHolder<NPT_HttpRequest> req1(req); NPT_String reqPath(req->GetUrl().GetPath()); NPT_TimeStamp ts; NPT_System::GetCurrentTimeStamp(ts); NPT_String dateStr = NPT_DateTime(ts).ToString(NPT_DateTime::FORMAT_RFC_1123); NPT_HttpResponse *resp = new NPT_HttpResponse(200, "OK", NPT_HTTP_PROTOCOL_1_1); PtrHolder<NPT_HttpResponse> resp1(resp); resp->GetHeaders().SetHeader(NPT_HTTP_HEADER_SERVER, m_serverHeader); resp->GetHeaders().SetHeader("Date", dateStr); resp->GetHeaders().SetHeader(NPT_HTTP_HEADER_CONTENT_LENGTH, "0"); resp->GetHeaders().SetHeader(NPT_HTTP_HEADER_CONTENT_TYPE, "text/xml"); HttpOutput *httpOutput = new HttpOutputImpl(this, si, outputStream); PtrHolder<HttpOutput> httpOutput1(httpOutput); { ReadLocker locker(m_cpLock); for (NPT_Ordinal i = 0; i < m_controlPointList.GetItemCount(); i++) { NPT_List<ControlPointInfo*>::Iterator it = m_controlPointList.GetItem(i); ControlPointInfo *info = *it; if (reqPath.StartsWith(info->m_context.m_httpRoot)) { NPT_InputStream *input = inputStream.AsPointer(); inputStream.Detach(); httpOutput1.detach(); resp1.detach(); req1.detach(); task->detach(); return info->m_controlPoint->processHttpRequest(&intf->m_context, reqPath.SubString(info->m_context.m_httpRoot.GetLength()), reqCtx, req, resp, input, httpOutput, client); } } } { ReadLocker locker(m_dsLock); for (NPT_Ordinal i = 0; i < m_deviceImplList.GetItemCount(); i++) { NPT_List<DeviceImplInfo*>::Iterator it = m_deviceImplList.GetItem(i); DeviceImplInfo *info = *it; if (reqPath.StartsWith(info->m_context.m_httpRoot)) { NPT_InputStream *input = inputStream.AsPointer(); inputStream.Detach(); httpOutput1.detach(); resp1.detach(); req1.detach(); task->detach(); return info->m_deviceImpl->processHttpRequest(&intf->m_context, reqPath.SubString(info->m_context.m_httpRoot.GetLength()), reqCtx, req, resp, input, httpOutput, client); } } } setStatusCode(*resp, 404); httpOutput->writeResponseHeader(*resp); httpOutput->flush(); }
void FrontEnd::processSsdpSearch(SsdpServerTask *task, Interface *intf, const NPT_DataBuffer& data, const NPT_SocketAddress& fromAddr) { do { NPT_HttpRequest *req; NPT_InputStreamReference inputStream0(new NPT_MemoryStream(data.GetData(), data.GetDataSize())); NPT_BufferedInputStream inputStream(inputStream0); if (NPT_FAILED(NPT_HttpRequest::Parse(inputStream, NULL, req))) { break; } PtrHolder<NPT_HttpRequest> req1(req); if (req->GetMethod().Compare("M-SEARCH") != 0 || req->GetProtocol().Compare(NPT_HTTP_PROTOCOL_1_1) != 0 || req->GetUrl().GetPath().Compare("*") != 0) { break; } NPT_HttpHeader *hdrMan = req->GetHeaders().GetHeader("MAN"); if (!hdrMan || hdrMan->GetValue().Compare("\"ssdp:discover\"") != 0) { break; } NPT_HttpHeader *hdrHost = req->GetHeaders().GetHeader("HOST"); if (!hdrHost || (hdrHost->GetValue().Compare("239.255.255.250:1900") != 0 && hdrHost->GetValue().Compare("239.255.255.250") != 0)) { break; } int mx; NPT_HttpHeader *hdrMX = req->GetHeaders().GetHeader("MX"); if (!hdrMX || NPT_FAILED(NPT_ParseInteger(hdrMX->GetValue(), mx)) || mx < 1) { break; } if (mx > 120) { mx = 120; } NPT_HttpHeader *hdrST = req->GetHeaders().GetHeader("ST"); if (!hdrST) { break; } NPT_List<MatchContext*> matchList; NPT_UdpSocket sock(NPT_SOCKET_FLAG_CANCELLABLE); sock.Bind(NPT_SocketAddress(intf->m_context.m_ifAddr, 0)); NPT_SharedVariable waitVar; waitVar.SetValue(0); { ReadLocker locker(m_dsLock); for (NPT_Ordinal i = 0; i < m_deviceImplList.GetItemCount(); i++) { NPT_List<DeviceImplInfo*>::Iterator it = m_deviceImplList.GetItem(i); DeviceImplInfo *info = *it; MatchContext *matchContext = new MatchContext(); if (info->m_deviceImpl->match(hdrST->GetValue(), matchContext->matches)) { matchList.Add(matchContext); matchContext->deviceUuid = info->m_deviceImpl->uuid(); matchContext->expireSeconds = info->m_deviceImpl->m_expireSeconds; matchContext->descPath = info->m_deviceImpl->m_descPath; matchContext->httpRoot = info->m_context.m_httpRoot; } else { delete matchContext; } } } SsdpSearchAbortCallback abortCallback(&sock, &waitVar); if (task->registerAbortCallback(&abortCallback)) { for (NPT_Ordinal i = 0; i < matchList.GetItemCount(); i++) { MatchContext *matchContext = *matchList.GetItem(i); NPT_String location = NPT_String::Format("http://%s:%d%s%s", intf->m_context.m_ifAddr.ToString().GetChars(), intf->m_context.m_httpPort, matchContext->httpRoot.GetChars(), matchContext->descPath.GetChars()); bool broken = false; for (NPT_Ordinal j = 0; j < matchContext->matches.GetItemCount(); j++) { NPT_List<DeviceImplMatch>::Iterator it2 = matchContext->matches.GetItem(j); NPT_Timeout timeout = NPT_System::GetRandomInteger() % (mx * 1000); // TODO: wait or not ??? timeout = 0; if (NPT_SUCCEEDED(waitVar.WaitWhileEquals(0, timeout))) { break; } { ReadLocker locker(m_dsLock); if (m_deviceImplIndex.HasKey(matchContext->deviceUuid)) { NPT_TimeStamp ts; NPT_System::GetCurrentTimeStamp(ts); NPT_String dateStr = NPT_DateTime(ts).ToString(NPT_DateTime::FORMAT_RFC_1123); NPT_String resp = NPT_String::Format("HTTP/1.1 200 OK\r\nCACHE-CONTROL: max-age=%d\r\nDATE: %s\r\nEXT: \r\nLOCATION: %s\r\nSERVER: %s\r\nST: %s\r\nUSN: %s\r\nCUSTOM:%s\r\n\r\n", matchContext->expireSeconds, dateStr.GetChars(), location.GetChars(), m_serverHeader.GetChars(), it2->m_st.GetChars(), it2->m_usn.GetChars(), m_DevName.GetChars()); NPT_DataBuffer packet(resp.GetChars(), resp.GetLength(), false); sock.Send(packet, &fromAddr); } } } if (broken) { break; } } task->unregisterAbortCallback(&abortCallback); } matchList.Apply(NPT_ObjectDeleter<MatchContext>()); } while (false); }