Bienvenidos sean a este post, hoy veremos como escuchar la conversacion HTTP.
En este post vimos como es el objeto HTTPServer y como utilizarlo en conjunto con EventEmitter para crear un servidor que permite la entrega de aplicaciones web, en e post de hoy veremos como crear un modulo que nos permitira escuchar a todos los eventos del objeto y se puede convertir en una herramienta muy util para la depuracion asi como una demostracion de como opera el objeto.
En este post cuando hablamos sobre EventEmitter mencionamos que este objeto se utiliza mediante otro objeto, es decir que el objeto HTTPserver es nuestro EventEmitter y HTTP sniffer se encargara de escuchar cada evento en el servidor y mostrando la informacion de cada evento, para ello necesitaremos el codigo que vimos en este post y en caso de no tenerlo les dejo un link para descargarlo:
Extraigan el archivo en un directorio, una vez realizado esto deben crear en el mismo directorio un nuevo archivo con el nombre de sniffer.mjs y le agregaremos el siguiente codigo:
sniffer.mjs
import * as util from 'util';
import * as url from 'url';
const tiempoActual = () => { return new Date().toISOString(); }
export function sniffIni(servidor) {
servidor.on('request', (req, res) => {
console.log(`${tiempoActual()} request`);
console.log(`${tiempoActual()} ${solicitud(req)}`);
});
servidor.on('close',
errno => { console.log(`${tiempoActual()}
close errno=${errno}`); }
);
servidor.on('checkContinue', (req, res) => {
console.log(`${tiempoActual()} checkContinue`);
console.log(`${tiempoActual()} ${solicitud(req)}`);
res.writeContinue();
});
servidor.on('upgrade', (req, socket, head) => {
console.log(`${tiempoActual()} upgrade`);
console.log(`${tiempoActual()} ${solicitud(req)}`);
});
servidor.on('clientError', () => { console.log('clientError'); });
}
export function solicitud(req) {
var ret = `request ${req.method} ${req.httpVersion} ${req.url}` + '\n';
ret += JSON.stringify(url.parse(req.url, true)) + '\n';
var claves = Object.keys(req.headers);
for(var i=0; i < claves.length; i++)
{
var clave = claves[i];
ret += `${i} ${clave}: ${req.headers[clave]}` + '\n';
}
if (req.trailers)
ret += util.inspect(req.trailers) + '\n';
return ret;
}
Este sera el modulo que usaremos para «sniffear», en este caso primero importaremos dos modulos y luego definiremos una funcion donde devolveremos la hora y fecha actual, algo similar al timestamp que se utiliza en otros lenguajes y/o bases de datos, el metodo toISOString es para convertir el valor devuelto en un formato para poder ser manipulado con los otros metodos, despues tendremos dos funciones para trabajar, en ambos casos usaremos a export para poder ser importadas, analicemos la primera:
export function sniffIni(servidor) {
servidor.on('request', (req, res) => {
console.log(`${tiempoActual()} request`);
console.log(`${tiempoActual()} ${solicitud(req)}`);
});
servidor.on('close',
errno => { console.log(`${tiempoActual()}
close errno=${errno}`); }
);
servidor.on('checkContinue', (req, res) => {
console.log(`${tiempoActual()} checkContinue`);
console.log(`${tiempoActual()} ${solicitud(req)}`);
res.writeContinue();
});
servidor.on('upgrade', (req, socket, head) => {
console.log(`${tiempoActual()} upgrade`);
console.log(`${tiempoActual()} ${solicitud(req)}`);
});
servidor.on('clientError', () => { console.log('clientError'); });
}
Esta sera la funcion encargada de monitorear o «sniffear» los eventos de nuestro servidor, para ello recibira el objeto del servidor creado y mediante varios escuchadores procesaremos varios eventos, hablemos de cada uno de ellos:
- request, esta sera utilizado cada vez que nos conectemos a una pagina del servidor, indicaremos que es un request y por medio de la segunda funcion pasaremos todos los datos del request.
- close, este se emitira cuando se cierre el servidor y lo mostrara en pantalla con el codigo devuelto.
- checkContinue, este es un evento donde el servidor chequea si debe continuar y como, puede ser contenido o bien un codigo de error (400 bad gateway, por ejemplo)
- upgrade, este sera para el evento upgrade y se refiere a la actualizacion HTTP y al igual que la mayoria de los anteriores usaremos a la segunda funcion para mostrar lo procesado por el servidor
- clientError, en este caso lo usaremos para cuando sucede un error con el cliente y lo notificaremos
En todos los casos usaremos a la funcion definida anteriormente para indicar el tiempo seguido de la salida de la segunda funcion sobre cada solicitud que se hace al servidor, hablemos de la seguda funcion:
export function solicitud(req) {
var ret = `request ${req.method} ${req.httpVersion} ${req.url}` + '\n';
ret += JSON.stringify(url.parse(req.url, true)) + '\n';
var claves = Object.keys(req.headers);
for(var i=0; i < claves.length; i++)
{
var clave = claves[i];
ret += `${i} ${clave}: ${req.headers[clave]}` + '\n';
}
if (req.trailers)
ret += util.inspect(req.trailers) + '\n';
return ret;
}
Primero definiremos una variable con algunos datos del request, despues convertiremos a string todos los datos enviados en la url y lo agregaremos a la variable anteriror, lo siguiente sera definir un array donde tendremos todas las claves de la conexion como el host, user-agent, connection, etc, con esto creado nuestro siguiente paso sera usar un bucle for al cual le pasaremos por el array anterior y obtendremos cada clave y la agregaremos en la variable definida al comienzo y mediante esta clave cada valor asociado, por ultimo tenemos un condicional donde verifica si enviamos un dato adicional llamado trailers y en caso de ser verdadero lo agrega a la variable, por ultimo devolvemos la variable generada con toda la informacion, un ejemplo de valor de ret es el siguiente:
2023-10-06T15:38:51.042Z request
2023-10-06T15:38:51.054Z request GET 1.1 /
{"protocol":null,"slashes":null,"auth":null,"host":null,"port":null,"hostname":null,"hash":null,"search":null,"query":{},"pathname":"/","path":"/","href":"/"}
0 host: localhost:8124
1 user-agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Firefox/102.0
2 accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
3 accept-language: en-US,en;q=0.5
4 accept-encoding: gzip, deflate, br
5 connection: keep-alive
6 upgrade-insecure-requests: 1
7 sec-fetch-dest: document
8 sec-fetch-mode: navigate
9 sec-fetch-site: none
10 sec-fetch-user: ?1
{}
Este es nuestro modulo solo nos falta implementarlo, para ello deben ir al archivo server.mjs y al comienzo del mismo junto con los otros modulos importados agreguen la siguiente linea:
import { sniffIni } from './sniffer.mjs';
Esta se encargara de importar la funcion encargada del «sniffeo» del archivo anterior, la siguiente modificacion sera agregar el llamado a esta funcion para ello debemos modificar estas dos lineas:
server.listen(8124, '127.0.0.1');
console.log(`Servidor corriendo en http://127.0.0.1:8124`);
De la siguiente manera:
server.listen(8124, '127.0.0.1');
sniffIni(server);
console.log(`Escuchando a ${escucha}`);
Simplemente agregamos la nueva funcion, le pasamos el objeto del servidor y por ultimo cambiamos el mensaje de notificacion desde donde estamos escuchando, con esto comentado veamos como trabaja mediante el siguiente video
Observen como va variando los datos devueltos por cada request, en este caso seran muy similares entre si pero nos viene bien para observar como llega cada request al servidor pero lo principal sobre este codigo que tambien les puede ser util para ver los eventos en toda clase de objeto EventEmitter, antes de finalizar les dejo un archivo con los codigos trabajados en este post:
En resumen, hoy hemos visto como crear un «sniffer» para nuestro servidor, en realidad esta mas pensado mas en como monitorear los eventos de EventEmitter, para finalmente ver todos los datos que nos devuelve, espero les haya sido de utilidad sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.


Donación
Es para mantenimento del sitio, gracias!
$1.50
