Χρήση του URIEncoding στο Apache Tomcat για τις παραμέτρους GET

Εισαγωγή

Η σωστή παράδοση παραμέτρων από HTML φόρμες, όταν οι χαρακτήρες δεν ανήκουν στο λατινικό αλφάβητο, ήταν ένα πρόβλημα που για μεγάλο χρονικό διάστημα παίδευε τους προγραμματιστές ιστότοπων.

Ειδικά για τους προγραμματιστές σε Java JSP/Java Servlets, είχαν (σχετικά πρόσφατα) εμφανιστεί καλές λύσεις, και προβλέψεις στα σχετικά πρότυπα, που φάνηκαν να λύνουν οριστικά το πρόβλημα. Ο ίσως πλέον απλός κανόνας λέει να χρησιμοποιείται UTF-8 κωδικοποίηση (<%@ page contentType="text/html; charset=utf-8" pageEncoding="utf-8" %>) και η εντολή request.setCharacterEncoding("UTF-8").

Ένας από τους πλέον δημοφιλείς εξυπηρετητές για JSP/Servlet είναι ο Apache Tomcat ([1]). Με την έκδοση 5 όμως του Apache Tomcat, φάνηκε να άλλαξε ξαφνικά κάτι που είχε ως αποτέλεσμα να μη δουλεύει πλέον ο παραπάνω (καθιερωμένος) κανόνας!

Η αλλαγή αφορά μόνο τις παραμέτρους GET και στις λίστες επικοινωνίας εμφανίστηκαν πολλά μηνύματα παραπόνων και αρκετές υποβολές προβλημάτων (Bug Reports) σχετικά με το θέμα ([2]), αλλά οι ομάδα ανάπτυξης επέμενε για την ορθότητα της αλλαγής.

Με σκοπό τη δυνατότητα διατήρησης της συμβατότητας με προηγούμενες εκδόσεις του Tomcat, η μόνη υποχώρηση που έκανε η ομάδα ανάπτυξης, ήταν η ενσωμάτωση μίας παραμέτρου για τη ρύθμιση της εγκατάστασης η οποία εν μέρη βοηθάει στη διατήρηση της παλαιάς συμπεριφοράς.

Περιγραφή προβλήματος και γιατί πραγματικά είναι πρόβλημα

Το HTTP πρωτόκολλο ([3]), προβλέπει δύο διαφορετικούς τρόπους για να περάσουν παράμετροι (όνομα παραμέτρου και τιμή παραμέτρου) σε μία αίτηση προς τον εξυπηρετητή:

  1. Μέθοδος GET: οι παράμετροι περνάνε στα πλαίσια της διεύθυνσης της αίτησης (URI). Για παράδειγμα, στη διεύθυνση http://www.onoma.gr/index.jsp?onoma=timh υπάρχει μία παράμετρος με όνομα onoma και τιμή timh
  2. Μέθοδος POST: οι παράμετροι περνάνε στα πλαίσια του κυρίους σώματα της αίτησης και δε φαίνεται τίποτα στη διεύθυνση

Στην πράξη αυτό που γίνεται είναι οι εξυπηρετητές να λαμβάνουν μία σειρά από bytes και να τα μετατρέπουν σε συμβολοσειρές, σύμφωνα με μία κωδικοποίηση. Η κωδικοποίηση καθορίζει πόσα bytes θα χρησιμοποιηθούν για την αναπαράσταση ενός χαρακτήρα. Γνωστές κωδικοποιήσεις για ελληνικούς χαρακτήρες είναι για παράδειγμα windows-1253 (1 byte ανά χαρακτήρα) ή UTF-8 (μεταβλητός αριθμός byte ανά χαρακτήρα, υποστηρίζονται και χαρακτήρες άλλων αλφαβλήτων). (Να σημειωθεί σε αυτό το σημείο ότι στη μέθοδο GET κωδικοποιούνται ακόμα και τα byte. Έτσι βλέπουμε διευθύνσεις που περιέχουν χαρακτήρες της μορφής %ΧΧ όπου το XX είναι ο δεκαεξαδικός αριθμός ενός byte. Οπότε πρώτα γίνεται η αποκωδικοποίηση σε byte και μετά η αποκωδικοποίηση των byte σε χαρακτήρες).

Για τον καθορισμό της κωδικοποίησης που θα χρησιμοποιηθεί για την μετατροπή των byte σε χαρακτήρες, δεν υπάρχει κάποιο καθορισμένο πρότυπο! Οπότε αυτό που γίνεται είναι οι προγραμματιστές να ακολουθούν κάποιες συμβάσεις ή κανόνες. Για παράδειγμα, όταν οι εφαρμογές πλοήγησης όταν στέλνουν τις παραμέτρους μίας HTML φόρμας, χρησιμοποιούν για την κωδικοποίηση την κωδικοποίησης της σελίδας στην οποία υπήρχε η φόρμα. Οπότε οι προγραμματιστές καθορίζοντας την κωδικοποίηση της σελίδας στην οποία είναι η φόρμα, γνωρίζουν και ποια κωδικοποίηση θα χρησιμοποιήσουν για να διαβάσουν τις παραμέτρους.

Όταν χρησιμοποιούμε JSP ή Servlet, καθορίζουμε την κωδικοποίηση που θα χρησιμοποιηθεί με την εντολή request.setCharacterEncoding("XXX"), όπου αντί XXX βάζουμε την επιθυμητή κωδικοποίηση. Έτσι κάθε ακόλουθη κλήση του request.getParameter("onoma") θα χρησιμοποιήσει της κωδικοποίηση του XXX.

Τα παραπάνω άλλαξαν στον Apache Tomcat κάποια στιγμή στην έκδοση 5! Ενώ συνέχιζαν να λειτουργούν τα πράγματα με τον ίδιο τρόπο για παραμέτρους POST, σταμάτησαν να δουλεύουν για παραμέτρους GET.

Από τους πλέον ένθερμους υποστηρικτές της αλλαγής είναι ο Rémy Maucherat, κύριος προγραμματιστής του Tomcat. Παρόλο που η αλλαγή φαντάζει παράλογη (λειτουργούσε με τον παλιό τρόπο για πολύ καιρό, όπως και ένα σωρό άλλες παρόμοιες εφαρμογές), τα επιχειρήματα που προέβαλε είναι μάλλον σωστά.

Το πρόβλημα είναι το εξής:

Να σημειωθεί εδώ ότι οι διευθύνσεις των ιστότοπων μπορεί να αποτελούνται πλέον και από μη λατινικούς χαρακτήρες. Έστω για παράδειγμα ότι έχουμε έναν ιστότοπο με διεύθυνση www.ελλάδα.gr, στον οποίον υπάρχει μία σελίδα με κινέζικο περιεχόμενο κωδικοποίησης Big5. Εάν σε αυτή τη σελίδα υπάρχει μία φόρμα και στέλνονται παράμετροι με την μέθοδο GET, τότε θα έχουμε μία κατάσταση όπου το αρχικό τμήμα της διεύθυνσης πρέπει να σταλεί με κωδικοποίηση για ελληνικούς χαρακτήρες, και το υπόλοιπο τμήμα με κωδικοποίηση για τους κινέζικους χαρακτήρες.

Οπότε το πρόβλημα στη γενική του περίπτωση είναι όντως υπαρκτό!!!

Λύση για τον Apache Tomcat

Παρόλο που μετά από αρκετές συζητήσεις στις σχετικές λίστες αναγνωρίστηκε η ύπαρξη του προβλήματος, αναγνωρίστηκε επίσης από τους προγραμματιστές ότι είναι θεμιτή η δυνατότητα διατήρησης της προηγούμενης συμπεριφοράς.

Για αυτό το λόγο εισήγαγαν ένα νέο χαρακτηριστικό στη δήλωση του Connector στο αρχείο server.xml, το οποίο επιτρέπει τον καθορισμό της κωδικοποίησης που θα χρησιμοποιείται αντί της προκαθορισμένης ISO-8859-1.

Για παράδειγμα <Connector URIEncoding="UTF-8" port="8009" protocol="AJP/1.3" />

[1] Apache Tomcat
[2] Apache Tomcat Bug Reports 23929, 24345, 24557, 25231, 25235, 25360, 25848
[3] HTTP 1.1
[4] Berners-Lee, T., Fielding, R. and L. Masinter, Uniform Resource Identifiers (URI): Generic Syntax and Semantics, RFC 2396, August 1998. [jg645]

Φεβρουάριος 2007
Στέφανος Καρασαββίδης
sk at karasavvidis dot gr

Valid HTML 4.01!