Oops - PDI handshake delay was too long, causing the device's /RESET functionality...
[pub/USBasp.git] / Projects / Webserver / Lib / HTTPServerApp.c
index 3f8a2c3..5f0b2cf 100644 (file)
@@ -96,62 +96,64 @@ void WebserverApp_Callback(void)
        char*                     AppData     = (char*)uip_appdata;\r
        uint16_t                  AppDataSize = 0;\r
 \r
-       if (uip_aborted() || uip_timedout())\r
-       {\r
-               /* Close the file before terminating, if it is open */\r
-               f_close(&AppState->FileToSend);\r
-\r
-               AppState->CurrentState = WEBSERVER_STATE_Closed;\r
-\r
-               return;\r
-       }\r
-       else if (uip_closed())\r
+       if (uip_aborted() || uip_timedout() || uip_closed())\r
        {\r
+               /* Check if the open file needs to be closed */\r
+               if (AppState->FileOpen)\r
+               {\r
+                       f_close(&AppState->FileHandle);\r
+                       AppState->FileOpen = false;\r
+               }\r
+\r
+               AppState->PrevState    = WEBSERVER_STATE_Closed;\r
                AppState->CurrentState = WEBSERVER_STATE_Closed;\r
 \r
                return;\r
        }\r
        else if (uip_connected())\r
        {\r
-               /* New connection - initialize connection state and data pointer to the appropriate HTTP header */\r
+               /* New connection - initialize connection state values */\r
+               AppState->PrevState    = WEBSERVER_STATE_OpenRequestedFile;\r
                AppState->CurrentState = WEBSERVER_STATE_OpenRequestedFile;\r
+               AppState->FileOpen     = false;\r
+       }\r
+       else if (uip_rexmit())\r
+       {\r
+               /* Re-try last state */\r
+               AppState->CurrentState = AppState->PrevState;\r
        }\r
        \r
        switch (AppState->CurrentState)\r
        {\r
                case WEBSERVER_STATE_OpenRequestedFile:\r
                        /* Wait for the packet containing the request header */\r
-                       if (uip_datalen())\r
+                       if (uip_newdata())\r
                        {\r
+                               char* RequestToken = strtok(AppData, " ");\r
+                       \r
                                /* Must be a GET request, abort otherwise */\r
-                               if (strncmp(AppData, "GET ", (sizeof("GET ") - 1)) != 0)\r
+                               if (strcmp(RequestToken, "GET") != 0)\r
                                {\r
                                        uip_abort();\r
                                        break;\r
                                }\r
                \r
-                               /* Copy over the requested filename from the GET request as all-lowercase */\r
-                               for (uint8_t i = 0; i < (sizeof(AppState->FileName) - 1); i++)\r
-                               {\r
-                                       AppState->FileName[i] = tolower(AppData[sizeof("GET ") + i]);\r
-                                       \r
-                                       if (AppState->FileName[i] == ' ')\r
-                                       {\r
-                                               AppState->FileName[i] = 0x00;\r
-                                               break;\r
-                                       }\r
-                               }\r
+                               char* RequestedFileName = strtok(NULL, " ");\r
                                \r
-                               /* Ensure requested filename is null-terminated */\r
-                               AppState->FileName[(sizeof(AppState->FileName) - 1)] = 0x00;\r
-                               \r
-                               /* If no filename specified, assume the default of index.htm */\r
-                               if (AppState->FileName[0] == 0x00)\r
+                               /* If the requested filename has more that just the leading '/' path in it, copy it over */\r
+                               if (strlen(RequestedFileName) > 1)\r
+                                 strncpy(AppState->FileName, &RequestedFileName[1], (sizeof(AppState->FileName) - 1));\r
+                               else\r
                                  strcpy(AppState->FileName, "index.htm");\r
+\r
+                               /* Ensure filename is null-terminated */\r
+                               AppState->FileName[(sizeof(AppState->FileName) - 1)] = 0x00;\r
                                \r
                                /* Try to open the file from the Dataflash disk */\r
-                               AppState->FileOpen = (f_open(&AppState->FileToSend, AppState->FileName, FA_OPEN_EXISTING | FA_READ) == FR_OK);\r
+                               AppState->FileOpen       = (f_open(&AppState->FileHandle, AppState->FileName, FA_OPEN_EXISTING | FA_READ) == FR_OK);\r
+                               AppState->CurrentFilePos = 0;\r
 \r
+                               AppState->PrevState    = WEBSERVER_STATE_OpenRequestedFile;\r
                                AppState->CurrentState = WEBSERVER_STATE_SendResponseHeader;\r
                        }\r
 \r
@@ -169,8 +171,7 @@ void WebserverApp_Callback(void)
                                strncpy_P(AppData, HTTP404Header, AppDataSize);\r
                        }\r
                        \r
-                       uip_send(AppData, AppDataSize);\r
-                       \r
+                       AppState->PrevState    = WEBSERVER_STATE_SendResponseHeader;\r
                        AppState->CurrentState = WEBSERVER_STATE_SendMIMETypeHeader;\r
                        break;\r
                case WEBSERVER_STATE_SendMIMETypeHeader:\r
@@ -205,32 +206,45 @@ void WebserverApp_Callback(void)
                                /* Add the end-of line terminator and end-of-headers terminator after the MIME type */\r
                                strncpy(&AppData[AppDataSize], "\r\n\r\n", sizeof("\r\n\r\n"));\r
                                AppDataSize += (sizeof("\r\n\r\n") - 1);\r
-                               \r
-                               uip_send(AppData, AppDataSize);\r
                        }\r
                                \r
+                       AppState->PrevState    = WEBSERVER_STATE_SendMIMETypeHeader;\r
                        AppState->CurrentState = WEBSERVER_STATE_SendData;                              \r
                        break;\r
                case WEBSERVER_STATE_SendData:\r
                        /* If end of file/file not open, progress to the close state */\r
-                       if (!(AppState->FileOpen))\r
+                       if (!(AppState->FileOpen) && !(uip_rexmit()))\r
                        {\r
-                               f_close(&AppState->FileToSend);\r
+                               f_close(&AppState->FileHandle);\r
                                uip_close();\r
+\r
+                               AppState->PrevState    = WEBSERVER_STATE_Closed;\r
                                AppState->CurrentState = WEBSERVER_STATE_Closed;\r
                                break;\r
                        }\r
 \r
                        uint16_t MaxSegSize = uip_mss();\r
                        \r
+                       /* Return file pointer to the last ACKed position */\r
+                       f_lseek(&AppState->FileHandle, AppState->CurrentFilePos);\r
+\r
                        /* Read the next chunk of data from the open file */\r
-                       f_read(&AppState->FileToSend, AppData, MaxSegSize, &AppDataSize);\r
-                       AppState->FileOpen = (MaxSegSize == AppDataSize);\r
+                       f_read(&AppState->FileHandle, AppData, MaxSegSize, &AppDataSize);\r
+\r
+                       /* If we are not re-transmitting a lost segment, advance file position */\r
+                       if (uip_acked() && !(uip_rexmit()))\r
+                       {\r
+                               AppState->FileOpen = (AppDataSize > 0);\r
+                               AppState->CurrentFilePos += AppDataSize;\r
+                       }\r
+                       \r
+                       /* Stay in the SendData state if retransmission is required until all data sent */\r
+                       AppState->PrevState = WEBSERVER_STATE_SendData;\r
 \r
-                       /* If data was read, send it to the client */\r
-                       if (AppDataSize)\r
-                         uip_send(AppData, AppDataSize);\r
-                                       \r
                        break;\r
        }\r
+\r
+       /* If data has been loaded into the application buffer by the server, send it to the client */\r
+       if (AppDataSize)\r
+         uip_send(AppData, AppDataSize);\r
 }\r