コード例 #1
0
ファイル: PltHttpServer.cpp プロジェクト: 1c0n/xbmc
/*----------------------------------------------------------------------
|   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));
}
コード例 #2
0
/*----------------------------------------------------------------------
|   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;
}
コード例 #3
0
/*----------------------------------------------------------------------
|   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();
    }
}
コード例 #4
0
ファイル: DJMediaStore.cpp プロジェクト: bubbletreefrog/DLNA
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);
	}
}
コード例 #5
0
ファイル: DJMediaStore.cpp プロジェクト: bubbletreefrog/DLNA
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
}
コード例 #6
0
ファイル: PltHttpServer.cpp プロジェクト: 1c0n/xbmc
/*----------------------------------------------------------------------
|   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;
}
コード例 #7
0
/*----------------------------------------------------------------------
|   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);
}
コード例 #8
0
ファイル: DJFrontEnd.cpp プロジェクト: bubbletreefrog/DLNA
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);
}
コード例 #9
0
ファイル: DJFrontEnd.cpp プロジェクト: bubbletreefrog/DLNA
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();

}