A little while back I noticed a problem with using Apache's Tomcat servlet engine to serve the web content my Palm pilot application. At that time, I thought the problem was with the way that Tomcat creates session IDs. That is incorrect. The problem is an obscure bug in the HTTP generated by the PQA/Proxy browser.

The problem was what I consider to be an obscure bug in the content sent by the Palm for a blank password input element. If a, b, and c are the names of three input elements, and b is a password input element (<input type="password" name="b" value="">), then, if the password is left blank (displays on the Palm as "-Unassigned-" surrounded by a dotted-line rectangle), the Palm sends a string similar to the following for the "application/x-www-form-urlencoded" form data:

a=v1&b&c=v2
Note that there is no equal sign ("=") after the b. This is contrary to my reading of the spec at http://www.w3.org/MarkUp/html-spec/html-spec_8.html#SEC8.2.1.

As it happens, the Jetty servlet engine interprets this to mean that b should have a blank value. Tomcat, due to its use of Sun's HttpUtils.parseQueryString() method, signals an error, which returns a 500 error code to the Palm.

The Palm should instead send:

a=v1&b=&c=v2
or leave out the b value entirely:
a=v1&c=v2
Of course it would also be nice for Tomcat to be a little more forgiving here, like Jetty. That's how I fixed the problem, by patching the parseQueryString() method.

How did I figure this out?

I looked at a bunch of protocol sniffers, none of which quite did the job, especially since the only way I can get the proxy to browse my web server is via a phone line; the office firewall defeats both the emulator going out and the Palm proxy coming back in. Since the protocol sniffers I found seem to work only on the ethernet card, they don't work for me. They're tough to use, too.

Yesterday I came on the idea of using a simple proxy. There is a nice page of proxies at http://www.ijs.co.nz/sorm.htm. I used a Java proxy called TCP Reflector: http://locutus.kingwoodcable.com/jfd/java/tcp/tcp.html. This proxy allows you to set up a server on one TCP port that will pass all traffic through to another machine and port. You can optionally echo all the traffic on the console. I set it to map port 80 to port 8080 on the same machine, and configured Tomcat to serve on port 8080 (Tomcat is a web server as well as a servlet engine). Presto! Within 10 minutes I had generated the following transcript, which led me right to the problem.

<HTML><HEAD><TITLE>Login</TITLE>
<META NAME="PalmComputingPlatform" CONTENT="true">
</HEAD>
<BODY >
<FORM ACTION="/uim/UIM_s200011141659153/uthlogin.p" METHOD="POST"><TABLE><TR><TD
>User name:</TD
><TD><input type="text" name="a" size="10" maxlength="10"  value="shaker"></TD
></TR
><TR><TD>Password:</TD
><TD><input type="password" name="b" size="12" maxlength="12"  value=""></TD
></TR
><TR><TD>Database:</TD
><TD><SELECT NAME="c"><OPTION VALUE="0">a1 - Valley's database<OPTION VALUE="1">a9<OPTION VALUE="2">b1 - BBL's database for testing (Mine U)<OPTION VALUE="3">b7 - Brinderson<OPTION VALUE="4">bu - Butler's Accounting Db for QA (MU)<OPTION VALUE="5">d0 - Empty Master - Do not delete or update!<OPTION VALUE="6">d1 - SingCO, No   Div, No   Ctr<OPTION VALUE="7">d6 - Grand Construction<OPTION VALUE="8">d8 - Accounting database connected to summary files db<OPTION VALUE="9">d9<OPTION VALUE="10">e1 - Ecker testing database<OPTION VALUE="11">e3 - testing Energysystems<OPTION VALUE="12">g1 - Gale Work Order QA - << DO NOT USE >><OPTION VALUE="13">h3 - hooper co 3<OPTION VALUE="14">j2 - Butler's Accounting DB<OPTION VALUE="15">k2 - Aspen Demo DB<OPTION VALUE="16">p1 - Web Application test database<OPTION SELECTED VALUE="17">p2 - Pike's scaled down p1 db for EIS demo<OPTION VALUE="18">q6 - QA Database - copy of d6<OPTION VALUE="19">r1 - Dicks ARGON Test DB<OPTION VALUE="20">s1 - Master sales database<OPTION VALUE="21">s9<OPTION VALUE="22">t1</SELECT
></TD
></TR
></TABLE
>
<br>
<TABLE><TR></TR
><TR><TD><input type="submit" name="d" value="OK"></TD
><TD><input type="submit" name="e" value="Cancel"></TD
></TR
></TABLE
></FORM
></BODY></HTML>
########################################################################
# Thu Dec 14 16:59:21 EST 2000
# TCPReflector
# Removing connection from: 209.247.202.105/209.247.202.105:80
# To                      : localhost/127.0.0.1:8080
########################################################################

########################################################################
# Thu Dec 14 16:59:31 EST 2000
# TCPReflector
# Connection initiated from: 209.247.202.105/209.247.202.105
########################################################################
########################################################################
# Thu Dec 14 16:59:31 EST 2000
# TCPReflector
# Connection established from: 209.247.202.105/209.247.202.105:80
# To                         : localhost/127.0.0.1:8080
########################################################################

[src  => dest, (355 bytes)]
POST /uim/UIM_s200011141659153/uthlogin.p HTTP/1.0
user-agent: Mozilla/2.0 (compatible; Elaine/1.1)
Accept: text/html, image/jpeg, image/gif
Content-Type: application/x-www-form-urlencoded
X-Forwarded-For: 192.168.166.5
Host: 205.231.148.68
Content-Length: 20
Via: 1.1 wp01dlsvl (NetCache 4.0R4D11)
Connection: Keep-Alive

a=shaker&b&c=17&d=OK

[dest => src, (202 bytes)]
HTTP/1.0 500 Internal Server Error
Content-Type: text/html
Servlet-Engine: Tomcat Web Server/3.2 (final) (JSP 1.1; Servlet 2.2; Java 1.3.0;
 Windows 2000 5.0 x86; java.vendor=Sun Microsystems Inc.)

[dest => src, (1596 bytes)]
<h1>Error: 500</h1>
<h2>Location: /uim/UIM_s200011141659153/uthlogin.p</h2><b>Internal Servlet Error
:</b><br><pre>java.lang.IllegalArgumentException
[9]at javax.servlet.http.HttpUtils.parseQueryString(HttpUtils.java:151)
[9]at javax.servlet.http.HttpUtils.parsePostData(HttpUtils.java:254)
...