error_t httpSendResponse(HttpConnection *connection, const char_t *uri) { #if (HTTP_SERVER_FS_SUPPORT == ENABLED) error_t error; uint32_t length; size_t n; FsFile *file; //Retrieve the full pathname httpGetAbsolutePath(connection, uri, connection->buffer, HTTP_SERVER_BUFFER_SIZE); //Retrieve the size of the specified file error = fsGetFileSize(connection->buffer, &length); //The specified URI cannot be found? if(error) return ERROR_NOT_FOUND; //Open the file for reading file = fsOpenFile(connection->buffer, FS_FILE_MODE_READ); //Failed to open the file? if(!file) return ERROR_NOT_FOUND; #else error_t error; size_t length; uint8_t *data; //Retrieve the full pathname httpGetAbsolutePath(connection, uri, connection->buffer, HTTP_SERVER_BUFFER_SIZE); //Get the resource data associated with the URI error = resGetData(connection->buffer, &data, &length); //The specified URI cannot be found? if(error) return error; #endif //Format HTTP response header connection->response.statusCode = 200; connection->response.contentType = mimeGetType(uri); connection->response.chunkedEncoding = FALSE; connection->response.contentLength = length; //Send the header to the client error = httpWriteHeader(connection); //Any error to report? if(error) { #if (HTTP_SERVER_FS_SUPPORT == ENABLED) //Close the file fsCloseFile(file); #endif //Return status code return error; } #if (HTTP_SERVER_FS_SUPPORT == ENABLED) //Send response body while(length > 0) { //Limit the number of bytes to read at a time n = MIN(length, HTTP_SERVER_BUFFER_SIZE); //Read data from the specified file error = fsReadFile(file, connection->buffer, n, &n); //End of input stream? if(error) break; //Send data to the client error = httpWriteStream(connection, connection->buffer, n); //Any error to report? if(error) break; //Decrement the count of remaining bytes to be transferred length -= n; } //Close the file fsCloseFile(file); //Successful file transfer? if(length == 0 && error == ERROR_END_OF_STREAM) { //Properly close the output stream error = httpCloseStream(connection); } #else //Send response body error = httpWriteStream(connection, data, length); //Any error to report? if(error) return error; //Properly close output stream error = httpCloseStream(connection); #endif //Return status code return error; }
"<p>%s</p>\r\n" "</body>\r\n" "</html>\r\n"; //Compute the length of the response length = strlen(template) + strlen(message) - 4; //Format HTTP response header connection->response.version = connection->request.version; connection->response.statusCode = statusCode; connection->response.contentType = mimeGetType(".htm"); connection->response.chunkedEncoding = FALSE; connection->response.contentLength = length; //Send the header to the client error = httpWriteHeader(connection); //Any error to report? if(error) return error; //Format HTML response sprintf(connection->buffer, template, statusCode, statusCode, message); //Send response body error = httpWriteStream(connection, connection->buffer, length); //Any error to report? if(error) return error; //Properly close output stream error = httpCloseStream(connection); //Return status code return error;
error_t httpServerUriNotFoundCallback(HttpConnection *connection, const char_t *uri) { error_t error; size_t n; char_t *buffer; //Process data.xml file? if(!strcasecmp(uri, "/data.xml")) { //Point to the scratch buffer buffer = connection->buffer + 384; //Format XML data n = sprintf(buffer, "<data>\r\n"); n += sprintf(buffer + n, " <ax>%d</ax>\r\n", ax); n += sprintf(buffer + n, " <ay>%d</ay>\r\n", ay); n += sprintf(buffer + n, " <az>%d</az>\r\n", az); n += sprintf(buffer + n, " <adc>%u</adc>\r\n", adcValue); n += sprintf(buffer + n, " <joystick>%u</joystick>\r\n", joystickState); //End of XML data n += sprintf(buffer + n, "</data>\r\n"); //Format HTTP response header connection->response.version = connection->request.version; connection->response.statusCode = 200; connection->response.keepAlive = connection->request.keepAlive; connection->response.noCache = TRUE; connection->response.contentType = mimeGetType(".xml"); connection->response.chunkedEncoding = FALSE; connection->response.contentLength = n; //Send the header to the client error = httpWriteHeader(connection); //Any error to report? if(error) return error; //Send response body error = httpWriteStream(connection, buffer, n); //Any error to report? if(error) return error; //Properly close output stream error = httpCloseStream(connection); //Return status code return error; } //Process send_mail.xml file? else if(!strcasecmp(uri, "/send_mail.xml")) { char_t *separator; char_t *property; char_t *value; char_t *p; SmtpAuthInfo authInfo; SmtpMail mail; SmtpMailAddr recipients[4]; //Initialize structures to zero memset(&authInfo, 0, sizeof(authInfo)); memset(&mail, 0, sizeof(mail)); memset(recipients, 0, sizeof(recipients)); //Set the relevant PRNG algorithm to be used authInfo.prngAlgo = YARROW_PRNG_ALGO; authInfo.prngContext = &yarrowContext; //Set email recipients mail.recipients = recipients; //Point to the scratch buffer buffer = connection->buffer; //Start of exception handling block do { //Process HTTP request body while(1) { //Read the HTTP request body until an ampersand is encountered error = httpReadStream(connection, buffer, HTTP_SERVER_BUFFER_SIZE - 1, &n, HTTP_FLAG_BREAK('&')); //End of stream detected? if(error) break; //Properly terminate the string with a NULL character buffer[n] = '\0'; //Remove the trailing ampersand if(n > 0 && buffer[n - 1] == '&') buffer[--n] = '\0'; //Decode the percent-encoded string httpDecodePercentEncodedString(buffer, buffer, HTTP_SERVER_BUFFER_SIZE); //Check whether a separator is present separator = strchr(buffer, '='); //Separator found? if(separator) { //Split the line *separator = '\0'; //Get property name and value property = strTrimWhitespace(buffer); value = strTrimWhitespace(separator + 1); //Check property name if(!strcasecmp(property, "server")) { //Save server name authInfo.serverName = strDuplicate(value); } else if(!strcasecmp(property, "port")) { //Save the server port to be used authInfo.serverPort = atoi(value); } else if(!strcasecmp(property, "userName")) { //Save user name authInfo.userName = strDuplicate(value); } else if(!strcasecmp(property, "password")) { //Save password authInfo.password = strDuplicate(value); } else if(!strcasecmp(property, "useTls")) { //Open a secure SSL/TLS session? authInfo.useTls = TRUE; } else if(!strcasecmp(property, "recipient")) { //Split the recipient address list value = strtok_r(value, ", ", &p); //Loop through the list while(value != NULL) { //Save recipient address recipients[mail.recipientCount].name = NULL; recipients[mail.recipientCount].addr = strDuplicate(value); recipients[mail.recipientCount].type = SMTP_RCPT_TYPE_TO; //Get the next item in the list value = strtok_r(NULL, ", ", &p); //Increment the number of recipients if(++mail.recipientCount >= arraysize(recipients)) break; } } else if(!strcasecmp(property, "from")) { //Save sender address mail.from.name = NULL; mail.from.addr = strDuplicate(value); } else if(!strcasecmp(property, "date")) { //Save current time mail.dateTime = strDuplicate(value); } else if(!strcasecmp(property, "subject")) { //Save mail subject mail.subject = strDuplicate(value); } else if(!strcasecmp(property, "body")) { //Save mail body mail.body = strDuplicate(value); } } } //Propagate exception if necessary if(error != ERROR_END_OF_STREAM) break; //Send mail error = smtpSendMail(&authInfo, &mail); //Point to the scratch buffer buffer = connection->buffer + 384; //Format XML data n = sprintf(buffer, "<data>\r\n <status>"); if(error == NO_ERROR) n += sprintf(buffer + n, "Mail successfully sent!\r\n"); else if(error == ERROR_NAME_RESOLUTION_FAILED) n += sprintf(buffer + n, "Cannot resolve SMTP server name!\r\n"); else if(error == ERROR_AUTHENTICATION_FAILED) n += sprintf(buffer + n, "Authentication failed!\r\n"); else if(error == ERROR_UNEXPECTED_RESPONSE) n += sprintf(buffer + n, "Unexpected response from SMTP server!\r\n"); else n += sprintf(buffer + n, "Failed to send mail (error %d)!\r\n", error); n += sprintf(buffer + n, "</status>\r\n</data>\r\n"); //Format HTTP response header connection->response.version = connection->request.version; connection->response.statusCode = 200; connection->response.keepAlive = connection->request.keepAlive; connection->response.noCache = TRUE; connection->response.contentType = mimeGetType(".xml"); connection->response.chunkedEncoding = FALSE; connection->response.contentLength = n; //Send the header to the client error = httpWriteHeader(connection); //Any error to report? if(error) break; //Send response body error = httpWriteStream(connection, buffer, n); //Any error to report? if(error) break; //Properly close output stream error = httpCloseStream(connection); //Any error to report? if(error) break; //End of exception handling block } while(0); //Free previously allocated memory osFreeMem((void *) authInfo.serverName); osFreeMem((void *) authInfo.userName); osFreeMem((void *) authInfo.password); osFreeMem((void *) recipients[0].addr); osFreeMem((void *) mail.from.addr); osFreeMem((void *) mail.dateTime); osFreeMem((void *) mail.subject); osFreeMem((void *) mail.body); //Return status code return error; } else { return ERROR_NOT_FOUND; } }
error_t httpServerProcessGetConfig(HttpConnection *connection) { error_t error; uint_t i; size_t n; char_t *buffer; char_t temp[40]; //Allocate a memory buffer buffer = osAllocMem(2048); //Failed to allocate memory? if(!buffer) return ERROR_OUT_OF_MEMORY; //Format XML data n = sprintf(buffer, "<settings>\r\n"); //Icecast settings n += sprintf(buffer + n, " <icecast>\r\n"); //Icecast resource n += sprintf(buffer + n, " <url>%s</url>\r\n", appSettings.icecast.url); //Icecast server port n += sprintf(buffer + n, " <port>%" PRIu16 "</port>\r\n", appSettings.icecast.port); //End of Icecast settings n += sprintf(buffer + n, " </icecast>\r\n"); //LAN settings n += sprintf(buffer + n, " <lan>\r\n"); //MAC address n += sprintf(buffer + n, " <macAddr>%s</macAddr>\r\n", macAddrToString(&appSettings.lan.macAddr, temp)); //Host name n += sprintf(buffer + n, " <hostName>%s</hostName>\r\n", appSettings.lan.hostname); //Enable DHCP n += sprintf(buffer + n, " <enableDhcp>%u</enableDhcp>\r\n", appSettings.lan.enableDhcp); //IPv4 host address n += sprintf(buffer + n, " <hostAddr>%s</hostAddr>\r\n", ipv4AddrToString(appSettings.lan.hostAddr, temp)); //Subnet mask n += sprintf(buffer + n, " <subnetMask>%s</subnetMask>\r\n", ipv4AddrToString(appSettings.lan.subnetMask, temp)); //Default gateway n += sprintf(buffer + n, " <defaultGateway>%s</defaultGateway>\r\n", ipv4AddrToString(appSettings.lan.defaultGateway, temp)); //Primary DNS n += sprintf(buffer + n, " <primaryDns>%s</primaryDns>\r\n", ipv4AddrToString(appSettings.lan.primaryDns, temp)); //Secondary DNS n += sprintf(buffer + n, " <secondaryDns>%s</secondaryDns>\r\n", ipv4AddrToString(appSettings.lan.secondaryDns, temp)); //End of LAN settings n += sprintf(buffer + n, " </lan>\r\n"); //Proxy settings n += sprintf(buffer + n, " <proxy>\r\n"); //Enable proxy server n += sprintf(buffer + n, " <enable>%u</enable>\r\n", appSettings.proxy.enable); //Proxy server name n += sprintf(buffer + n, " <name>%s</name>\r\n", appSettings.proxy.name); //Proxy server port n += sprintf(buffer + n, " <port>%" PRIu16 "</port>\r\n", appSettings.proxy.port); //End of proxy settings n += sprintf(buffer + n, " </proxy>\r\n"); //End of settings n += sprintf(buffer + n, "</settings>\r\n"); //Format HTTP response header connection->response.version = connection->request.version; connection->response.statusCode = 200; connection->response.keepAlive = connection->request.keepAlive; connection->response.noCache = TRUE; connection->response.contentType = mimeGetType(".xml"); connection->response.chunkedEncoding = FALSE; connection->response.contentLength = n; //Send the header to the client error = httpWriteHeader(connection); //Check status code if(!error) { //Send response body error = httpWriteStream(connection, buffer, n); } //Check status code if(!error) { //Properly close output stream error = httpCloseStream(connection); } //Free previously allocated memory osFreeMem(buffer); //Return status code return error; }
error_t httpServerProcessSetConfig(HttpConnection *connection) { error_t error; uint_t i; size_t n; char_t *p; char_t *buffer; char_t *separator; char_t *property; char_t *value; Settings *newSettings; //Point to the scratch buffer buffer = connection->buffer; //Allocate a memory buffer to hold the new configuration newSettings = osAllocMem(sizeof(Settings)); //Failed to allocate memory? if(!newSettings) return ERROR_OUT_OF_MEMORY; //Start of exception handling block do { //Retrieve default settings error = getDefaultSettings(newSettings); //Any error to report? if(error) break; //Process HTTP request body while(1) { //Read the HTTP request body until an ampersand is encountered error = httpReadStream(connection, buffer, HTTP_SERVER_BUFFER_SIZE - 1, &n, HTTP_FLAG_BREAK('&')); //End of stream detected? if(error) break; //Properly terminate the string with a NULL character buffer[n] = '\0'; //Remove the trailing ampersand if(n > 0 && buffer[n - 1] == '&') buffer[--n] = '\0'; //Decode the percent-encoded string error = httpDecodePercentEncodedString(buffer, buffer, HTTP_SERVER_BUFFER_SIZE); //Any error detected? if(error) break; //Check whether a separator is present separator = strchr(buffer, '='); //Separator found? if(separator) { //Split the line *separator = '\0'; //Get property name and value property = strTrimWhitespace(buffer); value = strTrimWhitespace(separator + 1); //Debug message TRACE_DEBUG("[%s]=%s\r\n", property, value); //Icecast settings if(!strcasecmp(property, "icecastSettingsUrl")) { //Check resource length if(strlen(value) >= sizeof(newSettings->icecast.url)) { //Report an error error = ERROR_INVALID_SYNTAX; break; } //Save resource strcpy(newSettings->icecast.url, value); } else if(!strcasecmp(property, "icecastSettingsPort")) { //Save Icecast server port newSettings->icecast.port = strtoul(value, &p, 10); //Invalid port number? if(*p != '\0') { //Report an error error = ERROR_INVALID_SYNTAX; break; } } //LAN settings else if(!strcasecmp(property, "lanSettingsMacAddr")) { //Save MAC address error = macStringToAddr(value, &newSettings->lan.macAddr); //Invalid address? if(error) break; } else if(!strcasecmp(property, "lanSettingsHostName")) { //Check the length of the host name if(strlen(value) >= sizeof(newSettings->lan.hostname)) { //Report an error error = ERROR_INVALID_SYNTAX; break; } //Save host name strcpy(newSettings->lan.hostname, value); } else if(!strcasecmp(property, "lanSettingsEnableDhcp")) { //Check flag value if(!strcasecmp(value, "off")) { //DHCP client is disabled newSettings->lan.enableDhcp = FALSE; } else if(!strcasecmp(value, "on")) { //DHCP client is enabled newSettings->lan.enableDhcp = TRUE; } else { //Invalid value error = ERROR_INVALID_SYNTAX; break; } } else if(!strcasecmp(property, "lanSettingsHostAddr")) { //Save IPv4 host address error = ipv4StringToAddr(value, &newSettings->lan.hostAddr); //Invalid address? if(error) break; } else if(!strcasecmp(property, "lanSettingsSubnetMask")) { //Save subnet mask error = ipv4StringToAddr(value, &newSettings->lan.subnetMask); //Invalid mask? if(error) break; } else if(!strcasecmp(property, "lanSettingsDefaultGateway")) { //Save default gateway error = ipv4StringToAddr(value, &newSettings->lan.defaultGateway); //Invalid address? if(error) break; } else if(!strcasecmp(property, "lanSettingsPrimaryDns")) { //Save primary DNS error = ipv4StringToAddr(value, &newSettings->lan.primaryDns); //Invalid address? if(error) break; } else if(!strcasecmp(property, "lanSettingsSecondaryDns")) { //Save secondary DNS error = ipv4StringToAddr(value, &newSettings->lan.secondaryDns); //Invalid address? if(error) break; } //Proxy settings else if(!strcasecmp(property, "proxySettingsEnable")) { //Check flag value if(!strcasecmp(value, "off")) { //Proxy server is disabled newSettings->proxy.enable = FALSE; } else if(!strcasecmp(value, "on")) { //Proxy server is enabled newSettings->proxy.enable = TRUE; } else { //Invalid value error = ERROR_INVALID_SYNTAX; break; } } else if(!strcasecmp(property, "proxySettingsName")) { //Check the length of proxy server name if(strlen(value) >= sizeof(newSettings->proxy.name)) { //Report an error error = ERROR_INVALID_SYNTAX; break; } //Save proxy server name strcpy(newSettings->proxy.name, value); } else if(!strcasecmp(property, "proxySettingsPort")) { //Save proxy server port newSettings->proxy.port = strtoul(value, &p, 10); //Invalid port number? if(*p != '\0') { //Report an error error = ERROR_INVALID_SYNTAX; break; } } } } //Check status code if(error == NO_ERROR || error == ERROR_END_OF_STREAM) { //Commit changes appSettings = *newSettings; //Write settings to non-volatile memory error = saveSettings(newSettings); } else if(error != ERROR_INVALID_SYNTAX) { //Propagate exception break; } //Point to the scratch buffer buffer = connection->buffer + 384; //Format XML data n = sprintf(buffer, "<data>\r\n <status>"); if(error == ERROR_INVALID_SYNTAX) n += sprintf(buffer + n, "Invalid configuration!\r\n"); else if(error != NO_ERROR) n += sprintf(buffer + n, "Failed to save settings to non-volatile memory!\r\n"); else n += sprintf(buffer + n, "Settings successfully saved. Please reboot the board.\r\n"); //Terminate XML data n += sprintf(buffer + n, "</status>\r\n</data>\r\n"); //Format HTTP response header connection->response.version = connection->request.version; connection->response.statusCode = 200; connection->response.keepAlive = connection->request.keepAlive; connection->response.noCache = TRUE; connection->response.contentType = mimeGetType(".xml"); connection->response.chunkedEncoding = FALSE; connection->response.contentLength = n; //Send the header to the client error = httpWriteHeader(connection); //Any error to report? if(error) break; //Send response body error = httpWriteStream(connection, buffer, n); //Any error to report? if(error) break; //Properly close output stream error = httpCloseStream(connection); //Any error to report? if(error) break; //End of exception handling block } while(0); //Free previously allocated memory osFreeMem(newSettings); //Return status code return error; }
error_t ssiExecuteScript(HttpConnection *connection, const char_t *uri, uint_t level) { error_t error; size_t length; #if (HTTP_SERVER_FS_SUPPORT == ENABLED) bool_t more; uint_t pos; uint_t n; char_t *buffer; FsFile *file; #else uint_t i; uint_t j; char_t *data; #endif //Recursion limit exceeded? if(level >= HTTP_SERVER_SSI_MAX_RECURSION) return NO_ERROR; //Retrieve the full pathname httpGetAbsolutePath(connection, uri, connection->buffer, HTTP_SERVER_BUFFER_SIZE); #if (HTTP_SERVER_FS_SUPPORT == ENABLED) //Open the file for reading file = fsOpenFile(connection->buffer, FS_FILE_MODE_READ); //Failed to open the file? if(!file) return ERROR_NOT_FOUND; //Allocate a memory buffer buffer = osAllocMem(HTTP_SERVER_BUFFER_SIZE); //Failed to allocate memory? if(!buffer) { //Close the file fsCloseFile(file); //Report an error return ERROR_OUT_OF_MEMORY; } #else //Get the resource data associated with the URI error = resGetData(connection->buffer, (uint8_t **) &data, &length); //The specified URI cannot be found? if(error) return error; #endif //Send the HTTP response header before executing the script if(!level) { //Format HTTP response header connection->response.statusCode = 200; connection->response.contentType = mimeGetType(uri); connection->response.chunkedEncoding = TRUE; //Send the header to the client error = httpWriteHeader(connection); //Any error to report? if(error) { #if (HTTP_SERVER_FS_SUPPORT == ENABLED) //Close the file fsCloseFile(file); //Release memory buffer osFreeMem(buffer); #endif //Return status code return error; } } #if (HTTP_SERVER_FS_SUPPORT == ENABLED) //Point to the beginning of the buffer pos = 0; length = 0; //This flag indicates whether data should be read more = TRUE; //Parse the specified file while(1) { //Read more data if needed if(more) { //Read data from the specified file error = fsReadFile(file, buffer + pos + length, HTTP_SERVER_BUFFER_SIZE - (pos + length), &n); //End of input stream? if(error) { //Purge data buffer error = httpWriteStream(connection, buffer + pos, length); //Exit immediately break; } //Adjust the length of the buffer length += n; //Clear flag more = FALSE; } //Search for any SSI tags error = ssiSearchTag(buffer + pos, length, "<!--#", 5, &n); //Full match? if(error == NO_ERROR) { //Send the part of the file that precedes the tag error = httpWriteStream(connection, buffer + pos, n); //Failed to send data? if(error) break; //Advance data pointer pos += n; length -= n; //Search for the comment terminator error = ssiSearchTag(buffer + pos + 5, length - 5, "-->", 3, &n); //Full match? if(error == NO_ERROR) { //Advance data pointer over the opening identifier pos += 5; length -= 5; //Process SSI directive error = ssiProcessCommand(connection, buffer + pos, n, uri, level); //Any error to report? if(error) break; //Advance data pointer over the SSI tag pos += n + 3; length -= n + 3; } //No match or partial match? else { if(pos > 0) { //Move the remaining bytes to the start of the buffer memmove(buffer, buffer + pos, length); //Rewind to the beginning of the buffer pos = 0; //More data are needed more = TRUE; } else { //Send data to the client error = httpWriteStream(connection, buffer + pos, length); //Any error to report? if(error) break; //Rewind to the beginning of the buffer pos = 0; length = 0; //More data are needed more = TRUE; } } } //Partial match? else if(error == ERROR_PARTIAL_MATCH) { //Send the part of the file that precedes the tag error = httpWriteStream(connection, buffer + pos, n); //Failed to send data? if(error) break; //Advance data pointer pos += n; length -= n; //Move the remaining bytes to the start of the buffer memmove(buffer, buffer + pos, length); //Rewind to the beginning of the buffer pos = 0; //More data are needed more = TRUE; } //No match? else { //Send data to the client error = httpWriteStream(connection, buffer + pos, length); //Any error to report? if(error) break; //Rewind to the beginning of the buffer pos = 0; length = 0; //More data are needed more = TRUE; } } //Close the file fsCloseFile(file); //Release memory buffer osFreeMem(buffer); //Properly close the output stream if(!level && error == NO_ERROR) error = httpCloseStream(connection); #else //Parse the specified file while(length > 0) { //Search for any SSI tags error = ssiSearchTag(data, length, "<!--#", 5, &i); //Opening identifier found? if(!error) { //Search for the comment terminator error = ssiSearchTag(data + i + 5, length - i - 5, "-->", 3, &j); } //Check whether a valid SSI tag has been found? if(!error) { //Send the part of the file that precedes the tag error = httpWriteStream(connection, data, i); //Failed to send data? if(error) return error; //Advance data pointer over the opening identifier data += i + 5; length -= i + 5; //Process SSI directive error = ssiProcessCommand(connection, data, j, uri, level); //Any error to report? if(error) return error; //Advance data pointer over the SSI tag data += j + 3; length -= j + 3; } else { //Send the rest of the file error = httpWriteStream(connection, data, length); //Failed to send data? if(error) return error; //Advance data pointer data += length; length = 0; } } //Properly close the output stream if(!level) error = httpCloseStream(connection); #endif //Return status code return error; }