Archivo de la etiqueta: Windows

Pasar URL a minúsculas con nginx

[spanish]

Con nginx y el módulo de Perl embebido es posible reescribir/redirigir todas las visitas a URL en minúsculas añadiendo algo como esto a la configuración:

http {

	...
	perl_modules  perl/lib;

 	perl_set $uri_lowercase 'sub {
   		my $r = shift;
   		my $uri = $r->uri;
   		$uri = lc($uri);
   		return $uri;
 	}';
	...
}

server {
	...

	location / {
               if ( $uri != $uri_lowercase ) {
                       rewrite . http://$host$uri_lowercase;
               }
# or just:
#		rewrite . $uri_lowercase;
	}
	...
}

La primera opción (con el if y el http://$host) genera una redirección HTTP a la URL en minúscula si la URL que pide el cliente no está ya toda en minúscula. Me gusta más esta técnica ya que de alguna forma normaliza todas las URL a una forma canónica en minúsculas. La segunda opción (sin el if ni el http://) simplemente acepta cualquier URL y la reescribe internamente a minúsculas. Si previamente se renombran todos los ficheros y directorios a minúsculas se consigue un efecto «case insensitive» similar al de Windows.

Quiero dar las gracias al siguiente post de la lista de usuarios de nginx en el que me he inspiarado ;D para conseguir hacer esto. En efecto, la documentación y ejemplos del módulo de Perl de nginx son muy escasos. :-(

http://forum.nginx.org/read.php?2,39425,39944

De todas formas esta solución tiene dos problemas:

  • Hace falta el módulo de Perl que según los propios desarrolladores es experimental y puede tener memory leaks.
  • Aunque la redirección se hace en el location que esté el rewrite, el cálculo de la URL en minúscula al estar en la sección «http» de la configuración se hace para todas las peticiones que lleguen al servidor, haya que cambiarles la URL o no. Es decir, si tienes un servidor virtual con 10 dominios y sólo en una parte de uno de ellos es necesario reescribir las URL, aunque sólo se redirija el tráfico en ese caso, la URL en minúscula se calcula para todas las peticiones de todos los dominios.

Supongo que si en lugar de definir la variable en minúscula se escribiera una función Perl si que se podría restringir a un location determinado, tengo que mirarlo con más detenimiento aunque con la poca documentación que hay de esto la cosa está chunga. Otra opción es escribir un módulo en C que lo haga.

¿Y por qué querría alguien reescribir todas las URL a minúsculas? En el trabajo estamos migrando una aplicación Tomcat vieja desarrollada y que hasta ahora corría en un servidor Windows a Linux, y parece ser que los desarrolladores originales no prestaron nada de atención al tema de las mayúsculas y minúsculas en los nombres de ficheros y directorios, enlazando a veces bien los ficheros según mayúsculas y minúsculas pero otras veces no. Esto en Windows no es un problema, pero en Linux si que lo es. Así que lo que hemos hecho ha sido renombrarlo todo a minúsculas y configurar esta redirección a minúsculas en los servidores nginx que tenemos delante de la granja de Tomcats. Aún así todavía quedan algunos casos problemáticos aislados que han tenido que ser tratados uno a uno, como includes en los JSP a ficheros en mayúsculas (estos casos no «salen» al nginx si no que los trata internamente Tomcat, con lo que la redirección no se aplica), pero el grueso de los accesos a imágenes, videos, páginas HTML estáticas, etc. mal enlazados se ha solucionado de un plumazo sin tener que tocar el código.

[/spanish][english]

With nginx and its embedded Perl module it is possible to automatically rewrite/redirect every incoming request to a lowercase URL with something like this:

http {
	...
	perl_modules  perl/lib;

 	perl_set $uri_lowercase 'sub {
   		my $r = shift;
   		my $uri = $r->uri;
   		$uri = lc($uri);
   		return $uri;
 	}';
	...
}

server {
	...

	location / {
               if ( $uri != $uri_lowercase ) {
                       rewrite . http://$host$uri_lowercase;
               }
# or just:
#		rewrite . $uri_lowercase;
	}
	...
}

The first option (with the if and http://$host) sends an HTTP redirect to the lowercase URL if the requested URL is not completely in lowercase. I like this approach better as it kind of normalizes all URL to a canonical form. The second option (without if nor http://) just accepts any URL and internally rewrites them to lowercase: if you rename all your directories and files to lowercase, this will imitate Windows’ case-insensitive behaviour.

Kudos to the following post on the nginx users list were I draw the «inspiration» :D from to get this done. The embedded perl doc and examples are indeed scarce. :-(

http://forum.nginx.org/read.php?2,39425,39944

Anyway I see two problems in this approach:

  • you need the embedded perl module which according to the docs is experimental and can lead to memory leaks.
  • the actual redirection is done with the rewrite, which you can put on the location you need. But the URL lowercase calculation, being on the «http» section of the config, is done for each and every request arriving to your server. Say you have a virtual server with 10 domains and you only need this on one particular location of one of them. The lowercase URL is going to be calculated for every request of every domain.

I guess that by defining a perl function the URL calculation could be restricted to a particular location, have to look into it further. Another option is writing a C module.

And why would anybody want to rewrite every URL to lowercase? We’re migrating a legacy Tomcat-based application from Windows to Linux, and it seems the original developers were not «case-aware» at all, they mixed upper and lowercase in the filenames without regarding how the actual files were named. On Windows this is not a problem but when moving the app to Linux it is. So we have renamed every file and directory to lowercase and used the previous configuration on the nginx servers that load-balance our Tomcat farm. Some corner-cases remain (includes in JSP files, which don’t route back to the nginx server and are dealt internally by Tomcat) and have been dealt with one by one, but the bulk of wrongly addressed images, videos, links to HTML files, etc. now works.

[/english]

CrossOver de gratis y otras ¿apuestas? ¿o marketing?

CodeWeavers, los creadores de CrossOver, una versión comercial de Wine que permite ejecutar aplicaciones y juegos nativos de Windows en Linux y MacOS X hicieron una apuesta hace unas semanas: si el precio de la gasolina bajaba de cierto límite, durante un día iban a dar licencias gratis de su software. El precio ha bajado y ese día es hoy. El software se puede bajar de aquí y pedir la licencia aquí, que debido a la sobrecarga de los servidores no se podrá activar hasta mañana (y por lo visto, sólo mañana).

Yo la verdad este tipo de emuladores al final sólo los uso para poder ejecutar Internet Explorer en el Mac y probar cómo se ve alguna web o acceder a otra que le pegue una patada a los estándares y no funcione correctamente con otros navegadores. Y a pesar de que IE se puede instalar también con la versión libre de Darwine e incluso un tío se curró un script para automatizarlo, CrossOver está bastante más pulido y toda la instalación es más simplona, click-click-click y ya tienes el Explorer (o el Word, o el Acrobat, o …) en Mac.

Y esto me recuerda a esa empresa de refrescos que apostó que si Guns N’ Roses cumplía la fecha de noviembre de 2008 para el lanzamiento de su nuevo disco iba a regalar un refresco a cada estadounidense. ¿Qué es ésto? ¿Una nueva forma de márqueting viral? ¿Una forma de conseguir titulares (y entradas en blogs ;-D) de forma gratuita? El tema con CodeWeavers lo veo claro, total es la discusión de siempre, copiar un software no cuesta NADA y menos si se distribuye a través de Internet con lo que no hay un soporte físico, así que dar el software, durante un día… tal vez sirve para hinchar los números de usuarios reales, o para hacerse una idea de los usuairos que realmente tienen (¿cuántos que tienen CrossOver pirata lo «legalizarán» hoy?). Sin embargo los de los refrescos si que van a tener que dar las latas, una a una. Ahí si que hay un gasto. ¿Realmente se esperaban que Axl y compañía cumplieran, o les ha salido el tiro por la culata? Aunque aún está por ver que el disco salga a tiempo, que después de 15 años a ver quién se fia ahora. ;-)