Nouvelles Chroniques d'Amethyste

Penser au Sens, pas au Verbe

Owin/Katana: quelques pièges

Poster un commentaire

Le petit pipeline suivant a l’air bien innocent, mais est porteur de nombreux problèmes potentiels comme nous allons le voir:

 


app.Use(async (context, next) =>
{
    string message = "<h1>Hello Fredo1</h1>";
    context.Response.ContentType = "text/html;charset=utf-8";

    await context.Response.WriteAsync(message);
    await next.Invoke();
});

app.Use(async (context, next) =>
{
    string message = "<h1>Hello Fredo2</h1>";
    context.Response.ContentType = "text/html;charset=utf-8";

    await context.Response.WriteAsync(message);
    await next.Invoke();
});

 

Si on l’exécute il s’affiche:

Hello Fredo1

Hello Fredo2

 

Donc tout à l’air d’aller bien. Pourquoi s’inquiéter?

C’est précisément ce que nous allons étudier dans cet article qui concerne d’ailleurs aussi bien Katana que n’importe quelle application Web.

Note: pour des raisons qui seront plus claire dans l’article qui suit, les exemples seront lancé dans le contexte d’un hébergement Console.

  • Première modification, il serait peut être bien de préciser un Content-Length ce qui permet aux navigateurs de faire quelques optimisations. Et donc nous écrivons:

app.Use(async (context, next) =>
{
    string message = "<h1>Hello Fredo 1</h1>";
    context.Response.ContentType = "text/html;charset=utf-8";
    context.Response.ContentLength = message.Length;

    await context.Response.WriteAsync(message);
    await next.Invoke();
});

app.Use(async (context, next) =>
{
    string message = "<h1>Hello Fredo 2</h1>";
    context.Response.ContentType = "text/html;charset=utf-8";
    context.Response.ContentLength = message.Length;

    await context.Response.WriteAsync(message);
    await next.Invoke();
});

 

Mais cette fois l’affichage n’est plus que:

Hello Fredo1

 

Le placement d’un point d’arrêt montre pourtant que le deuxième middleware s’exécute normalement, mais où passe son message?

 

La norme HTTP 1.1 précise le comportement selon que Content-Length est fournit ou non.

Content-Length est le poids en octets du message transmit. Dès que cette taille est atteinte, le navigateur « sait » qu’il a reçu la totalité du message est ferme la connexion.

C’est ce qui explique que dans le deuxième essai nous ne recevons que le premier message. Au moment où le deuxième middleware commence à émettre, il n’y a plus de connexion ou en tout cas quelqu’un pour écouter.

 

Il est possible, comme nous l’avons vu, de ne pas fournir la taille du message. Dans ce cas le navigateur passe en mode Encodage de Transfert en Bloc (Chunked Transfert Encoding). Dans ce mode la connexion ne se referme pas, elle reste active et le serveur pour continuer à envoyer des messages. C’est très précisément ce que nous observons lors du premier essai.

On différencie ces deux modes en examinant l’en-tête Http.

Dans le premier cas:

25-04-2014 23-08-55

Dans le deuxième cas, rien de spécial:

25-04-2014 23-10-21

Si on ne souhaite pas utiliser le mode chunked, on doit être attentif quand à la déclaration faite quand à la taille du buffer.

 

  • Remplaçons maintenant cette chaîne:

string message = "<h1>Hello Fredo 1</h1>";

context.Response.ContentLength = message.Length;

 

Par:


string message = "<h1>Hello Frédo 1</h1>";
context.Response.ContentLength = message.Length;

Un simple accent de différence. Mais qui suffit à faire planter le site!

 

Que se passe t’il?

Passer la taille c’est bien, mais encore faut t’il qu’elle soit exacte.

.Net encode en UTF-16 tandis que nous transmettons de l’UTF-8 et c’est là qu’est le problème. La taille n’est pas la même dans les deux cas.

La façon correcte de transmettre la taille est la suivante.


context.Response.ContentLength = Encoding.UTF8.GetBytes(message).Length;

Ou encore:


context.Response.ContentLength = Encoding.UTF8.GetByteCount(message);

 

Et vous constaterez que tout rentre dans l’ordre.

 

Dans l’article qui suit, nous allons approfondir la façon dont fonctionne le flux Http et en particulier parler des modes streaming ou bufférisés.

 

 

 

 

 

 

 

 

Publicités

Laisser un commentaire

Entrez vos coordonnées ci-dessous ou cliquez sur une icône pour vous connecter:

Logo WordPress.com

Vous commentez à l'aide de votre compte WordPress.com. Déconnexion / Changer )

Image Twitter

Vous commentez à l'aide de votre compte Twitter. Déconnexion / Changer )

Photo Facebook

Vous commentez à l'aide de votre compte Facebook. Déconnexion / Changer )

Photo Google+

Vous commentez à l'aide de votre compte Google+. Déconnexion / Changer )

Connexion à %s