A common problem faced by ISAPI Filter writers that buffer/modify HTTP response is to ensure that this code works for all of the valid formats of HTTP responses that can be sent by the web server.

Question:

*) Can you suggest any tools / techniques that will enable me to test all code paths.  At the moment i am at the mercy of the servers in that they determine what the response format should be, i need to thoroughly test my chunked code, content-length code and non-content length.

Answer:

Sure. The following ASP page will generate all of the valid HTTP response formats to allow you to test your handling of chunked, content-length, and non-content-length (i.e. connection close) responses.

The ASP page takes in three parameters via querystring to generate the variety of valid HTTP response formats. Syntax:

  • chunksize - the bytes of response data per response chunk
  • numchunks - the number of response chunks to send
  • type - the format of the response. Either "chunk" for chunk-encoded, "cl" for content-lengith, or "neither" for neither header, just send data and close connection

Sample requests and outputs:

  • Sends 5 chunks of 10 bytes each, keep-alive possible
    WWWConnect::Connect("localhost","80")\n
    source port: 3725\n
    REQUEST: **************\n
    GET /output.asp?chunksize=10&numchunks=5&type=chunk HTTP/1.1\r\n
    Host: localhost\r\n
    Accept: */*\r\n
    \r\n
    RESPONSE: **************\n
    HTTP/1.1 200 OK\r\n
    Server: Microsoft-IIS/5.0\r\n
    Date: Mon, 15 Aug 2005 11:39:18 GMT\r\n
    Content-Type: text/html\r\n
    Set-Cookie: ASPSESSIONIDASTATTTA=PIMPPEJBIMEGJLHOBNPHMIDC; path=/\r\n
    Cache-control: private\r\n
    Transfer-Encoding: chunked\r\n
    \r\n
    a\r\n
    XXXXXXXXXX\r\n
    a\r\n
    XXXXXXXXXX\r\n
    a\r\n
    XXXXXXXXXX\r\n
    a\r\n
    XXXXXXXXXX\r\n
    a\r\n
    XXXXXXXXXX\r\n
    0\r\n
    \r\n
    finished.
    
  • Sends 50 bytes with content-length, keep-alive possible
    REQUEST: **************\n
    GET /output.asp?chunksize=10&numchunks=5&type=cl HTTP/1.1\r\n
    Host: localhost\r\n
    Accept: */*\r\n
    \r\n
    RESPONSE: **************\n
    HTTP/1.1 200 OK\r\n
    Server: Microsoft-IIS/5.0\r\n
    Date: Mon, 15 Aug 2005 11:39:59 GMT\r\n
    Content-Length: 50\r\n
    Content-Type: text/html\r\n
    Set-Cookie: ASPSESSIONIDASTATTTA=AJMPPEJBCGEMEKINJEKEKAJO; path=/\r\n
    Cache-control: private\r\n
    \r\n
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    finished.
    
  • Sends 50 bytes without content-length and closes connection afterwards
    REQUEST: **************\n
    GET /output.asp?chunksize=10&numchunks=5&type=neither HTTP/1.1\r\n
    Host: localhost\r\n
    Accept: */*\r\n
    \r\n
    RESPONSE: **************\n
    HTTP/1.1 200 OK\r\n
    Server: Microsoft-IIS/5.0\r\n
    Date: Mon, 15 Aug 2005 11:40:25 GMT\r\n
    Connection: close\r\n
    Content-Type: text/html\r\n
    Set-Cookie: ASPSESSIONIDASTATTTA=BJMPPEJBMAANLOOIBJEOJJBA; path=/\r\n
    Cache-control: private\r\n
    \r\n
    XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    WWWConnect::Close("localhost","80")\n
    closed source port: 3725\r\n
    finished.
    

Enjoy.

//David

<%
DIM i, outputType, szChunk, dwRepeat

outputType = UCASE( Request.QueryString( "type" ) )
szChunk = STRING( CINT( Request.QueryString( "chunksize" ) ), "X" )
dwRepeat = CINT( Request.QueryString( "numchunks" ) )

IF outputType = "CHUNK" THEN
    Response.Buffer = false
ELSEIF outputType = "CL" THEN
    Response.Buffer = true
ELSE
    Response.Buffer = true
    Response.Flush
END IF

FOR i = 1 TO dwRepeat
    Response.Write szChunk
NEXT
%>