Esempio n. 1
0
/*****************************************************************************
  Function:
	HTTP_IO_RESULT HTTPExecutePost(void)

  	This function processes every POST request from the pages. 
  ***************************************************************************/
HTTP_IO_RESULT HTTPExecutePost(void)
{
// Resolve which function to use and pass along
	BYTE filename[20];
	int len;
	// Load the file name
	// Make sure BYTE filename[] above is large enough for your longest name
	MPFSGetFilename(curHTTP.file, filename, sizeof(filename));
	while(curHTTP.byteCount)
	{
		// Check for a complete variable
		len = TCPFind(sktHTTP, '&', 0, FALSE);
		if(len == 0xffff)
		{
			// Check if is the last post, otherwise continue in the loop
			if( TCPIsGetReady(sktHTTP) == curHTTP.byteCount)
				len = curHTTP.byteCount - 1;
			else 
			{	
				return HTTP_IO_NEED_DATA; // No last post, we need more data
			}
		}

	 
		if(len > HTTP_MAX_DATA_LEN - 2)
		{
			// Make sure we don't overflow
			curHTTP.byteCount -= TCPGetArray(sktHTTP, (BYTE*)String_post, len+1);
			continue;
		}

		len = TCPGetArray(sktHTTP,curHTTP.data, len+1);

		curHTTP.byteCount -= len;
		curHTTP.data[len] = '\0';
		HTTPURLDecode(curHTTP.data);
		
		//	NETWORK TYPE SELECTION: ADHOC/INFRASTRUCTURE/SOFTAP(WIFI G only)
		if(memcmppgm2ram(curHTTP.data,(ROM void*)"NETTYPE", 7) == 0)
		{
			memcpy(String_post,(void*)&curHTTP.data[8], len-8);			
			WFSetParam(NETWORK_TYPE, String_post);
		}		  
		
		//	DHCP CLIENT ENABLING/DISABLING
		else if(memcmppgm2ram(curHTTP.data,(ROM void*)"DHCPCL", 6) == 0)
		{
			memcpy(String_post,(void*)&curHTTP.data[7], len-7);
			if (String_post [0] == 'd')
				WFSetParam(DHCP_ENABLE , DISABLED);
			else 
				WFSetParam(DHCP_ENABLE , ENABLED);
		}	
			
		//	IP ADDRESS OF THE DEVICE
		else if(memcmppgm2ram(curHTTP.data,(ROM void*)"IPADDR", 6) == 0)
		{
			memcpy(String_post,(void*)&curHTTP.data[7], len-7);
			WFSetParam(MY_IP_ADDR, String_post);
		}			
				
		//	SUBNET MASK
		else if(memcmppgm2ram(curHTTP.data,(ROM void*)"SUBNET", 6) == 0)
		{
			memcpy(String_post,(void*)&curHTTP.data[7], len-7);
			WFSetParam(SUBNET_MASK, String_post);
		}		
				
		//	DEFAULT GATEWAY 
		else if(memcmppgm2ram(curHTTP.data,(ROM void*)"GATEWAY", 7) == 0)
		{
			memcpy(String_post,(void*)&curHTTP.data[8], len-8);
			WFSetParam(MY_GATEWAY, String_post); 
		}	
					
		//	DNS SERVER #1
		else if(memcmppgm2ram(curHTTP.data,(ROM void*)"DNS1", 4) == 0)
		{
			memcpy(String_post,(void*)&curHTTP.data[5], len-5);
			WFSetParam(PRIMARY_DNS, String_post);
		}
						
		//	DNS SERVER #2
		else if(memcmppgm2ram(curHTTP.data,(ROM void*)"DNS2", 4) == 0)
		{
			memcpy(String_post,(void*)&curHTTP.data[5], len-5);
			WFSetParam(SECONDARY_DNS, String_post);
		}
									
		//	SSID 
		else if(memcmppgm2ram(curHTTP.data,(ROM void*)"SSID", 4) == 0)
		{
			memcpy(String_post,(void*)&curHTTP.data[5], len-5);
			WFSetParam(SSID_NAME, String_post); 
		}
								
		//	SECURITY TYPE
		else if(memcmppgm2ram(curHTTP.data,(ROM void*)"SECTYPE", 7) == 0)
		{
			memcpy(String_post,(void*)&curHTTP.data[8], len-8);
			
			if (String_post[2] == 'E')
			{
				security = 0;
				WFSetSecurity(WF_SECURITY_OPEN, "", 0, 0);
				ParamSet = TRUE;
			}
			else if (String_post[2] == 'A')
			{
				if (String_post[3] == '2')
					security = 5;
				else 
					security = 3;
			}
			else if (String_post[2] == 'P') 
			{
				if (String_post[3] == '4')
					security = 1;
				else 
					security = 2;
			}			
		}
		
		//	----------	SECURITY KEY AND PASSWORD	----------	
		
		//	WEP40 KEY
		else if (memcmppgm2ram(curHTTP.data,(ROM void*)"WEP40KEY4", 9) == 0)
		{
			if (security == 1)
			{
				if (len > 10)
				{
					int j = 0, j1 = 0;
					WORD_VAL dummy;
					for ( j=0; j<40; j=j+2)
					{
						memcpy(String_post,(void*)&curHTTP.data[10+j], 2);
					
						dummy.v[1] =  String_post[0];
						dummy.v[0] =  String_post[1];
						PassKey[j1] = hexatob(dummy);
						j1++;
					}
					PassKey[j1]= '\0';
					security = 1;
				}
			}
		}
		
		//	WEP40 KEY INDEX
		else if (memcmppgm2ram(curHTTP.data,(ROM void*)"WEP40KEYID", 10) == 0)
		{	
			memcpy(String_post,(void*)&curHTTP.data[11], len-11);
			
			int k_index;
			k_index = atoi(String_post);
			k_index--;
			if (security == 1)
			{
				WFSetSecurity(WF_SECURITY_WEP_40, PassKey, 20, k_index);
				ParamSet = TRUE;
			}
		}
		
		//	WEP104 KEY INDEX
		else if (memcmppgm2ram(curHTTP.data,(ROM void*)"WEP104KEY", 9) == 0)
		{
			if (security == 2)
			{
				int j = 0, j1 = 0;
				WORD_VAL dummy;
				for ( j=0; j<32; j=j+2)
				{
					memcpy(String_post,(void*)&curHTTP.data[10+j], 2);
					
					dummy.v[1] =  String_post[0];
					dummy.v[0] =  String_post[1];
					PassKey[j1] = hexatob(dummy);
					j1++;
				}
				PassKey[j1]= '\0';
				WFSetSecurity(WF_SECURITY_WEP_104, PassKey, 16, 0);	
				ParamSet = TRUE;
			}
			
		}
		
		//	WPA WITH PASSPHRASE
		else if (memcmppgm2ram(curHTTP.data,(ROM void*)"WPAPASS", 7) == 0)
		{	
			if (security == 3)
			{
				if (len > 10)
				{
					memcpy(String_post,(void*)&curHTTP.data[8], len-8);									
					WFSetSecurity(WF_SECURITY_WPA_WITH_PASS_PHRASE, String_post, len-9, 0);
					ParamSet = TRUE;
				}
			}
		}

		//	WPA WITH PASSKEY
		else if (memcmppgm2ram(curHTTP.data,(ROM void*)"WPAKEY", 6) == 0)
		{	
			if (security == 3)
			{
				if (len > 10)
				{
					int j = 0, j1 = 0;
					WORD_VAL dummy;
					for ( j=0; j<64; j=j+2)
					{
						memcpy(String_post,(void*)&curHTTP.data[7+j], 2);
						
						dummy.v[1] =  String_post[0];
						dummy.v[0] =  String_post[1];
						PassKey[j1] = hexatob(dummy);
						j1++;
					}
					PassKey[j1]= '\0';
					WFSetSecurity(WF_SECURITY_WPA_WITH_KEY, PassKey, 32, 0);
					ParamSet = TRUE;
				}
			}
		}
		
		//	WPA2 WITH PASSPHRASE
		else if (memcmppgm2ram(curHTTP.data,(ROM void*)"WPA2PASS", 8) == 0)
		{	
			if (len > 10)
			{
				memcpy(String_post,(void*)&curHTTP.data[9], len-9);
							
				WFSetSecurity(WF_SECURITY_WPA2_WITH_PASS_PHRASE, String_post, len-9, 0);
				ParamSet = TRUE;
			}
		}
		
		//	WPA2 WITH PASSKEY
		else if (memcmppgm2ram(curHTTP.data,(ROM void*)"WPA2KEY", 7) == 0)
		{	
			if (len > 10)
			{
				int j = 0, j1 = 0;
				WORD_VAL dummy;
				for ( j=0; j<64; j=j+2)
				{
					memcpy(String_post,(void*)&curHTTP.data[8+j], 2);

					dummy.v[1] =  String_post[0];
					dummy.v[0] =  String_post[1];
					PassKey[j1] = hexatob(dummy);
					j1++;
				}
				PassKey[j1]= '\0';
				WFSetSecurity(WF_SECURITY_WPA2_WITH_KEY, PassKey, 32, 0);
				ParamSet = TRUE;
			}
		}

		/* EMAIL */
		else if (memcmppgm2ram(curHTTP.data,(ROM void*)"TXEMAIL", 7) == 0)
		{	
			memcpy(MY_EMAIL,(void*)&curHTTP.data[8], len-8);
		}
		else if (memcmppgm2ram(curHTTP.data,(ROM void*)"USEREMAIL", 9) == 0)
		{	
			memcpy(MY_EMAIL_USER,(void*)&curHTTP.data[10], len-10);
		}
		else if (memcmppgm2ram(curHTTP.data,(ROM void*)"PASSEMAIL", 9) == 0)
		{	
			memcpy(MY_EMAIL_PASS,(void*)&curHTTP.data[10], len-10);
		}
		else if (memcmppgm2ram(curHTTP.data,(ROM void*)"SERVER", 6) == 0)
		{	
			memcpy(MY_SMTP,(void*)&curHTTP.data[7], len-7);
		}
		else if (memcmppgm2ram(curHTTP.data,(ROM void*)"PORT", 4) == 0)
		{	
			memcpy(MY_SMTP_PORT,(void*)&curHTTP.data[5], len-5);
		}
		else if (memcmppgm2ram(curHTTP.data,(ROM void*)"SUBJ", 4) == 0)
		{	
			memcpy(EMAIL_SUBJECT,(void*)&curHTTP.data[5], len-5);
		}
		else if (memcmppgm2ram(curHTTP.data,(ROM void*)"TEXT", 4) == 0)
		{	
			memcpy(EMAIL_BODY,(void*)&curHTTP.data[5], len-5);
		}
		else if (memcmppgm2ram(curHTTP.data,(ROM void*)"RXEMAIL", 7) == 0)
		{	
			memcpy(EMAIL_DEST,(void*)&curHTTP.data[8], len-8);
		}	
		
		/* ALARM */
		else if (memcmppgm2ram(curHTTP.data,(ROM void*)"GMT", 3) == 0)
		{	
			memcpy(GMT,(void*)&curHTTP.data[4], len-4);
		}
		else if (memcmppgm2ram(curHTTP.data,(ROM void*)"START", 5) == 0)
		{	
			memcpy(start_string,(void*)&curHTTP.data[6], len-6);
		}
		else if (memcmppgm2ram(curHTTP.data,(ROM void*)"STOP", 4) == 0)
		{	
			memcpy(stop_string,(void*)&curHTTP.data[5], len-5);
		}
	}
	
	return HTTP_IO_DONE;
}
Esempio n. 2
0
/*********************************************************************
 * Function:        static void HTTPProcess(void)
 *
 * PreCondition:    HTTPInit() called and curHTTP loaded
 *
 * Input:           None
 *
 * Output:          None
 *
 * Side Effects:    None
 *
 * Overview:		Serves the current HTTP connection in curHTTP
 *
 * Note:            None
 ********************************************************************/
static void HTTPProcess(void)
{
    WORD lenA, lenB;
	BYTE c, i;
    BOOL isDone;
	BYTE *ext;
	BYTE buffer[HTTP_MAX_HEADER_LEN+1];

    do
    {
        isDone = TRUE;

        // If a socket is disconnected at any time 
        // forget about it and return to idle state.
        if(TCPWasReset(sktHTTP))
        {
            smHTTP = SM_HTTP_IDLE;

			// Make sure any opened files are closed
			if(curHTTP.file != MPFS_INVALID_HANDLE)
			{
				MPFSClose(curHTTP.file);
				curHTTP.file = MPFS_INVALID_HANDLE;
			}
			if(curHTTP.offsets != MPFS_INVALID_HANDLE)
			{
				MPFSClose(curHTTP.offsets);
				curHTTP.offsets = MPFS_INVALID_HANDLE;
			}

			// Adjust the TCP FIFOs for optimal reception of 
			// the next HTTP request from the browser
			TCPAdjustFIFOSize(sktHTTP, 1, 0, TCP_ADJUST_GIVE_REST_TO_RX | TCP_ADJUST_PRESERVE_RX);
        }


        switch(smHTTP)
        {

        case SM_HTTP_IDLE:

			// Check how much data is waiting
			lenA = TCPIsGetReady(sktHTTP);

			// If a connection has been made, then process the request
            if(lenA)
            {// Clear out state info and move to next state
				curHTTP.ptrData = curHTTP.data;
				smHTTP = SM_HTTP_PARSE_REQUEST;
				curHTTP.isAuthorized = 0xff;
				curHTTP.hasArgs = FALSE;
				curHTTP.callbackID = TickGet() + HTTP_TIMEOUT*TICK_SECOND;
				curHTTP.callbackPos = 0xffffffff;
				curHTTP.byteCount = 0;
			}
			
			// In all cases, we break
			// For new connections, this waits for the buffer to fill
			break;

		case SM_HTTP_PARSE_REQUEST:

			// Verify the entire first line is in the FIFO
			if(TCPFind(sktHTTP, '\n', 0, FALSE) == 0xffff)
			{// First line isn't here yet
				if(TCPGetRxFIFOFree(sktHTTP) == 0)
				{// If the FIFO is full, we overflowed
					curHTTP.httpStatus = HTTP_OVERFLOW;
					smHTTP = SM_HTTP_SERVE_HEADERS;
					isDone = FALSE;
				}
				if(TickGet() > curHTTP.callbackID)
				{// A timeout has occurred
					TCPDisconnect(sktHTTP);
					smHTTP = SM_HTTP_DISCONNECT;
					isDone = FALSE;
				}
				break;
			}

			// Reset the watchdog timer
			curHTTP.callbackID = TickGet() + HTTP_TIMEOUT*TICK_SECOND;

			// Determine the request method
			lenA = TCPFind(sktHTTP, ' ', 0, FALSE);
			if(lenA > 5)
				lenA = 5;
			TCPGetArray(sktHTTP, curHTTP.data, lenA+1);

		    if ( memcmppgm2ram(curHTTP.data, (ROM void*)"GET", 3) == 0)
			    curHTTP.httpStatus = HTTP_GET;
			#if defined(HTTP_USE_POST)
		    else if ( memcmppgm2ram(curHTTP.data, (ROM void*)"POST", 4) == 0)
			    curHTTP.httpStatus = HTTP_POST;
			#endif
		    else
			{// Unrecognized method, so return not implemented
		        curHTTP.httpStatus = HTTP_NOT_IMPLEMENTED;
				smHTTP = SM_HTTP_SERVE_HEADERS;
				isDone = FALSE;
				break;
			}

			// Find end of filename
			lenA = TCPFind(sktHTTP, ' ', 0, FALSE);
			lenB = TCPFindEx(sktHTTP, '?', 0, lenA, FALSE);
			lenA = mMIN(lenA, lenB);
			
			// If the file name is too long, then reject the request
			if(lenA > HTTP_MAX_DATA_LEN - HTTP_DEFAULT_LEN - 1)
			{
				curHTTP.httpStatus = HTTP_OVERFLOW;
				smHTTP = SM_HTTP_SERVE_HEADERS;
				isDone = FALSE;
				break;
			}

			// Read in the filename and decode
			lenB = TCPGetArray(sktHTTP, curHTTP.data, lenA);
			curHTTP.data[lenB] = '\0';
			HTTPURLDecode(curHTTP.data);
			
			// Check if this is an MPFS Upload
			#if defined(HTTP_MPFS_UPLOAD)
			if(memcmppgm2ram(&curHTTP.data[1], HTTP_MPFS_UPLOAD, strlenpgm(HTTP_MPFS_UPLOAD)) == 0)
			{// Read remainder of line, and bypass all file opening, etc.
				#if defined(HTTP_USE_AUTHENTICATION)
				curHTTP.isAuthorized = HTTPAuthenticate(NULL, NULL, &curHTTP.data[1]);
				#endif
				if(curHTTP.httpStatus == HTTP_GET)
					curHTTP.httpStatus = HTTP_MPFS_FORM;
				else
					curHTTP.httpStatus = HTTP_MPFS_UP;

				smHTTP = SM_HTTP_PARSE_HEADERS;
				isDone = FALSE;
				break;
			}
			#endif
			
			// If the last character is a not a directory delimiter, then try to open the file
			// String starts at 2nd character, because the first is always a '/'
			if(curHTTP.data[lenB-1] != '/')
				curHTTP.file = MPFSOpen(&curHTTP.data[1]);
				
			// If the open fails, then add our default name and try again
			if(curHTTP.file == MPFS_INVALID_HANDLE)
			{
				// Add the directory delimiter if needed
				if(curHTTP.data[lenB-1] != '/')
					curHTTP.data[lenB++] = '/';
				
				// Add our default file name			
				// If this is a loopback, then it's an SSL connection
				if(TCPIsLoopback(sktHTTP))
				{
					strcpypgm2ram((void*)&curHTTP.data[lenB], HTTPS_DEFAULT_FILE);
					lenB += strlenpgm(HTTPS_DEFAULT_FILE);
				}
				else
				{
					strcpypgm2ram((void*)&curHTTP.data[lenB], HTTP_DEFAULT_FILE);
					lenB += strlenpgm(HTTP_DEFAULT_FILE);
				}
					
				// Try to open again
				curHTTP.file = MPFSOpen(&curHTTP.data[1]);
			}
			
			// Find the extension in the filename
			for(ext = curHTTP.data + lenB-1; ext != curHTTP.data; ext--)
				if(*ext == '.')
					break;
					
			// Compare to known extensions to determine Content-Type
			ext++;
			for(curHTTP.fileType = HTTP_TXT; curHTTP.fileType < HTTP_UNKNOWN; curHTTP.fileType++)
				if(!stricmppgm2ram(ext, (ROM void*)httpFileExtensions[curHTTP.fileType]))
					break;
			
			// Perform first round authentication (pass file name only)
			#if defined(HTTP_USE_AUTHENTICATION)
			curHTTP.isAuthorized = HTTPAuthenticate(NULL, NULL, &curHTTP.data[1]);
			#endif
			
			// If the file was found, see if it has an index
			if(curHTTP.file != MPFS_INVALID_HANDLE &&
				(MPFSGetFlags(curHTTP.file) & MPFS2_FLAG_HASINDEX) )
			{
				curHTTP.data[lenB-1] = '#';
				curHTTP.offsets = MPFSOpen(&curHTTP.data[1]);
			}

			// Read GET args, up to buffer size - 1
			lenA = TCPFind(sktHTTP, ' ', 0, FALSE);
			if(lenA != 0)
			{
				curHTTP.hasArgs = TRUE;
				
				// Trash the '?'
				TCPGet(sktHTTP, &c);

				// Verify there's enough space
				lenA--;
				if(lenA >= HTTP_MAX_DATA_LEN - 2)
				{
			        curHTTP.httpStatus = HTTP_OVERFLOW;
					smHTTP = SM_HTTP_SERVE_HEADERS;
					isDone = FALSE;
					break;
				}

				// Read in the arguments and '&'-terminate in anticipation of cookies
				curHTTP.ptrData += TCPGetArray(sktHTTP, curHTTP.data, lenA);
				*(curHTTP.ptrData++) = '&';

			}

			// Clear the rest of the line
			lenA = TCPFind(sktHTTP, '\n', 0, FALSE);
			TCPGetArray(sktHTTP, NULL, lenA + 1);

			// Move to parsing the headers
			smHTTP = SM_HTTP_PARSE_HEADERS;
			
			// No break, continue to parsing headers

		case SM_HTTP_PARSE_HEADERS:

			// Loop over all the headers
			while(1)
			{
				// Make sure entire line is in the FIFO
				lenA = TCPFind(sktHTTP, '\n', 0, FALSE);
				if(lenA == 0xffff)
				{// If not, make sure we can receive more data
					if(TCPGetRxFIFOFree(sktHTTP) == 0)
					{// Overflow
						curHTTP.httpStatus = HTTP_OVERFLOW;
						smHTTP = SM_HTTP_SERVE_HEADERS;
						isDone = FALSE;
					}
					if(TickGet() > curHTTP.callbackID)
					{// A timeout has occured
						TCPDisconnect(sktHTTP);
						smHTTP = SM_HTTP_DISCONNECT;
						isDone = FALSE;
					}
					break;
				}
				
				// Reset the watchdog timer
				curHTTP.callbackID = TickGet() + HTTP_TIMEOUT*TICK_SECOND;
				
				// If a CRLF is immediate, then headers are done
				if(lenA == 1)
				{// Remove the CRLF and move to next state
					TCPGetArray(sktHTTP, NULL, 2);
					smHTTP = SM_HTTP_AUTHENTICATE;
					isDone = FALSE;
					break;
				}
	
				// Find the header name, and use isDone as a flag to indicate a match
				lenB = TCPFindEx(sktHTTP, ':', 0, lenA, FALSE) + 2;
				isDone = FALSE;
	
				// If name is too long or this line isn't a header, ignore it
				if(lenB > sizeof(buffer))
				{
					TCPGetArray(sktHTTP, NULL, lenA+1);
					continue;
				}
				
				// Read in the header name
				TCPGetArray(sktHTTP, buffer, lenB);
				buffer[lenB-1] = '\0';
				lenA -= lenB;
		
				// Compare header read to ones we're interested in
				for(i = 0; i < HTTP_NUM_HEADERS; i++)
				{
					if(strcmppgm2ram((char*)buffer, (ROM char *)HTTPRequestHeaders[i]) == 0)
					{// Parse the header and stop the loop
						HTTPHeaderParseLookup(i);
						isDone = TRUE;
						break;
					}
				}
				
				// Clear the rest of the line, and call the loop again
				if(isDone)
				{// We already know how much to remove unless a header was found
					lenA = TCPFind(sktHTTP, '\n', 0, FALSE);
				}
				TCPGetArray(sktHTTP, NULL, lenA+1);
			}
			
			break;

		case SM_HTTP_AUTHENTICATE:
		
			#if defined(HTTP_USE_AUTHENTICATION)
			// Check current authorization state
			if(curHTTP.isAuthorized < 0x80)
			{// 401 error
				curHTTP.httpStatus = HTTP_UNAUTHORIZED;
				smHTTP = SM_HTTP_SERVE_HEADERS;
				isDone = FALSE;
				
				#if defined(HTTP_NO_AUTH_WITHOUT_SSL)
				if(!TCPIsLoopback(sktHTTP))
					curHTTP.httpStatus = HTTP_SSL_REQUIRED;
				#endif

				break;
			}
			#endif

			// Parse the args string
			*curHTTP.ptrData = '\0';
			curHTTP.ptrData = HTTPURLDecode(curHTTP.data);

			// If this is an MPFS upload form request, bypass to headers
			#if defined(HTTP_MPFS_UPLOAD)
			if(curHTTP.httpStatus == HTTP_MPFS_FORM)
			{
				smHTTP = SM_HTTP_SERVE_HEADERS;
				isDone = FALSE;
				break;
			}
			#endif
			
			// Move on to GET args, unless there are none
			smHTTP = SM_HTTP_PROCESS_GET;
			if(!curHTTP.hasArgs)
				smHTTP = SM_HTTP_PROCESS_POST;
			isDone = FALSE;
			curHTTP.hasArgs = FALSE;
			break;

		case SM_HTTP_PROCESS_GET:

			// Run the application callback HTTPExecuteGet()
			if(HTTPExecuteGet() == HTTP_IO_WAITING)
			{// If waiting for asynchronous process, return to main app
				break;
			}

			// Move on to POST data
			smHTTP = SM_HTTP_PROCESS_POST;

		case SM_HTTP_PROCESS_POST:

			#if defined(HTTP_USE_POST)
			
			// See if we have any new data
			if(TCPIsGetReady(sktHTTP) == curHTTP.callbackPos)
			{
				if(TickGet() > curHTTP.callbackID)
				{// If a timeout has occured, disconnect
					TCPDisconnect(sktHTTP);
					smHTTP = SM_HTTP_DISCONNECT;
					isDone = FALSE;
					break;
				}
			}
			
			if(curHTTP.httpStatus == HTTP_POST 
				#if defined(HTTP_MPFS_UPLOAD)
				|| (curHTTP.httpStatus >= HTTP_MPFS_UP && curHTTP.httpStatus <= HTTP_MPFS_ERROR)
				#endif
				 )
			{
				// Run the application callback HTTPExecutePost()
				#if defined(HTTP_MPFS_UPLOAD)
				if(curHTTP.httpStatus >= HTTP_MPFS_UP && curHTTP.httpStatus <= HTTP_MPFS_ERROR)
				{
					c = HTTPMPFSUpload();
					if(c == HTTP_IO_DONE)
					{
						smHTTP = SM_HTTP_SERVE_HEADERS;
						isDone = FALSE;
						break;
					}
				}
				else
				#endif
				c = HTTPExecutePost();
				
				// If waiting for asynchronous process, return to main app
				if(c == HTTP_IO_WAITING)
				{// return to main app and make sure we don't get stuck by the watchdog
					curHTTP.callbackPos = TCPIsGetReady(sktHTTP) - 1;
					break;
				} else if(c == HTTP_IO_NEED_DATA)
				{// If waiting for more data
					curHTTP.callbackPos = TCPIsGetReady(sktHTTP);
					curHTTP.callbackID = TickGet() + HTTP_TIMEOUT*TICK_SECOND;
					// If more is expected and space is available, return to main app
					if(curHTTP.byteCount > 0 && TCPGetRxFIFOFree(sktHTTP) != 0)
						break;
					else
					{// Handle cases where application ran out of data or buffer space
						curHTTP.httpStatus = HTTP_INTERNAL_SERVER_ERROR;
						smHTTP = SM_HTTP_SERVE_HEADERS;
						isDone = FALSE;
						break;
					}	
				}
			}
			#endif

			// We're done with POST
			smHTTP = SM_HTTP_PROCESS_REQUEST;
			// No break, continue to sending request

		case SM_HTTP_PROCESS_REQUEST:

			// Check for 404
            if(curHTTP.file == MPFS_INVALID_HANDLE)
            {
                curHTTP.httpStatus = HTTP_NOT_FOUND;
                smHTTP = SM_HTTP_SERVE_HEADERS;
                isDone = FALSE;
                break;
            }

			// Set up the dynamic substitutions
			curHTTP.byteCount = 0;
			if(curHTTP.offsets == MPFS_INVALID_HANDLE)
            {// If no index file, then set next offset to huge
	            curHTTP.nextCallback = 0xffffffff;
            }
            else
            {// Read in the next callback index
	            MPFSGetLong(curHTTP.offsets, &(curHTTP.nextCallback));
			}
			
			// Move to next state
			smHTTP = SM_HTTP_SERVE_HEADERS;

		case SM_HTTP_SERVE_HEADERS:

			// We're in write mode now:
			// Adjust the TCP FIFOs for optimal transmission of 
			// the HTTP response to the browser
			TCPAdjustFIFOSize(sktHTTP, 1, 0, TCP_ADJUST_GIVE_REST_TO_TX);
				
			// Send headers
			TCPPutROMString(sktHTTP, (ROM BYTE*)HTTPResponseHeaders[curHTTP.httpStatus]);
			
			// If this is a redirect, print the rest of the Location: header			   
			if(curHTTP.httpStatus == HTTP_REDIRECT)
			{
				TCPPutString(sktHTTP, curHTTP.data);
				TCPPutROMString(sktHTTP, (ROM BYTE*)"\r\n\r\n304 Redirect: ");
				TCPPutString(sktHTTP, curHTTP.data);
				TCPPutROMString(sktHTTP, (ROM BYTE*)HTTP_CRLF);
			}

			// If not GET or POST, we're done
			if(curHTTP.httpStatus != HTTP_GET && curHTTP.httpStatus != HTTP_POST)
			{// Disconnect
				smHTTP = SM_HTTP_DISCONNECT;
				break;
			}

			// Output the content type, if known
			if(curHTTP.fileType != HTTP_UNKNOWN)
			{
				TCPPutROMString(sktHTTP, (ROM BYTE*)"Content-Type: ");
				TCPPutROMString(sktHTTP, (ROM BYTE*)httpContentTypes[curHTTP.fileType]);
				TCPPutROMString(sktHTTP, HTTP_CRLF);
			}
			
			// Output the gzip encoding header if needed
			if(MPFSGetFlags(curHTTP.file) & MPFS2_FLAG_ISZIPPED)
			{
				TCPPutROMString(sktHTTP, (ROM BYTE*)"Content-Encoding: gzip\r\n");
			}
						
			// Output the cache-control
			TCPPutROMString(sktHTTP, (ROM BYTE*)"Cache-Control: ");
			if(curHTTP.httpStatus == HTTP_POST || curHTTP.nextCallback != 0xffffffff)
			{// This is a dynamic page or a POST request, so no cache
				TCPPutROMString(sktHTTP, (ROM BYTE*)"no-cache");
			}
			else
			{// This is a static page, so save it for the specified amount of time
				TCPPutROMString(sktHTTP, (ROM BYTE*)"max-age=");
				TCPPutROMString(sktHTTP, (ROM BYTE*)HTTP_CACHE_LEN);
			}
			TCPPutROMString(sktHTTP, HTTP_CRLF);
			
			// Check if we should output cookies
			if(curHTTP.hasArgs)
				smHTTP = SM_HTTP_SERVE_COOKIES;
			else
			{// Terminate the headers
				TCPPutROMString(sktHTTP, HTTP_CRLF);
				smHTTP = SM_HTTP_SERVE_BODY;
			}
	
			// Move to next stage
			isDone = FALSE;
			break;

		case SM_HTTP_SERVE_COOKIES:

			#if defined(HTTP_USE_COOKIES)
			// If the TX FIFO runs out of space, the client will never get CRLFCRLF
			// Avoid writing huge cookies - keep it under a hundred bytes max

			// Write cookies one at a time as space permits
			for(curHTTP.ptrRead = curHTTP.data; curHTTP.hasArgs != 0; curHTTP.hasArgs--)
			{
				// Write the header
				TCPPutROMString(sktHTTP, (ROM BYTE*)"Set-Cookie: ");

				// Write the name, URL encoded, one character at a time
				while((c = *(curHTTP.ptrRead++)))
				{
					if(c == ' ')
						TCPPut(sktHTTP, '+');
					else if(c < '0' || (c > '9' && c < 'A') || (c > 'Z' && c < 'a') || c > 'z')
					{
						TCPPut(sktHTTP, '%');
						TCPPut(sktHTTP, btohexa_high(c));
						TCPPut(sktHTTP, btohexa_low(c));
					}
					else
						TCPPut(sktHTTP, c);
				}
				
				TCPPut(sktHTTP, '=');
				
				// Write the value, URL encoded, one character at a time
				while((c = *(curHTTP.ptrRead++)))
				{
					if(c == ' ')
						TCPPut(sktHTTP, '+');
					else if(c < '0' || (c > '9' && c < 'A') || (c > 'Z' && c < 'a') || c > 'z')
					{
						TCPPut(sktHTTP, '%');
						TCPPut(sktHTTP, btohexa_high(c));
						TCPPut(sktHTTP, btohexa_low(c));
					}
					else
						TCPPut(sktHTTP, c);
				}
				
				// Finish the line
				TCPPutROMString(sktHTTP, HTTP_CRLF);

			}
			#endif

			// We're done, move to next state
			TCPPutROMString(sktHTTP, HTTP_CRLF);
			smHTTP = SM_HTTP_SERVE_BODY;

		case SM_HTTP_SERVE_BODY:

			isDone = FALSE;

			// Try to send next packet
			if(HTTPSendFile())
			{// If EOF, then we're done so close and disconnect
				MPFSClose(curHTTP.file);
				curHTTP.file = MPFS_INVALID_HANDLE;
				smHTTP = SM_HTTP_DISCONNECT;
				isDone = TRUE;
			}
			
			// If the TX FIFO is full, then return to main app loop
			if(TCPIsPutReady(sktHTTP) == 0)
				isDone = TRUE;
            break;

		case SM_HTTP_SEND_FROM_CALLBACK:

			isDone = TRUE;

			// Check that at least the minimum bytes are free
			if(TCPIsPutReady(sktHTTP) < HTTP_MIN_CALLBACK_FREE)
				break;

			// Fill TX FIFO from callback
			HTTPPrint(curHTTP.callbackID);
			
			if(curHTTP.callbackPos == 0)
			{// Callback finished its output, so move on
				isDone = FALSE;
				smHTTP = SM_HTTP_SERVE_BODY;
			}// Otherwise, callback needs more buffer space, so return and wait
			
			break;

		case SM_HTTP_DISCONNECT:
		
			// Loopbacks have no wait state, so all data must be retrieved first
			if(TCPIsLoopback(sktHTTP) && TCPGetTxFIFOFull(sktHTTP) != 0)
				break;

			// Make sure any opened files are closed
			if(curHTTP.file != MPFS_INVALID_HANDLE)
			{
				MPFSClose(curHTTP.file);
				curHTTP.file = MPFS_INVALID_HANDLE;
			}
			if(curHTTP.offsets != MPFS_INVALID_HANDLE)
			{
				MPFSClose(curHTTP.offsets);
				curHTTP.offsets = MPFS_INVALID_HANDLE;
			}

			TCPDisconnect(sktHTTP);
            smHTTP = SM_HTTP_IDLE;
            break;
		}
	} while(!isDone);

}