Ejemplo n.º 1
0
/*----------------------------------------------------------------------
|   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;
}
Ejemplo n.º 2
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.º 3
0
/*----------------------------------------------------------------------
|   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;
}
Ejemplo n.º 4
0
/*----------------------------------------------------------------------
|   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;
}
Ejemplo n.º 5
0
/*----------------------------------------------------------------------
|   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);
}
Ejemplo n.º 6
0
/*----------------------------------------------------------------------
|   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));
}
Ejemplo n.º 7
0
/*----------------------------------------------------------------------
|   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)); 
}
Ejemplo n.º 8
0
/*----------------------------------------------------------------------
|   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;
}
Ejemplo n.º 9
0
/*----------------------------------------------------------------------
|   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);
}
Ejemplo n.º 10
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.º 11
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;
}
/*----------------------------------------------------------------------
 |   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;
}
Ejemplo n.º 13
0
/*----------------------------------------------------------------------
|   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;
}
Ejemplo n.º 14
0
/*----------------------------------------------------------------------
|   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;
}
Ejemplo n.º 15
0
/*----------------------------------------------------------------------
|   PLT_HttpHelper::SetHost
+---------------------------------------------------------------------*/
void         
PLT_HttpHelper::SetHost(NPT_HttpRequest& request, const char* host)
{ 
    request.GetHeaders().SetHeader(NPT_HTTP_HEADER_HOST, host); 
}
Ejemplo n.º 16
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);
}
Ejemplo n.º 17
0
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();

}