/*---------------------------------------------------------------------- | 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)); }
/*---------------------------------------------------------------------- | NPT_LogTcpHandler::Log +---------------------------------------------------------------------*/ void NPT_LogTcpHandler::FormatRecord(const NPT_LogRecord& record, NPT_String& msg) { /* format the record */ const char* level_name = NPT_Log::GetLogLevelName(record.m_Level); NPT_String level_string; /* format and emit the record */ if (level_name[0] == '\0') { level_string = NPT_String::FromIntegerU(record.m_Level); level_name = level_string; } msg.Reserve(2048); msg += "Logger: "; msg += record.m_LoggerName; msg += "\r\nLevel: "; msg += level_name; msg += "\r\nSource-File: "; msg += record.m_SourceFile; msg += "\r\nSource-Function: "; msg += record.m_SourceFunction; msg += "\r\nSource-Line: "; msg += NPT_String::FromIntegerU(record.m_SourceLine); msg += "\r\nThread-Id: "; msg += NPT_String::FromIntegerU(record.m_ThreadId); msg += "\r\nTimeStamp: "; msg += NPT_DateTime(record.m_TimeStamp, true).ToString(NPT_DateTime::FORMAT_W3C, NPT_DateTime::FLAG_EMIT_FRACTION | NPT_DateTime::FLAG_EXTENDED_PRECISION); msg += "\r\nContent-Length: "; msg += NPT_String::FromIntegerU(NPT_StringLength(record.m_Message)); msg += "\r\n\r\n"; msg += record.m_Message; }
/*---------------------------------------------------------------------- | NPT_LogFileHandler::Log +---------------------------------------------------------------------*/ void NPT_LogFileHandler::Log(const NPT_LogRecord& record) { if (m_MaxFilesize > 0) { /* get current file size */ NPT_LargeSize size; NPT_File::GetSize(m_Filename, size); /* time to recycle ? */ if (size > m_MaxFilesize) { /* release stream to force a reopen later and to be able to rename file */ m_Stream = NULL; /* rename file using current time */ NPT_TimeStamp now; NPT_System::GetCurrentTimeStamp(now); NPT_String suffix = NPT_DateTime(now, true).ToString(NPT_DateTime::FORMAT_W3C); suffix.Replace(':', '_'); NPT_String new_name = NPT_FilePath::Create( NPT_FilePath::DirName(m_Filename), NPT_FilePath::BaseName(m_Filename, false) + "-" + suffix + NPT_FilePath::FileExtension(m_Filename)); NPT_File::Rename(m_Filename, new_name); } } /* try to reopen the file if it failed to open previously or if we rotated it */ if (m_Stream.IsNull()) { Open(m_Append); } if (m_Stream.AsPointer()) { NPT_Log::FormatRecordToStream(record, *m_Stream, false, m_FormatFilter); if (m_Flush) m_Stream->Flush(); } }
void serveStreamAdv(AbortableTask *task, const MediaStore::FileDetail& detail, AdvStreamReader *reader, const FrontEnd::RequestContext& reqCtx, const NPT_HttpRequest *req, NPT_HttpResponse& resp, HttpOutput *httpOutput, NPT_Size bufferSize) { bool isGetMethod = req->GetMethod().Compare("GET") == 0; bool isHeadMethod = req->GetMethod().Compare("HEAD") == 0; if (isGetMethod || isHeadMethod) { NPT_Result nr; NPT_UInt64 offset, length; NPT_HttpHeader *hdrRange = req->GetHeaders().GetHeader("RANGE"); if (hdrRange) { if (!parseRangeHeader(hdrRange->GetValue(), detail.m_size, offset, length)) { setStatusCode(resp, 416); httpOutput->writeResponseHeader(resp); return; } setStatusCode(resp, 206); resp.GetHeaders().SetHeader(NPT_HTTP_HEADER_CONTENT_RANGE, NPT_String::Format("bytes %s-%s/%s", NPT_String::FromIntegerU(offset).GetChars(), NPT_String::FromIntegerU(offset + length - 1).GetChars(), NPT_String::FromIntegerU(detail.m_size).GetChars())); } else { offset = 0; length = detail.m_size; setStatusCode(resp, 200); } resp.GetHeaders().SetHeader(NPT_HTTP_HEADER_CONTENT_TYPE, detail.m_mimeType); resp.GetHeaders().SetHeader(NPT_HTTP_HEADER_CONTENT_LENGTH, NPT_String::FromIntegerU(length)); resp.GetHeaders().SetHeader("Last-Modified", NPT_DateTime(detail.m_modificationTime).ToString(NPT_DateTime::FORMAT_RFC_1123)); resp.GetHeaders().SetHeader("Accept-Ranges", "bytes"); resp.GetHeaders().SetHeader("EXT", ""); if (reqCtx.transferMode != FrontEnd::TM_None) { const char *transferMode = "Streaming"; switch (reqCtx.transferMode) { case FrontEnd::TM_Background: transferMode = "Background"; break; case FrontEnd::TM_Interactive: transferMode = "Interactive"; break; } resp.GetHeaders().SetHeader("transferMode.dlna.org", transferMode); } if (reqCtx.getcontentFeaturesReq) { NPT_String contentFeatures("DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01700000000000000000000000000000"); resp.GetHeaders().SetHeader("contentFeatures.dlna.org", contentFeatures); } httpOutput->writeResponseHeader(resp); if (isGetMethod) { bool abortFlag = false; ServeFileAbortCallback abortCallback(&abortFlag, reader); if (task->registerAbortCallback(&abortCallback)) { reader->seek(offset); NPT_DataBuffer buffer(bufferSize); NPT_UInt64 cbRemain = length; for (;;) { if (abortFlag) { break; } if (cbRemain == 0) { break; } NPT_Size cbRead; NPT_Size cbToRead = cbRemain; if (cbToRead > buffer.GetBufferSize()) { cbToRead = buffer.GetBufferSize(); } nr = reader->read(buffer.UseData(), buffer.GetBufferSize(), &cbRead); if (NPT_FAILED(nr)) { /*if (nr == NPT_ERROR_EOS) { } else { }*/ break; } if (abortFlag) { break; } if (cbRead > 0) { cbRemain -= cbRead; httpOutput->writeData(buffer.GetData(), cbRead); } } task->unregisterAbortCallback(&abortCallback); } } } else { setStatusCode(resp, 405); resp.GetHeaders().SetHeader("Allow", "GET, HEAD"); httpOutput->writeResponseHeader(resp); } }
void serveFile2(AbortableTask *task, const NPT_String& filePath, const NPT_String& mimeType, const FrontEnd::RequestContext& reqCtx, const NPT_HttpRequest *req, NPT_HttpResponse& resp, HttpOutput *httpOutput) { #if 1 NPT_File f(filePath); NPT_FileInfo fileInfo; if (NPT_FAILED(f.GetInfo(fileInfo)) || fileInfo.m_Type != NPT_FileInfo::FILE_TYPE_REGULAR || NPT_FAILED(f.Open(NPT_FILE_OPEN_MODE_READ))) { setStatusCode(resp, 404); httpOutput->writeResponseHeader(resp); return; } NPT_InputStreamReference fileInput; f.GetInputStream(fileInput); serveStream(task, fileInput.AsPointer(), fileInfo.m_ModificationTime, mimeType, reqCtx, req, resp, httpOutput); #else bool isGetMethod = req->GetMethod().Compare("GET") == 0; bool isHeadMethod = req->GetMethod().Compare("HEAD") == 0; if (isGetMethod || isHeadMethod) { NPT_Result nr; NPT_File f(filePath); NPT_FileInfo fileInfo; if (NPT_FAILED(f.GetInfo(fileInfo)) || fileInfo.m_Type != NPT_FileInfo::FILE_TYPE_REGULAR || NPT_FAILED(f.Open(NPT_FILE_OPEN_MODE_READ))) { setStatusCode(resp, 404); httpOutput->writeResponseHeader(resp); return; } NPT_InputStreamReference fileInput; f.GetInputStream(fileInput); NPT_UInt64 offset, length; NPT_HttpHeader *hdrRange = req->GetHeaders().GetHeader("RANGE"); if (hdrRange) { if (!parseRangeHeader(hdrRange->GetValue(), fileInfo.m_Size, offset, length)) { setStatusCode(resp, 416); httpOutput->writeResponseHeader(resp); return; } setStatusCode(resp, 206); resp.GetHeaders().SetHeader(NPT_HTTP_HEADER_CONTENT_RANGE, NPT_String::Format("bytes %s-%s/%s", NPT_String::FromIntegerU(offset).GetChars(), NPT_String::FromIntegerU(offset + length - 1).GetChars(), NPT_String::FromIntegerU(fileInfo.m_Size).GetChars())); fileInput->Seek(offset); } else { offset = 0; length = fileInfo.m_Size; setStatusCode(resp, 200); } resp.GetHeaders().SetHeader(NPT_HTTP_HEADER_CONTENT_TYPE, mimeType); resp.GetHeaders().SetHeader(NPT_HTTP_HEADER_CONTENT_LENGTH, NPT_String::FromIntegerU(length)); resp.GetHeaders().SetHeader("Last-Modified", NPT_DateTime(fileInfo.m_ModificationTime).ToString(NPT_DateTime::FORMAT_RFC_1123)); resp.GetHeaders().SetHeader("Accept-Ranges", "bytes"); resp.GetHeaders().SetHeader("EXT", ""); if (reqCtx.transferMode != FrontEnd::TM_None) { const char *transferMode = "Streaming"; switch (reqCtx.transferMode) { case FrontEnd::TM_Background: transferMode = "Background"; break; case FrontEnd::TM_Interactive: transferMode = "Interactive"; break; } resp.GetHeaders().SetHeader("transferMode.dlna.org", transferMode); } if (reqCtx.getcontentFeaturesReq) { NPT_String contentFeatures("DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01700000000000000000000000000000"); resp.GetHeaders().SetHeader("contentFeatures.dlna.org", contentFeatures); } httpOutput->writeResponseHeader(resp); if (isGetMethod) { bool abortFlag = false; ServeFileAbortCallback abortCallback(&abortFlag); if (task->registerAbortCallback(&abortCallback)) { NPT_DataBuffer buffer(4096); NPT_UInt64 cbRemain = length; for (;;) { if (abortFlag) { break; } if (cbRemain == 0) { break; } NPT_Size cbRead; NPT_UInt64 cbToRead = cbRemain; if (cbToRead > buffer.GetBufferSize()) { cbToRead = buffer.GetBufferSize(); } nr = fileInput->Read(buffer.UseData(), buffer.GetBufferSize(), &cbRead); if (NPT_FAILED(nr)) { /*if (nr == NPT_ERROR_EOS) { } else { }*/ break; } if (abortFlag) { break; } if (cbRead > 0) { cbRemain -= cbRead; httpOutput->writeData(buffer.GetData(), cbRead); } } task->unregisterAbortCallback(&abortCallback); } } } else { setStatusCode(resp, 405); resp.GetHeaders().SetHeader("Allow", "GET, HEAD"); httpOutput->writeResponseHeader(resp); } #endif }
/*---------------------------------------------------------------------- | 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; }
/*---------------------------------------------------------------------- | NPT_Log::FormatRecordToStream +---------------------------------------------------------------------*/ void NPT_Log::FormatRecordToStream(const NPT_LogRecord& record, NPT_OutputStream& stream, bool use_colors, NPT_Flags format_filter) { const char* level_name = GetLogLevelName(record.m_Level); NPT_String level_string; /* format and emit the record */ if (level_name[0] == '\0') { level_string = NPT_String::FromInteger(record.m_Level); level_name = level_string; } if ((format_filter & NPT_LOG_FORMAT_FILTER_NO_SOURCE) == 0) { unsigned int start = 0; /* remove source file path if requested */ if (format_filter & NPT_LOG_FORMAT_FILTER_NO_SOURCEPATH) { for (start = NPT_StringLength(record.m_SourceFile); start; --start) { if (record.m_SourceFile[start-1] == '\\' || record.m_SourceFile[start-1] == '/') { break; } } } stream.WriteString(record.m_SourceFile + start); stream.Write("(", 1, NULL); stream.WriteString(NPT_String::FromIntegerU(record.m_SourceLine)); stream.Write("): ", 3, NULL); } if ((format_filter & NPT_LOG_FORMAT_FILTER_NO_LOGGER_NAME) == 0) { stream.Write("[", 1, NULL); stream.WriteString(record.m_LoggerName); stream.Write("] ", 2, NULL); } if ((format_filter & NPT_LOG_FORMAT_FILTER_NO_TIMESTAMP) == 0) { NPT_String ts = NPT_DateTime(record.m_TimeStamp, true).ToString(NPT_DateTime::FORMAT_W3C, NPT_DateTime::FLAG_EMIT_FRACTION | NPT_DateTime::FLAG_EXTENDED_PRECISION); stream.WriteString(ts.GetChars()); stream.Write(" ", 1); } if ((format_filter & NPT_LOG_FORMAT_FILTER_NO_FUNCTION_NAME) == 0) { stream.WriteFully("[",1); if (record.m_SourceFunction) { stream.WriteString(record.m_SourceFunction); } stream.WriteFully("] ",2); } if ((format_filter & NPT_LOG_FORMAT_FILTER_NO_THREAD_ID) == 0) { stream.Write("(", 1, NULL); stream.WriteString(NPT_String::FromIntegerU(record.m_ThreadId)); stream.Write(") ", 2, NULL); } const char* ansi_color = NULL; if (use_colors) { ansi_color = GetLogLevelAnsiColor(record.m_Level); if (ansi_color) { stream.Write("\033[", 2, NULL); stream.WriteString(ansi_color); stream.Write(";1m", 3, NULL); } } stream.WriteString(level_name); if (use_colors && ansi_color) { stream.Write("\033[0m", 4, NULL); } stream.Write(": ", 2, NULL); stream.WriteString(record.m_Message); stream.Write("\r\n", 2, NULL); }
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); }
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(); }