diff options
Diffstat (limited to 'lib/lufa/Projects/Webserver/Lib/HTTPServerApp.c')
| -rw-r--r-- | lib/lufa/Projects/Webserver/Lib/HTTPServerApp.c | 284 |
1 files changed, 0 insertions, 284 deletions
diff --git a/lib/lufa/Projects/Webserver/Lib/HTTPServerApp.c b/lib/lufa/Projects/Webserver/Lib/HTTPServerApp.c deleted file mode 100644 index ba5ce8b99..000000000 --- a/lib/lufa/Projects/Webserver/Lib/HTTPServerApp.c +++ /dev/null | |||
| @@ -1,284 +0,0 @@ | |||
| 1 | /* | ||
| 2 | LUFA Library | ||
| 3 | Copyright (C) Dean Camera, 2017. | ||
| 4 | |||
| 5 | dean [at] fourwalledcubicle [dot] com | ||
| 6 | www.lufa-lib.org | ||
| 7 | */ | ||
| 8 | |||
| 9 | /* | ||
| 10 | Copyright 2017 Dean Camera (dean [at] fourwalledcubicle [dot] com) | ||
| 11 | |||
| 12 | Permission to use, copy, modify, distribute, and sell this | ||
| 13 | software and its documentation for any purpose is hereby granted | ||
| 14 | without fee, provided that the above copyright notice appear in | ||
| 15 | all copies and that both that the copyright notice and this | ||
| 16 | permission notice and warranty disclaimer appear in supporting | ||
| 17 | documentation, and that the name of the author not be used in | ||
| 18 | advertising or publicity pertaining to distribution of the | ||
| 19 | software without specific, written prior permission. | ||
| 20 | |||
| 21 | The author disclaims all warranties with regard to this | ||
| 22 | software, including all implied warranties of merchantability | ||
| 23 | and fitness. In no event shall the author be liable for any | ||
| 24 | special, indirect or consequential damages or any damages | ||
| 25 | whatsoever resulting from loss of use, data or profits, whether | ||
| 26 | in an action of contract, negligence or other tortious action, | ||
| 27 | arising out of or in connection with the use or performance of | ||
| 28 | this software. | ||
| 29 | */ | ||
| 30 | |||
| 31 | /** \file | ||
| 32 | * | ||
| 33 | * Simple HTTP Webserver Application. When connected to the uIP stack, | ||
| 34 | * this will serve out files to HTTP clients on port 80. | ||
| 35 | */ | ||
| 36 | |||
| 37 | #define INCLUDE_FROM_HTTPSERVERAPP_C | ||
| 38 | #include "HTTPServerApp.h" | ||
| 39 | |||
| 40 | /** HTTP server response header, for transmission before the page contents. This indicates to the host that a page exists at the | ||
| 41 | * given location, and gives extra connection information. | ||
| 42 | */ | ||
| 43 | const char PROGMEM HTTP200Header[] = "HTTP/1.1 200 OK\r\n" | ||
| 44 | "Server: LUFA " LUFA_VERSION_STRING "\r\n" | ||
| 45 | "Connection: close\r\n" | ||
| 46 | "MIME-version: 1.0\r\n" | ||
| 47 | "Content-Type: "; | ||
| 48 | |||
| 49 | /** HTTP server response header, for transmission before a resource not found error. This indicates to the host that the given | ||
| 50 | * URL is invalid, and gives extra error information. | ||
| 51 | */ | ||
| 52 | const char PROGMEM HTTP404Header[] = "HTTP/1.1 404 Not Found\r\n" | ||
| 53 | "Server: LUFA " LUFA_VERSION_STRING "\r\n" | ||
| 54 | "Connection: close\r\n" | ||
| 55 | "MIME-version: 1.0\r\n" | ||
| 56 | "Content-Type: text/plain\r\n\r\n" | ||
| 57 | "Error 404: File Not Found: /"; | ||
| 58 | |||
| 59 | /** Default filename to fetch when a directory is requested */ | ||
| 60 | const char PROGMEM DefaultDirFileName[] = "index.htm"; | ||
| 61 | |||
| 62 | /** Default MIME type sent if no other MIME type can be determined. */ | ||
| 63 | const char PROGMEM DefaultMIMEType[] = "text/plain"; | ||
| 64 | |||
| 65 | /** List of MIME types for each supported file extension. */ | ||
| 66 | const MIME_Type_t MIMETypes[] = | ||
| 67 | { | ||
| 68 | {.Extension = "htm", .MIMEType = "text/html"}, | ||
| 69 | {.Extension = "jpg", .MIMEType = "image/jpeg"}, | ||
| 70 | {.Extension = "gif", .MIMEType = "image/gif"}, | ||
| 71 | {.Extension = "bmp", .MIMEType = "image/bmp"}, | ||
| 72 | {.Extension = "png", .MIMEType = "image/png"}, | ||
| 73 | {.Extension = "ico", .MIMEType = "image/x-icon"}, | ||
| 74 | {.Extension = "exe", .MIMEType = "application/octet-stream"}, | ||
| 75 | {.Extension = "gz", .MIMEType = "application/x-gzip"}, | ||
| 76 | {.Extension = "zip", .MIMEType = "application/zip"}, | ||
| 77 | {.Extension = "pdf", .MIMEType = "application/pdf"}, | ||
| 78 | }; | ||
| 79 | |||
| 80 | /** FATFs structure to hold the internal state of the FAT driver for the Dataflash contents. */ | ||
| 81 | FATFS DiskFATState; | ||
| 82 | |||
| 83 | |||
| 84 | /** Initialization function for the simple HTTP webserver. */ | ||
| 85 | void HTTPServerApp_Init(void) | ||
| 86 | { | ||
| 87 | /* Listen on port 80 for HTTP connections from hosts */ | ||
| 88 | uip_listen(HTONS(HTTP_SERVER_PORT)); | ||
| 89 | |||
| 90 | /* Mount the Dataflash disk via FatFS */ | ||
| 91 | f_mount(0, &DiskFATState); | ||
| 92 | } | ||
| 93 | |||
| 94 | /** uIP stack application callback for the simple HTTP webserver. This function must be called each time the | ||
| 95 | * TCP/IP stack needs a TCP packet to be processed. | ||
| 96 | */ | ||
| 97 | void HTTPServerApp_Callback(void) | ||
| 98 | { | ||
| 99 | uip_tcp_appstate_t* const AppState = &uip_conn->appstate; | ||
| 100 | |||
| 101 | if (uip_aborted() || uip_timedout() || uip_closed()) | ||
| 102 | { | ||
| 103 | /* Lock to the closed state so that no further processing will occur on the connection */ | ||
| 104 | AppState->HTTPServer.CurrentState = WEBSERVER_STATE_Closing; | ||
| 105 | AppState->HTTPServer.NextState = WEBSERVER_STATE_Closing; | ||
| 106 | } | ||
| 107 | |||
| 108 | if (uip_connected()) | ||
| 109 | { | ||
| 110 | /* New connection - initialize connection state values */ | ||
| 111 | AppState->HTTPServer.CurrentState = WEBSERVER_STATE_OpenRequestedFile; | ||
| 112 | AppState->HTTPServer.NextState = WEBSERVER_STATE_OpenRequestedFile; | ||
| 113 | AppState->HTTPServer.FileOpen = false; | ||
| 114 | AppState->HTTPServer.ACKedFilePos = 0; | ||
| 115 | AppState->HTTPServer.SentChunkSize = 0; | ||
| 116 | } | ||
| 117 | |||
| 118 | if (uip_acked()) | ||
| 119 | { | ||
| 120 | /* Add the amount of ACKed file data to the total sent file bytes counter */ | ||
| 121 | AppState->HTTPServer.ACKedFilePos += AppState->HTTPServer.SentChunkSize; | ||
| 122 | |||
| 123 | /* Progress to the next state once the current state's data has been ACKed */ | ||
| 124 | AppState->HTTPServer.CurrentState = AppState->HTTPServer.NextState; | ||
| 125 | } | ||
| 126 | |||
| 127 | if (uip_rexmit()) | ||
| 128 | { | ||
| 129 | /* Return file pointer to the last ACKed position */ | ||
| 130 | f_lseek(&AppState->HTTPServer.FileHandle, AppState->HTTPServer.ACKedFilePos); | ||
| 131 | } | ||
| 132 | |||
| 133 | if (uip_rexmit() || uip_acked() || uip_newdata() || uip_connected() || uip_poll()) | ||
| 134 | { | ||
| 135 | switch (AppState->HTTPServer.CurrentState) | ||
| 136 | { | ||
| 137 | case WEBSERVER_STATE_OpenRequestedFile: | ||
| 138 | HTTPServerApp_OpenRequestedFile(); | ||
| 139 | break; | ||
| 140 | case WEBSERVER_STATE_SendResponseHeader: | ||
| 141 | HTTPServerApp_SendResponseHeader(); | ||
| 142 | break; | ||
| 143 | case WEBSERVER_STATE_SendData: | ||
| 144 | HTTPServerApp_SendData(); | ||
| 145 | break; | ||
| 146 | case WEBSERVER_STATE_Closing: | ||
| 147 | /* Connection is being terminated for some reason - close file handle */ | ||
| 148 | f_close(&AppState->HTTPServer.FileHandle); | ||
| 149 | AppState->HTTPServer.FileOpen = false; | ||
| 150 | |||
| 151 | /* If connection is not already closed, close it */ | ||
| 152 | uip_close(); | ||
| 153 | |||
| 154 | AppState->HTTPServer.CurrentState = WEBSERVER_STATE_Closed; | ||
| 155 | AppState->HTTPServer.NextState = WEBSERVER_STATE_Closed; | ||
| 156 | break; | ||
| 157 | } | ||
| 158 | } | ||
| 159 | } | ||
| 160 | |||
| 161 | /** HTTP Server State handler for the Request Process state. This state manages the processing of incoming HTTP | ||
| 162 | * GET requests to the server from the receiving HTTP client. | ||
| 163 | */ | ||
| 164 | static void HTTPServerApp_OpenRequestedFile(void) | ||
| 165 | { | ||
| 166 | uip_tcp_appstate_t* const AppState = &uip_conn->appstate; | ||
| 167 | char* const AppData = (char*)uip_appdata; | ||
| 168 | |||
| 169 | /* No HTTP header received from the client, abort processing */ | ||
| 170 | if (!(uip_newdata())) | ||
| 171 | return; | ||
| 172 | |||
| 173 | char* RequestToken = strtok(AppData, " "); | ||
| 174 | char* RequestedFileName = strtok(NULL, " "); | ||
| 175 | |||
| 176 | /* Must be a GET request, abort otherwise */ | ||
| 177 | if (strcmp_P(RequestToken, PSTR("GET")) != 0) | ||
| 178 | { | ||
| 179 | uip_abort(); | ||
| 180 | return; | ||
| 181 | } | ||
| 182 | |||
| 183 | /* Copy over the requested filename */ | ||
| 184 | strlcpy(AppState->HTTPServer.FileName, &RequestedFileName[1], sizeof(AppState->HTTPServer.FileName)); | ||
| 185 | |||
| 186 | /* Determine the length of the URI so that it can be checked to see if it is a directory */ | ||
| 187 | uint8_t FileNameLen = strlen(AppState->HTTPServer.FileName); | ||
| 188 | |||
| 189 | /* If the URI is a directory, append the default filename */ | ||
| 190 | if ((AppState->HTTPServer.FileName[FileNameLen - 1] == '/') || !(FileNameLen)) | ||
| 191 | { | ||
| 192 | strlcpy_P(&AppState->HTTPServer.FileName[FileNameLen], DefaultDirFileName, | ||
| 193 | (sizeof(AppState->HTTPServer.FileName) - FileNameLen)); | ||
| 194 | } | ||
| 195 | |||
| 196 | /* Try to open the file from the Dataflash disk */ | ||
| 197 | AppState->HTTPServer.FileOpen = (f_open(&AppState->HTTPServer.FileHandle, AppState->HTTPServer.FileName, | ||
| 198 | (FA_OPEN_EXISTING | FA_READ)) == FR_OK); | ||
| 199 | |||
| 200 | /* Lock to the SendResponseHeader state until connection terminated */ | ||
| 201 | AppState->HTTPServer.CurrentState = WEBSERVER_STATE_SendResponseHeader; | ||
| 202 | AppState->HTTPServer.NextState = WEBSERVER_STATE_SendResponseHeader; | ||
| 203 | } | ||
| 204 | |||
| 205 | /** HTTP Server State handler for the HTTP Response Header Send state. This state manages the transmission of | ||
| 206 | * the HTTP response header to the receiving HTTP client. | ||
| 207 | */ | ||
| 208 | static void HTTPServerApp_SendResponseHeader(void) | ||
| 209 | { | ||
| 210 | uip_tcp_appstate_t* const AppState = &uip_conn->appstate; | ||
| 211 | char* const AppData = (char*)uip_appdata; | ||
| 212 | |||
| 213 | char* Extension = strpbrk(AppState->HTTPServer.FileName, "."); | ||
| 214 | bool FoundMIMEType = false; | ||
| 215 | |||
| 216 | /* If the file isn't already open, it wasn't found - send back a 404 error response and abort */ | ||
| 217 | if (!(AppState->HTTPServer.FileOpen)) | ||
| 218 | { | ||
| 219 | /* Copy over the HTTP 404 response header and send it to the receiving client */ | ||
| 220 | strcpy_P(AppData, HTTP404Header); | ||
| 221 | strcat(AppData, AppState->HTTPServer.FileName); | ||
| 222 | uip_send(AppData, strlen(AppData)); | ||
| 223 | |||
| 224 | AppState->HTTPServer.NextState = WEBSERVER_STATE_Closing; | ||
| 225 | return; | ||
| 226 | } | ||
| 227 | |||
| 228 | /* Copy over the HTTP 200 response header and send it to the receiving client */ | ||
| 229 | strcpy_P(AppData, HTTP200Header); | ||
| 230 | |||
| 231 | /* Check to see if a MIME type for the requested file's extension was found */ | ||
| 232 | if (Extension != NULL) | ||
| 233 | { | ||
| 234 | /* Look through the MIME type list, copy over the required MIME type if found */ | ||
| 235 | for (uint8_t i = 0; i < (sizeof(MIMETypes) / sizeof(MIMETypes[0])); i++) | ||
| 236 | { | ||
| 237 | if (strcmp(&Extension[1], MIMETypes[i].Extension) == 0) | ||
| 238 | { | ||
| 239 | strcat(AppData, MIMETypes[i].MIMEType); | ||
| 240 | FoundMIMEType = true; | ||
| 241 | break; | ||
| 242 | } | ||
| 243 | } | ||
| 244 | } | ||
| 245 | |||
| 246 | /* Check if a MIME type was found and copied to the output buffer */ | ||
| 247 | if (!(FoundMIMEType)) | ||
| 248 | { | ||
| 249 | /* MIME type not found - copy over the default MIME type */ | ||
| 250 | strcat_P(AppData, DefaultMIMEType); | ||
| 251 | } | ||
| 252 | |||
| 253 | /* Add the end-of-line terminator and end-of-headers terminator after the MIME type */ | ||
| 254 | strcat_P(AppData, PSTR("\r\n\r\n")); | ||
| 255 | |||
| 256 | /* Send the MIME header to the receiving client */ | ||
| 257 | uip_send(AppData, strlen(AppData)); | ||
| 258 | |||
| 259 | /* When the MIME header is ACKed, progress to the data send stage */ | ||
| 260 | AppState->HTTPServer.NextState = WEBSERVER_STATE_SendData; | ||
| 261 | } | ||
| 262 | |||
| 263 | /** HTTP Server State handler for the Data Send state. This state manages the transmission of file chunks | ||
| 264 | * to the receiving HTTP client. | ||
| 265 | */ | ||
| 266 | static void HTTPServerApp_SendData(void) | ||
| 267 | { | ||
| 268 | uip_tcp_appstate_t* const AppState = &uip_conn->appstate; | ||
| 269 | char* const AppData = (char*)uip_appdata; | ||
| 270 | |||
| 271 | /* Get the maximum segment size for the current packet */ | ||
| 272 | uint16_t MaxChunkSize = uip_mss(); | ||
| 273 | |||
| 274 | /* Read the next chunk of data from the open file */ | ||
| 275 | f_read(&AppState->HTTPServer.FileHandle, AppData, MaxChunkSize, &AppState->HTTPServer.SentChunkSize); | ||
| 276 | |||
| 277 | /* Send the next file chunk to the receiving client */ | ||
| 278 | uip_send(AppData, AppState->HTTPServer.SentChunkSize); | ||
| 279 | |||
| 280 | /* Check if we are at the last chunk of the file, if so next ACK should close the connection */ | ||
| 281 | if (MaxChunkSize != AppState->HTTPServer.SentChunkSize) | ||
| 282 | AppState->HTTPServer.NextState = WEBSERVER_STATE_Closing; | ||
| 283 | } | ||
| 284 | |||
