I first wrote a simple client and server program, and tested them against each other, so that I would have the ability to detect problems on each side that were caused by the other side.
When I extended my client program to implement HTTP, I tested it against the department Web server, so that I could see the format of the server responses, and make sure that my requests were formed correctly.
One problem that this uncovered was that my client was only waiting for one packet of data, whereas a full resource might be sent over several. I modified the client to parse the Content-Length header, so that it could determine when all the data had been sent.
There are resources for which Apache does not provide a Content-Length, however, and I found that for these, calling recv() after all the data had been sent would return 0, signalling the end of the data. I modified the client to select between the two criteria by the presence or absence of a Content-Length field.
The suggested URL from the department server loaded fine; looking at the Content-Type field reminded me to have the client reject any types that are not text.
While implementing HTTP in the server, I mostly used the client to connect to it, so that I could see the details of the headers that were returned, and so that I could purposely cause various errors. Having seen the problem before with resources larger than a single send(), I implemented content-length calculations and reporting in the server.
I then used Netscape to test my server. Here I found a problem I have not been able to solve. Although my server correctly reports Content-Length, and closes the connection when it has finished, Netscape loads the page but then continues to wait for something. Lynx, similarly, is waiting for something -- its status line reading, Read 113 of 113 bytes. I am still not sure what the problem is with this, but my client handles it fine, as it stops trying to recv() after it has received Content-Length bytes.
I also used Netscape to make several requests at once (loading images on a page). Although the server does not actually handle images, it dealt with concurrent connections correctly.
I tested both programs against the programs of colleague Joo Hi Lee. Her client had the same problem with my server, in that it continued to wait for something. Without seeing the source code, I am not sure what problem this causes. As for her server, my client connects to it just fine, so this does not point to any problems.
Each of my programs does extensive error checking. The server returns appropriate status codes with explanatory resource bodies, and the client recognizes status codes and also deals with unrecognized codes by their classification. The server is threaded and handles requests concurrently; the client can make multiple requests sequentially.