4thline / cling

UPnP/DLNA library for Java and Android

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Could not parse service descriptor: java.lang.RuntimeException: org.xml.sax.SAXNotRecognizedException: http://javax.xml.XMLConstants/feature/secure-processing

javaertj opened this issue · comments

Could not parse service descriptor: java.lang.RuntimeException: org.xml.sax.SAXNotRecognizedException: http://javax.xml.XMLConstants/feature/secure-processing

androidOsVersion="9.0"
clingVersion = "2.1.2"
jettyVersion = "8.1.22.v20160922"
slf4jVersion = "1.7.25"

In order to solve the exception, I rewrote several classes.

public class DLNABrowserService extends AndroidUpnpServiceImpl {
@OverRide
protected UpnpServiceConfiguration createConfiguration() {
return new AndroidUpnpServiceConfiguration() {

        @Override
        public ServiceDescriptorBinder createServiceDescriptorBinderUDA10() {
            return new DLNAUDA10ServiceDescriptorBinderSAXImpl();
        }
    };
}

}


public class DLNASAXParser extends SAXParser {

protected XMLReader create() {
    try {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        //fix bug .see https://stackoverflow.com/questions/10837706/solve-security-issue-parsing-xml-using-sax-parser
        factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);

        // Configure factory to prevent XXE attacks
        factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
        factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);
        factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
        factory.setXIncludeAware(false);

        factory.setNamespaceAware(true);

        if (getSchemaSources() != null) {
            factory.setSchema(createSchema(getSchemaSources()));
        }

        XMLReader xmlReader = factory.newSAXParser().getXMLReader();
        xmlReader.setErrorHandler(getErrorHandler());
        return xmlReader;
    } catch (Exception ex) {
        throw new RuntimeException(ex);
    }
}

}

public class DLNAUDA10ServiceDescriptorBinderSAXImpl extends UDA10ServiceDescriptorBinderSAXImpl {
private static Logger log = Logger.getLogger(ServiceDescriptorBinder.class.getName());

@Override
public <S extends Service> S describe(S undescribedService, String descriptorXml) throws DescriptorBindingException, ValidationException {

    if (descriptorXml == null || descriptorXml.length() == 0) {
        throw new DescriptorBindingException("Null or empty descriptor");
    }

    try {
        log.fine("Reading service from XML descriptor");

        SAXParser parser = new DLNASAXParser();

        MutableService descriptor = new MutableService();

        hydrateBasic(descriptor, undescribedService);

        new RootHandler(descriptor, parser);

        parser.parse(
                new InputSource(
                        // TODO: UPNP VIOLATION: Virgin Media Superhub sends trailing spaces/newlines after last XML element, need to trim()
                        new StringReader(descriptorXml.trim())
                )
        );

        // Build the immutable descriptor graph
        return (S)descriptor.build(undescribedService.getDevice());

    } catch (ValidationException ex) {
        throw ex;
    } catch (Exception ex) {
        throw new DescriptorBindingException("Could not parse service descriptor: " + ex.toString(), ex);
    }
}

}

Finally, I solved the problem that the upnp protocol could not be resolved by rewriting the SAXParser referenced in UDA10ServiceDescriptorBinderSAXImpl and commenting out a few lines of code.

public class DLNASAXParser extends SAXParser {
    protected XMLReader create() {
        try {
            SAXParserFactory factory = SAXParserFactory.newInstance();

            // Configure factory to prevent XXE attacks
            factory.setFeature("http://xml.org/sax/features/external-general-entities", false);
            factory.setFeature("http://xml.org/sax/features/external-parameter-entities", false);

            //commenting
            //factory.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
            //factory.setXIncludeAware(false);

            //factory.setNamespaceAware(true);

            if (getSchemaSources() != null) {
                factory.setSchema(createSchema(getSchemaSources()));
            }

            XMLReader xmlReader = factory.newSAXParser().getXMLReader();
            xmlReader.setErrorHandler(getErrorHandler());
            return xmlReader;
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
}

still Exception

05-11 20:58:56.859 18002-18002/com.tv.cast.castdemo2 D/devicetest: Discovery failed of 'Xiaomi MediaRenderer':org.fourthline.cling.binding.xml.DescriptorBindingException: Could not parse service descriptor: java.lang.RuntimeException: org.xml.sax.SAXNotRecognizedException: http://apache.org/xml/features/disallow-doctype-decl

you can switch to the safer implementation and not use the SAX, which only works with devices using perfect Upnp 1.0 implementations (this is Kotlin, Java should look similar but different), as described in the manual :

override fun getServiceDescriptorBinderUDA10(): ServiceDescriptorBinder? {
    return UDA10ServiceDescriptorBinderImpl()
}