Ejemplo n.º 1
0
/*----------------------------------------------------------------------
|   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;
}
Ejemplo n.º 2
0
/*----------------------------------------------------------------------
|   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;
}
Ejemplo n.º 3
0
/*----------------------------------------------------------------------
|   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);
}
Ejemplo n.º 4
0
/*----------------------------------------------------------------------
|   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;
}
Ejemplo n.º 5
0
/*----------------------------------------------------------------------
|   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;
}
Ejemplo n.º 6
0
/*----------------------------------------------------------------------
|   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;
}
Ejemplo n.º 7
0
/*----------------------------------------------------------------------
|   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;
}
Ejemplo n.º 8
0
/*----------------------------------------------------------------------
|   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;
}
Ejemplo n.º 9
0
/*----------------------------------------------------------------------
|   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;
}
Ejemplo n.º 10
0
/*----------------------------------------------------------------------
|   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;
}
Ejemplo n.º 11
0
/*----------------------------------------------------------------------
|   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;
}
Ejemplo n.º 12
0
    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;
    }
Ejemplo n.º 13
0
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;
}
Ejemplo n.º 14
0
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);
}
    NPT_Result SetupResponse(NPT_HttpRequest&              request, 
                             const NPT_HttpRequestContext& context,
                             NPT_HttpResponse&             response) {
        NPT_String msg = "<HTML>";
        msg += "PATH=";
        msg += request.GetUrl().GetPath();
        msg += "<P><B>Local Address:</B> ";
        msg += context.GetLocalAddress().ToString();
        msg += "<P>";
        msg += "<B>Remote Address:</B> ";
        msg += context.GetRemoteAddress().ToString();
        msg += "<P><UL>";
        if (request.GetUrl().HasQuery()) {
            NPT_UrlQuery query(request.GetUrl().GetQuery());
            for (NPT_List<NPT_UrlQuery::Field>::Iterator it = query.GetFields().GetFirstItem();
                 it;
                 ++it) {
                 NPT_UrlQuery::Field& field = *it;
                 msg += "<LI>";
                 msg += field.m_Name;
                 msg += " = ";
                 msg += field.m_Value;
                 msg += " </LI>";
                 
                 // check for a 'delay' field
                 if (field.m_Name == "delay") {
                    NPT_UInt32 delay = 0;
                    field.m_Value.ToInteger(delay);
                    NPT_Debug("DELAY: %d seconds\n", delay);
                    NPT_System::Sleep(NPT_TimeInterval((float)delay));
                 }
            }
        }
        msg += "</UL></HTML>";

        
        if (request.GetMethod() == NPT_HTTP_METHOD_POST) {
            NPT_DataBuffer request_body;
            request.GetEntity()->Load(request_body);
            NPT_Debug("REQUEST: body = %d bytes\n", request_body.GetDataSize());
            NPT_Debug("REQUEST: content type = %s\n", request.GetEntity()->GetContentType().GetChars());
            if (request.GetEntity()->GetContentType().StartsWith("text") ||
                request.GetEntity()->GetContentType() == "application/x-www-form-urlencoded") {
                NPT_String body_string;
                body_string.Assign((char*)request_body.GetData(), request_body.GetDataSize());
                NPT_Debug("%s", body_string.GetChars());
            }
        }

        NPT_HttpEntity* entity = response.GetEntity();
        entity->SetContentType("text/html");
        NPT_MemoryStreamReference memory_stream(
            new NPT_MemoryStream((const void*)msg.GetChars(), msg.GetLength()));
        entity->SetInputStream(memory_stream, !m_Chunked);
        
        if (m_Chunked) {
            entity->SetTransferEncoding(NPT_HTTP_TRANSFER_ENCODING_CHUNKED);
        }
        
        return NPT_SUCCESS;
    }