The HTTP Response
Like the HTTP request, the response consists of CRLF terminated header lines with a blank line (a CRLF field immediately after the last header line), followed by the payload that is being returned as a result of a request.
The first line of the response contains the level of the HTTP protocol that the server is using, the return code to the request and a textual description of the return code. A typical return code response line might look like this (values separated by spaces):
HTTP/1.0 200 OK CRLF
Where HTTP/1.0 tells the client that the server is using the 1.0 version of the HTTP protocol, 200 means the request was processed successfully and OK is just a textual description of the return code.
Note that whilst a client may say it is using HTTP 1.1 in the request, there is nothing to prevent the server from using HTTP 1.0 in the response. The client should degrade to the 1.0 protocol gracefully, which makes it a lot easier to RYO web server.
Following the initial response line can be a number of other lines (each one terminated by a CRLF field) that specify information about the server and how it wants the client to handle the response. Each line has the format:
keyword: value CRLF
These are the additional fields that I include in a response header:
Date: Wed, 15 Nov 1995 06:25:24 GMT Server: server name/version Connection: Close Cache-control: no-cache Content-Type: content_type
For HTTP 1.0 I always set the connection state to Close. With HTTP 1.1 the client tries to keep the session open so that it can reuse it. If you have the architecture in your server environment to support this then fine but I find it safer to always close the connection after each request and response has been processed, and in fact that is the standard mode of operation for HTTP 1.0 anyway.
The Cache-control tells the client to NOT cache the data returned by this request. This works well in a development environment since you don’t have to remember to clear the browser cache every time you make a change on the host, however not all browsers seem to pay attention to it and may still cache some things, particularly IE when submitting forms with method=”GET” on them.
The Content-Type field tells the client what it is that you are returning, for example text/html or image/jpeg.
Following the CRLF of the last header line should be another CRLF field to create a blank line. After that comes the actual response data.
EBCDIC, ASCII and Binary
Special consideration come into play when running a web server on a z/OS system. Not least of which is that z/OS (at least on the non USS side of the wall) typically uses EBCDIC to encode character data whilst the rest of the world uses ASCII. So if you are using say ISPF to create your web pages and other resources, they will be encoded as EBCDIC. Similarly your server is going to create all the HTTP header stuff in EBCDIC.
Now there is a simple option on the z/OS TCP/IP socket interface that will cause TCP/IP to automatically convert outbound data from EBCDIC to ASCII and inbound data from ASCII to EBCDIC. So it’s easy right? Turn on that option and let TCP/P handle the conversion. But wait, what if you want to return say a JPEG image (assume you uploaded it to the host as binary so it does not need converting). You cannot leave the option on because TCP/IP will try to convert the binary of the image to ascii. You cannot turn it off because then the header will not be converted.
What you have to do is to split the sending of the response into two parts. When you send the header, including the blank line marker, you turn the option on so the text of the header gets converted. Then you turn the option off and send the binary payload part of the response.
Where is my CRLF
In the ascii world, a carriage return character is hex 0d and a line feed character is hex 09 but when translating from ASCII to EBCDIC, TCP/IP converts the line feed character to hex 25. Thus on inbound messages the CRLF field is the hex string ‘0d25′ on the host side of things. Similarly on outbound messages TCP/IP converts hex 25 in EBCDIC to hex 09 in ascii so when sending responses you have to code the CRLF string as x’0d25’ so that it gets converted to the correct ascii string when sent.
Of course you could turn off the built in conversion and implement your own translation, something you might need to do if you have special character sets but for good old latin, the default translation should be good enough.