Comment prévenir l'exception Stackoverflow dans HtmlAgilityPack en cas de très mauvais html

c# html-agility-pack stack-overflow

Question

J'utilise HtmlAgilityPack dans une API Web MVC 5. 99,99% du temps, il n'y a pas de problèmes ... les sites se chargent et je les analyse pour extraire le texte que je veux. Mon API peut être touchée plusieurs centaines de milliers de fois par jour sans problème. Il a heureusement traité plus de 2 millions de hits en 24 heures dans le passé ...

Parfois, cependant, des sites Web terriblement formés provoquent une réponse d'erreur 500. Ensuite, toutes les demandes suivantes génèrent 500 erreurs et le site devient complètement inutilisable. La seule solution dans ce scénario consiste à redémarrer l'application Web. Le site est hébergé sur Windows Azure. J'ai utilisé de grandes instances équilibrées en charge et une fois que le processeur a atteint un pic, il reste élevé. Dans le passé, cela fonctionnait parfaitement sur une seule instance de Medium Azure (2 cœurs / 3,5 Go de RAM).

L'erreur est un Stackoverflow ... que je sais que je ne peux pas attraper.

Notez que ce code ne bloque PAS une application de la console

HtmlWeb web = new HtmlWeb();
HtmlDocument doc = web.Load("http://nursingandmidwiferycareersni.com/");            
Console.Write(doc.DocumentNode.InnerText);

... mais cela plantera définitivement une application Web MVC.

Cependant, dans une application Web MVC simple, je peux reproduire l'erreur stackoverflow avec un site tel que http://nursingandmidwiferycareersni.com/ . Si vous mettez http://nursingandmidwiferycareersni.com/ dans https://validator.w3.org, vous obtiendrez une erreur de serveur interne sur validator.w3.org!

Je vais faire un piratage du code source HAP si nécessaire pour résoudre ce problème ... pour le moment, je n'utilise que le paquet Nuget.

Est-il possible d'empêcher que le stackoverflow se produise dans HAP?
Ou existe-t-il un moyen de vérifier si le code HTML est terrible et d’empêcher le crash de se produire?

Réponse populaire

Essayez quelque chose comme ceci, où la méthode ParseHtml et le type ParsedHtml sont que des espaces réservés que vous devez remplir:

public async Task<ParsedHtml> TryParseHtml(
    string untrustedHtml,
    CancellationToken cancellationToken)
{
    var tcs = new TaskCompletionSource<ParsedHtml>();

    var thread = new Thread(() =>
    {
        ParsedHtml result = ParseHtml(untrustedHtml);
        tcs.TrySetResult(result);
    });
    thread.Start();

    using (cancellationToken.Register(() => tcs.TrySetCanceled()))
    {
        try
        {
            return await tcs.Task;
        }
        catch (OperationCanceledException)
        {
            thread.Abort();
            throw;
        }
    }
}

L'idée pourrait être étendue pour être plus efficace en réutilisant les threads dans le cas réussi, plutôt que de déclencher et de supprimer un thread pour chaque page HTML.



Related

Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow