The compiled web in the Digibutler software includes the page "variables.htm", which reloads itself every second or so. I observed that with Internet Explorer (IE) this process would stop after some unpredictable time, whereas with Firefox it would usually survive for days.
After a stop, the server would still be alife and accept a new request.
So, how could it tell IE from Firefox ?
The only difference I could think of was the contents of the request the user agent (a technical name for the navigator) was sending to the server, a collection of data called a header.
A header is made of a number of lines, each with the syntax :
data_name: data_value
except for the first and the last lines.
The last line is blank and is used to terminate the header.
The first line specifies the access method, the name of the requested file and the protocol :
GET /variables.htm HTTP/1.1
That is the only line that's useful to our little server.
A typical header sent by IE is as following :
GET /variables.htm HTTP/1.1 Accept: image/jpeg, application/x-ms-application, image/gif, application/xaml+xml, image/pjpeg, application/x-ms-xbap, application/x-shockwave-flash, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword,
Accept-Language: fr-FR User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; Trident/4.0; SLCC2; .NET CLR 2.0.507
27; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0;.NET4.0C) Accept-Encoding: gzip, deflate
Host: 192.168.1.59
Connection: Keep-Alive
The size of this one is 474 bytes, and it is probably not the largest !
Now let's look within module "freescale_http.c" at function "freescale_http_read_header(…)", where the received header is read with the code :
length = m_recv( freescale_http_sessions[session].socket, (char *)buffer, RECV_BUFFER_SIZE );
The size of the receive buffer is defined within module "freescale_http_server.h" :
//*****************************************
// Receive buffer, DO NOT CHANGE!!!
//*****************************************
#define RECV_BUFFER_SIZE 0x100
This is 256 bytes, much smaller than the received 474 bytes.
This means that the TCP/IP stack will keep the rest and return it on the next call of m_receiv().
If this call is assumed to return a new header, we'll process garbage, which we may detect as such or not (in the best case we can't satisfy an invalid request and return a "page not found" error, effectively creating the condition we started with), therefore we should discard the data in excess by calling m_receiv() repeatedly until the end-of-header line is found.
But m_receiv() has got to copy the data to some buffer. Of course, we could allocate a buffer from the stack, but this would increase the usage of the stack, not the best solution.
If we accept to limit the size of the file name (including ?forms) to a manageable 160 characters, the first header line would never exceed 192 bytes, so we could use the last 25% of the receive buffer to throw away the garbage.
The modified function "freescale_http_read_header(…)" would be as following :
void freescale_http_read_header( int session, char *buffer )
{
HEADER_TYPES i;
int length, j, k;
if(session>MAX_NUMBER_OF_SESSIONS){
freescale_http_sessions[session].state = EMG_HTTP_STATE_CLOSE;
return;
}
if( freescale_http_sessions[session].keep_alive )
freescale_http_sessions[session].keep_alive--;
// PARAM1: M_SOCK socket,
// PARAM2: char * buffer
// PARAM3: unsigned length
//
// RETURNS: number of bytes actually read, or -1 if error.
// int m_recv(M_SOCK so, char * buf, unsigned buflen) // commented out - HM 23-aug-11
length = m_recv( freescale_http_sessions[session].socket, buffer, RECV_BUFFER_SIZE );
if( length < 0 )
{
// if( !freescale_http_sessions[session].keep_alive )
freescale_http_sessions[session].state = EMG_HTTP_STATE_CLOSE;
return;
}
// ******************************************************************************
// Discard header data in excess
// As the headers supplied by the user agents tend to inflate, they have overgrown
// the size of the receive buffer. Only the first header line is of interest to us,
// the rest can safely be discarded.
// A scratch zone at the end of the receive buffer is used to store the header data
// in excess. It is overwritten by calls to m_recv until the returned data is
// shorter than expected or is terminated by a blank line (double CR/LF).
// Note : it is assumed that the useful data does never overflow into the
// scratch zone. This limits the size of the scratch zone, which should be large
// to limit processing overhead.
#define EXCESS (RECV_BUFFER_SIZE/4) // size of scratch zone at end of buffer
if (length >= RECV_BUFFER_SIZE) // if smaller, there is no excess data
do {
// The following test takes care of the possibility that the returned data fills the
// the scratch zone exactly, meaning there is no more data to receive.
if ((buffer[RECV_BUFFER_SIZE-4] == 13) &&
(buffer[RECV_BUFFER_SIZE-3] == 10) &&
(buffer[RECV_BUFFER_SIZE-2] == 13) &&
(buffer[RECV_BUFFER_SIZE-1] == 10)) break;
} while (EXCESS == m_recv( freescale_http_sessions[session].socket,
&buffer[RECV_BUFFER_SIZE-EXCESS], EXCESS));
// ******************************************************************************
// Scan through the buffer looking for the method
for( i=NO_HEADER_FOUND; header_table.header_string[0]; i++ )
{
if(i > 3) /* empty or invalid header */
{
freescale_http_sessions[session].state = EMG_HTTP_STATE_CLOSE;
return;
}
for( j=0, k=0; j < 8; j++ ) // the name of the method must be within the 7 first chars
{
if( buffer[j] == header_table.header_string[k] )
k++;
if( header_table.header_string[k] == 0 )
{
#if HTTP_VERBOSE>3
printf( "\n6 header[%d] = %s", session, &header_table.header_string[0] );
#endif
freescale_http_sessions[session].headertype = header_table.header_type;
// header = freescale_http_sessions[session].headertype;
#if 0
// Scan to /
for( ; j<length; j++ )
{
if( buffer[j] == '/' )
{
freescale_process_header( session , &buffer[++j], length-j );
return;
}
}
// If we get here, we did not find the '/'
// Just send the default file
buffer[0] = ' ';
#endif
freescale_process_header( session , buffer, length );
return;
}
}
}
// If we get here, then
// We do not support the method 'GET', 'POST', 'EMG'
// The only thing we can do is close the socket
freescale_http_sessions[session].state = EMG_HTTP_STATE_CLOSE;
}