NetBurner 3.5.6
PDF Version
Web Server

NetBurner Web Server Guide

Overview

The NetBurner web server provides a powerful embedded HTTP server with support for both static and dynamic content. The web server architecture integrates seamlessly with your application, allowing real-time data display and interactive control through web pages.

NetBurner Web Server Architecture
─────────────────────────────────
Web Browser NetBurner Device Application
─────────── ──────────────── ───────────
┌──────────┐ ┌──────────────┐ ┌─────────┐
│ │ │ │ │ │
│ HTTP │ Request │ Web Server │ │ User │
│ Client │───────────────>│ │ │ Code │
│ │ │ - Routes │ │ │
│ │ │ - Static │<────────────│ - Data │
│ │ Response │ - Dynamic │ Calls │ - Logic │
│ │<───────────────│ │ │ │
│ │ └──────────────┘ └─────────┘
└──────────┘ |
v
┌──────────────┐
│ html/ │
│ ├─ *.html │
│ ├─ *.css │
│ ├─ *.js │
│ └─ images/ │
└──────────────┘

Key Features

  • Static Content Serving - HTML, CSS, JavaScript, images
  • Dynamic Content Generation - Real-time data display
  • C++ Integration - Direct callback functions
  • Variable Display - Automatic type handling
  • URL Parsing - Request parameter processing
  • File System - Organized resource management

Basic Web Server Setup

Project Structure

When you create a NetBurner web application, the following structure is automatically generated:

Project Directory Structure
───────────────────────────
YourProject/
├── src/
│ ├── main.cpp <── Application entry point
│ └── htmldata.cpp <── Auto-generated from html/
├── html/ <── Web content directory
│ ├── index.html <── Default home page
│ ├── styles.css <── (Optional) Stylesheets
│ ├── script.js <── (Optional) JavaScript
│ └── images/ <── (Optional) Image assets
│ ├── logo.png
│ └── icon.jpg
└── makefile <── Build configuration

Initial index.html

The Application Wizard creates a basic index.html file:

<html>
<body>
The main page for the AppWizard project.
</body>
</html>

Static Content

All files in the html/ directory are compiled into your application binary. The web server serves these files when requested by a browser.

Static Content Flow
───────────────────
Build Time: Run Time:
─────────── ─────────
┌──────────┐ ┌──────────┐
│ html/ │ │ Browser │
│ Files │ │ Request │
└────┬─────┘ └────┬─────┘
| |
v v
┌──────────┐ Embedded ┌──────────┐
│ comphtml │ in Binary │ Web │
│ Tool │ ─────────> │ Server │
└────┬─────┘ └────┬─────┘
| |
v v
┌──────────┐ ┌──────────┐
│htmldata │ Linked to │ Static │
│ .cpp │ ─────────> │ Content │
└──────────┘ └──────────┘

Adding Resources

Adding Images

Create an images/ folder in your html/ directory:

html/
├── index.html
└── images/
└── logo.jpg

Reference images in your HTML:

<html>
<body>
<h1>The main page for the AppWizard project</h1>
<img src="images/logo.jpg" alt="Company Logo">
</body>
</html>

Adding CSS and JavaScript

html/
├── index.html
├── styles.css
├── script.js
└── images/

styles.css:**

body {
font-family: Arial, sans-serif;
background-color: #f0f0f0;
}

index.html with resources:**

<html>
<head>
<link rel="stylesheet" href="styles.css">
<script src="script.js"></script>
</head>
<body>
<h1>My NetBurner Application</h1>
<img src="images/logo.jpg" alt="Logo">
</body>
</html>

Editing HTML Files in NBEclipse

Right-click on an HTML file and select "Open With" > "Text Editor" to edit the raw HTML content.


Dynamic Web Content

NetBurner provides three HTML tags for dynamic content generation:

Dynamic Content Tags
────────────────────
Tag Type Purpose When to Use
──────── ─────── ───────────
CPPCALL Execute C++ function Complex logic, control
VARIABLE Display variable/expr Data display, sensors
INCLUDE Link external code Variable declarations

CPPCALL Tag - C++ Callback Functions

The CPPCALL tag executes a C++ function when the web page is served.

Syntax

<!--CPPCALL YourFunctionName -->

Function Signature

void YourFunctionName(int sock, PCSTR url)
{
// sock: TCP socket file descriptor
// url: Complete URL string from browser
}

Parameters Explained

CPPCALL Function Parameters
───────────────────────────
Parameter: sock (int)
┌─────────────────────────────────┐
│ TCP Socket File Descriptor │
│ - Use for writing output │
│ - writestring(sock, ...) │
│ - fdprintf(sock, ...) │
└─────────────────────────────────┘
Parameter: url (PCSTR)
┌─────────────────────────────────┐
│ Complete URL String │
│ "http://192.168.1.100/page?a=1"│
│ - Parse query parameters │
│ - Extract values after '?' │
└─────────────────────────────────┘
int fdprintf(int fd, const char *format,...)
Print formatted output to a file descriptor.
int writestring(int fd, const char *str)
Write a null terminated ascii string to the stream associated with a file descriptor (fd)....

Basic Example

main.cpp:**

#include <nbrtos.h>
#include <init.h>
#include <http.h>
void webHelloWorld(int sock, PCSTR url)
{
writestring(sock, "Hello World");
}
void UserMain(void *pd)
{
init();
StartHttp(); // Start web server on port 80
while (1) {
OSTimeDly(TICKS_PER_SECOND);
}
}
#define TICKS_PER_SECOND
System clock ticks per second.
Definition constants.h:49
void StartHttp(uint16_t port, bool RunConfigMirror)
Start the HTTP web server. Further documentation in the Initialization section Initialization - Syste...
void init()
System initialization. Ideally called at the beginning of all applications, since the easiest Recover...

index.html:**

<html>
<body>
<h1>The main page for the AppWizard project</h1>
<p>Message from device: <!--CPPCALL webHelloWorld --></p>
</body>
</html>

Request Flow

CPPCALL Execution Flow
──────────────────────
Browser Web Server Application
─────── ────────── ───────────
| | |
| GET /index.html | |
|────────────────────────────>| |
| | |
| | Stream static content |
|<────────────────────────────| |
| "<html><body><h1>..." | |
| | |
| | <!--CPPCALL detected --> |
| | |
| | Call webHelloWorld(sock) |
| |───────────────────────────>|
| | |
| | Execute function |
| | writestring(sock, "...") |
|<────────────────────────────|<───────────────────────────|
| "Hello World" | |
| | |
| | Continue static content |
|<────────────────────────────| |
| "</body></html>" | |

Advanced CPPCALL Example - URL Parsing

void webDeviceControl(int sock, PCSTR url)
{
// Parse URL for parameters
// Example: /index.html?action=toggle&pin=23
if (strstr(url, "action=toggle")) {
// Extract pin number
char *pinParam = strstr(url, "pin=");
if (pinParam) {
int pinNum = atoi(pinParam + 4);
// Toggle the pin
Pins[pinNum].set(!Pins[pinNum].read());
fdprintf(sock, "Pin %d toggled to %s",
pinNum,
Pins[pinNum].read() ? "HIGH" : "LOW");
}
} else if (strstr(url, "action=status")) {
fdprintf(sock, "Device uptime: %lu seconds", Secs);
} else {
writestring(sock, "Unknown command");
}
}
int read(int fd, char *buf, int nbytes)
Read data from a file descriptor (fd).

index.html:**

<html>
<body>
<h1>Device Control</h1>
<p>
<a href="?action=toggle&pin=23">Toggle Pin 23</a><br>
<a href="?action=status">Check Status</a>
</p>
<div>Response: <!--CPPCALL webDeviceControl --></div>
</body>
</html>

VARIABLE Tag - Displaying Variables

The VARIABLE tag displays application variables or expressions on web pages.

Syntax

<!--VARIABLE expression -->

Basic Usage

<!-- Display a simple variable -->
<!--VARIABLE TimeTick -->
<!-- Display an expression -->
<!--VARIABLE TimeTick/TICKS_PER_SECOND -->
<!-- Display with calculation -->
<!--VARIABLE (Temperature * 9/5) + 32 -->

Compilation Process

VARIABLE Tag Processing
───────────────────────
HTML Source: Generated Code:
──────────── ───────────────
<!--VARIABLE TimeTick --> WriteHtmlVariable(fd, TimeTick);
<!--VARIABLE TimeTick/ WriteHtmlVariable(fd,
<!--VARIABLE IPCAST( WriteHtmlVariable(fd,
IpAddress) --> IPCAST(IpAddress));

Supported Data Types

The following types are automatically handled by WriteHtmlVariable():

// Located in: \nburn\include\htmlfiles.h
void WriteHtmlVariable(int fd, char c);
void WriteHtmlVariable(int fd, int i);
void WriteHtmlVariable(int fd, short i);
void WriteHtmlVariable(int fd, long i);
void WriteHtmlVariable(int fd, BYTE b);
void WriteHtmlVariable(int fd, WORD w);
void WriteHtmlVariable(int fd, unsigned long dw);
void WriteHtmlVariable(int fd, const char *);
void WriteHtmlVariable(int fd, MACADR ip);
Used to store and manipulate MAC addresses.
Definition nettypes.h:69

Type Handling Overview

Type Conversion Flow
────────────────────
Variable Type Overloaded Function Output
───────────── ─────────────────── ──────
char ──> WriteHtmlVariable(fd, c) ──> 'A'
int ──> WriteHtmlVariable(fd, i) ──> 123
const char* ──> WriteHtmlVariable(fd, s) ──> "Hello"
unsigned long ──> WriteHtmlVariable(fd, ul) ──> 4294967295
MACADR ──> WriteHtmlVariable(fd, mac) ──> 00:03:F4:...

IP Address Display

Use the IPCAST() helper to convert 32-bit integers to IP address format:

<!-- Without IPCAST - displays as integer -->
IP Address: <!--VARIABLE IpAddress -->
<!-- Output: 3232235777 -->
<!-- With IPCAST - displays in dotted notation -->
IP Address: <!--VARIABLE IPCAST(IpAddress) -->
<!-- Output: 192.168.1.1 -->

Complete Example

main.cpp:**

#include <init.h>
#include <nbrtos.h>
// Global variables for web display
int Temperature = 25;
unsigned long Counter = 0;
const char *DeviceStatus = "Running";
void UserMain(void *pd)
{
init();
while (1) {
Counter++;
Temperature = 20 + (Counter % 15); // Simulate changing temp
OSTimeDly(TICKS_PER_SECOND);
}
}

index.html:**

<html>
<head>
<title>Device Status</title>
</head>
<body>
<h1>Device Status Monitor</h1>
<table border="1">
<tr>
<td>Uptime (seconds):</td>
<td><!--VARIABLE Secs --></td>
</tr>
<tr>
<td>System Ticks:</td>
<td><!--VARIABLE TimeTick --></td>
</tr>
<tr>
<td>Temperature (C):</td>
<td><!--VARIABLE Temperature --></td>
</tr>
<tr>
<td>Counter:</td>
<td><!--VARIABLE Counter --></td>
</tr>
<tr>
<td>Status:</td>
<td><!--VARIABLE DeviceStatus --></td>
</tr>
<tr>
<td>IP Address:</td>
<td><!--VARIABLE IPCAST(IpAddress) --></td>
</tr>
</table>
</body>
</html>

INCLUDE Tag - Linking Variables

To use variables with the VARIABLE tag, your application must link to them. Two methods are available:

Variable Linking Methods
────────────────────────
Method 1: htmlvar.h Header Method 2: INCLUDE Tag
───────────────────────── ─────────────────────
Project/ HTML File:
├── src/ ┌──────────────────────────────────┐
│ ├── main.cpp │ <!--INCLUDE mycustomheader.h --> │
│ └── htmlvar.h <───Link─── │ │
└── html/ └──────────────────────────────────┘
└── index.html |
v
Both methods allow Project/
htmldata.cpp to └── src/
link to your variables └── mycustomheader.h

Method 1: htmlvar.h Header File

Create htmlvar.h in your project's src/ directory:

htmlvar.h:**

#ifndef HTMLVARS_H_
#define HTMLVARS_H_
#include <init.h>
// Declare variables for web display
extern int Temperature;
extern unsigned long Counter;
extern const char *DeviceStatus;
// Declare function callbacks
const char *webMyVarFunction(int fd, int value);
#endif // HTMLVARS_H_

Project structure:**

Project/
├── src/
│ ├── main.cpp
│ ├── htmlvar.h <── Add this file
│ └── htmldata.cpp <── Auto-generated (includes htmlvar.h)
└── html/
└── index.html

Method 2: INCLUDE Tag in HTML

index.html:**

<html>
<!--INCLUDE customheader.h -->
<body>
<h1>Temperature: <!--VARIABLE Temperature --> C</h1>
</body>
</html>

src/customheader.h:**

#ifndef CUSTOMHEADER_H_
#define CUSTOMHEADER_H_
extern int Temperature;
#endif

Linking Flow

Variable Linking at Compile Time
─────────────────────────────────
Step 1: HTML Processing
┌────────────────────────┐
│ <!--VARIABLE Temp --> │
└───────────┬────────────┘
|
v
Step 2: Code Generation
┌─────────────────────────────────┐
│ WriteHtmlVariable(fd, Temp); │
└───────────┬─────────────────────┘
|
v
Step 3: Include Headers
┌─────────────────────────────────┐
│ #include "htmlvar.h"
// or │
│ #include "customheader.h"
└───────────┬─────────────────────┘
|
v
Step 4: Link Variable
┌─────────────────────────────────┐
extern int Temp; │
│ (declared in header) │
└───────────┬─────────────────────┘
|
v
Step 5: Compilation Success
┌─────────────────────────────────┐
│ htmldata.cpp links to Temp │
│ in main.cpp │
└─────────────────────────────────┘

Advanced Techniques

Function Callbacks with Parameters

The VARIABLE tag can be used for function callbacks that accept parameters, providing more flexibility than CPPCALL.

Comparison: CPPCALL vs VARIABLE Functions

CPPCALL vs VARIABLE Function Callbacks
───────────────────────────────────────
CPPCALL: VARIABLE Function:
──────── ──────────────────
Fixed Signature: Flexible Signature:
void func(int sock, PCSTR url) const char* func(int fd, int val)
const char* func(int fd, float val)
etc.
Limited Parameters Custom Parameters
Can't pass app data Can pass any type
Use for: Use for:
- URL parsing - Parameterized display
- Control actions - Formatted output
- General callbacks - Data transformation

Function Callback Workflow

VARIABLE Function Callback Flow
───────────────────────────────
HTML:
┌────────────────────────────────────┐
│ <!--VARIABLE myFunc(fd, myVar) --> │
└────────────────┬───────────────────┘
|
v
Generated Code:
┌────────────────────────────────────────────┐
│ WriteHtmlVariable(fd, myFunc(fd, myVar)); │
└────────────────┬───────────────────────────┘
|
v
Your Implementation:
┌─────────────────────────────────────────────┐
const char* myFunc(int fd, int myVar) { │
fdprintf(fd, "Value: %d", myVar); │
return ""; // Return empty string │
│ } │
└─────────────────────────────────────────────┘

Example: Temperature Formatter

htmlvar.h:**

#ifndef HTMLVARS_H_
#define HTMLVARS_H_
#include <init.h>
extern int Temperature;
// Function callback with parameter
const char *FormatTemperature(int fd, int tempC);
#endif

main.cpp:**

#include <nbrtos.h>
#include <init.h>
#include "htmlvar.h"
int Temperature = 25;
const char *FormatTemperature(int fd, int tempC)
{
// Write formatted output directly to socket
fdprintf(fd, "<span style='color: ");
if (tempC < 20) {
fdprintf(fd, "blue'>Cold: %dC", tempC);
} else if (tempC < 30) {
fdprintf(fd, "green'>Normal: %dC", tempC);
} else {
fdprintf(fd, "red'>Hot: %dC", tempC);
}
fdprintf(fd, "</span>");
// Return empty string (already wrote to socket)
return "";
}
void UserMain(void *pd)
{
init();
while (1) {
Temperature = 15 + (Secs % 25); // Vary temperature
OSTimeDly(TICKS_PER_SECOND);
}
}

index.html:**

<html>
<body>
<h1>Temperature Monitor</h1>
<!-- Pass fd and Temperature to function -->
<p>Current: <!--VARIABLE FormatTemperature(fd, Temperature) --></p>
<!-- Direct variable display for comparison -->
<p>Raw value: <!--VARIABLE Temperature --> C</p>
</body>
</html>

Multi-Parameter Function Example

htmlvar.h:**

extern int SensorValue;
extern int SensorID;
const char *DisplaySensor(int fd, int id, int value);

main.cpp:**

const char *DisplaySensor(int fd, int id, int value)
{
fdprintf(fd, "Sensor #%d: %d units", id, value);
return "";
}

index.html:**

<p><!--VARIABLE DisplaySensor(fd, SensorID, SensorValue) --></p>

Return Value Handling

Function Return Value Options
─────────────────────────────
Option 1: Write to Socket, Return Empty
┌───────────────────────────────────────┐
const char *func(int fd, int val) { │
fdprintf(fd, "Data: %d", val); │
return ""; // Nothing more │
│ } │
└───────────────────────────────────────┘
|
v
Output: "Data: 123"
Option 2: Return String for Printing
┌───────────────────────────────────────┐
const char *func(int fd, int val) { │
static char buf[80]; │
│ sprintf(buf, "Value: %d", val); │
return buf; // Printed by web │
│ } │
└───────────────────────────────────────┘
|
v
Output: "Value: 123"
Option 3: Both (Write + Return)
┌───────────────────────────────────────┐
const char *func(int fd, int val) { │
fdprintf(fd, "Start: "); │
return "End"; // Appended │
│ } │
└───────────────────────────────────────┘
|
v
Output: "Start: End"

Custom Data Types

Extend the VARIABLE tag to support user-defined structures and classes.

Custom Type Flow

Custom Type Support Architecture
─────────────────────────────────
Step 1: Define Your Type
┌────────────────────────────┐
struct MY_STRUCT { │
int value; │
char name[40]; │
│ }; │
│ │
│ MY_STRUCT myData; │
└────────────┬───────────────┘
|
v
Step 2: Declare in htmlvar.h
┌────────────────────────────────────────┐
extern MY_STRUCT myData; │
│ │
void WriteHtmlVariable(int fd, │
│ MY_STRUCT s); │
└────────────┬───────────────────────────┘
|
v
Step 3: Implement Function
┌────────────────────────────────────────┐
void WriteHtmlVariable(int fd, │
│ MY_STRUCT s) { │
fdprintf(fd, "%s: %d", │
│ s.name, s.value); │
│ } │
└────────────┬───────────────────────────┘
|
v
Step 4: Use in HTML
┌────────────────────────────────────────┐
│ <!--VARIABLE myData --> │
└────────────────────────────────────────┘

Complete Custom Type Example

main.cpp:**

#include <nbrtos.h>
#include <init.h>
// Define custom structure
struct SensorData {
int temperature;
char location[80];
uint32_t timestamp;
};
SensorData hallwaySensor;
SensorData laboratorySensor;
// Overload WriteHtmlVariable for custom type
void WriteHtmlVariable(int fd, SensorData sensor)
{
fdprintf(fd, "<div class='sensor'>");
fdprintf(fd, " <strong>Location:</strong> %s<br>", sensor.location);
fdprintf(fd, " <strong>Temperature:</strong> %dC<br>", sensor.temperature);
fdprintf(fd, " <strong>Reading Time:</strong> %lu seconds<br>", sensor.timestamp);
fdprintf(fd, "</div>");
}
void UserMain(void *pd)
{
init();
// Initialize sensors
strcpy(hallwaySensor.location, "Main Hallway");
strcpy(laboratorySensor.location, "Laboratory");
while (1) {
hallwaySensor.temperature = 20 + (Secs % 10);
hallwaySensor.timestamp = Secs;
laboratorySensor.temperature = 18 + (Secs % 8);
laboratorySensor.timestamp = Secs;
OSTimeDly(TICKS_PER_SECOND);
}
}

htmlvar.h:**

#ifndef HTMLVARS_H_
#define HTMLVARS_H_
#include <init.h>
struct SensorData {
int temperature;
char location[80];
uint32_t timestamp;
};
extern SensorData hallwaySensor;
extern SensorData laboratorySensor;
// Declare overloaded function
void WriteHtmlVariable(int fd, SensorData sensor);
#endif

index.html:**

<html>
<head>
<style>
.sensor {
border: 1px solid #ccc;
padding: 10px;
margin: 10px 0;
background-color: #f9f9f9;
}
</style>
</head>
<body>
<h1>Multi-Sensor Dashboard</h1>
<h2>Sensor 1</h2>
<!--VARIABLE hallwaySensor -->
<h2>Sensor 2</h2>
<!--VARIABLE laboratorySensor -->
<hr>
<p><small>System Time: <!--VARIABLE Secs --> seconds</small></p>
</body>
</html>

Class-Based Custom Type

class DeviceStatus {
public:
bool online;
int errorCount;
const char *version;
DeviceStatus() : online(true), errorCount(0), version("1.0.0") {}
};
DeviceStatus systemStatus;
// Overload for class
void WriteHtmlVariable(int fd, DeviceStatus status)
{
fdprintf(fd, "<table>");
fdprintf(fd, "<tr><td>Status:</td><td>%s</td></tr>",
status.online ? "Online" : "Offline");
fdprintf(fd, "<tr><td>Errors:</td><td>%d</td></tr>",
status.errorCount);
fdprintf(fd, "<tr><td>Version:</td><td>%s</td></tr>",
status.version);
fdprintf(fd, "</table>");
}

HTML usage:**

<div>
<h3>System Status</h3>
<!--VARIABLE systemStatus -->
</div>

Best Practices

Project Organization

Recommended Project Structure
─────────────────────────────
YourProject/
├── src/
│ ├── main.cpp <── Core application logic
│ ├── htmlvar.h <── Web variable declarations
│ ├── web_callbacks.cpp <── CPPCALL implementations
│ ├── web_callbacks.h <── CPPCALL declarations
│ └── htmldata.cpp <── Auto-generated (don't edit)
├── html/
│ ├── index.html <── Main page
│ ├── control.html <── Control interface
│ ├── status.html <── Status display
│ ├── styles/
│ │ └── main.css <── Stylesheets
│ ├── scripts/
│ │ └── main.js <── JavaScript
│ └── images/
│ ├── logo.png
│ └── icons/
└── makefile

Code Organization

Separate Web Logic

web_callbacks.h:**

#ifndef WEB_CALLBACKS_H_
#define WEB_CALLBACKS_H_
// CPPCALL functions
void webDeviceControl(int sock, PCSTR url);
void webSystemStatus(int sock, PCSTR url);
void webSensorData(int sock, PCSTR url);
// VARIABLE functions
const char *FormatTimestamp(int fd, unsigned long timestamp);
const char *FormatIPAddress(int fd, uint32_t ip);
#endif

web_callbacks.cpp:**

#include "web_callbacks.h"
#include <nbrtos.h>
void webDeviceControl(int sock, PCSTR url)
{
// Implementation
}
void webSystemStatus(int sock, PCSTR url)
{
// Implementation
}
// ... etc

Performance Optimization

Web Server Performance Tips
───────────────────────────
1. Minimize CPPCALL Processing
┌──────────────────────────────┐
void fastCallback(int sock, │
│ PCSTR url) │
│ { │
// Quick processing │
writestring(sock, data); │
// Exit immediately │
│ } │
└──────────────────────────────┘
v
Don't block web server thread!
2. Use VARIABLE for Simple Data
┌──────────────────────────────┐
│ <!--VARIABLE Temperature --> │
└──────────────────────────────┘
v
Faster than CPPCALL for display
3. Cache Formatted Strings
┌──────────────────────────────┐
│ static char statusBuf[256]; │
│ // Update periodically │
│ // in background task │
└──────────────────────────────┘
v
Reduce real-time formatting
4. Limit Dynamic Content
┌──────────────────────────────┐
│ Use static content where │
│ possible (HTML, CSS, JS) │
└──────────────────────────────┘

Security Considerations

Web Security Best Practices
───────────────────────────
Input Validation URL Parameter Sanitization
──────────────── ───────────────────────────
┌─────────────────────┐ ┌──────────────────────────┐
void callback( │ │ void handler(int sock, │
int sock, │ │ PCSTR url) │
│ PCSTR url) { │ │ { │
│ │ │ // BAD: Direct use │
// Validate input │ │ system(url); // NO! │
if (!isValid(url))│ │ │
│ { │ │ // GOOD: Parse & check │
writestring( │ │ char *param = │
│ sock, │ │ parseParam(url); │
"Invalid"); │ │ if (isSafe(param)) { │
return; │ │ // Use safely │
│ } │ │ } │
│ } │ │ } │
└─────────────────────┘ └──────────────────────────┘
Buffer Overflow Prevention Authentication
────────────────────────── ──────────────
┌─────────────────────┐ ┌──────────────────────────┐
char buf[256]; │ │ bool authenticated = │
│ │ │ CheckCredentials(url); │
// BAD │ │ │
│ sprintf(buf, ...); │ │ if (!authenticated) { │
│ │ │ writestring(sock, │
// GOOD │ │ "Access Denied"); │
│ sprintf(buf, │ │ return; │
sizeof(buf),...); │ │ } │
└─────────────────────┘ └──────────────────────────┘

Error Handling

void robustCallback(int sock, PCSTR url)
{
// Check socket validity
if (sock < 0) {
return;
}
// Validate URL
if (!url || strlen(url) == 0) {
writestring(sock, "Error: Invalid request");
return;
}
// Safe parameter parsing
char *param = strstr(url, "value=");
if (!param) {
writestring(sock, "Error: Missing parameter");
return;
}
// Process with bounds checking
int value = atoi(param + 6);
if (value < 0 || value > 100) {
fdprintf(sock, "Error: Value %d out of range", value);
return;
}
// Success
fdprintf(sock, "Success: Value set to %d", value);
}

HTML Best Practices

<!-- Good: Clean, organized structure -->
<html>
<head>
<title>Device Control</title>
<link rel="stylesheet" href="styles/main.css">
</head>
<body>
<header>
<h1>NetBurner Device</h1>
<p>System Time: <!--VARIABLE Secs --> seconds</p>
</header>
<main>
<section id="status">
<h2>Status</h2>
<!--CPPCALL webSystemStatus -->
</section>
<section id="control">
<h2>Control</h2>
<!--CPPCALL webDeviceControl -->
</section>
</main>
<footer>
<p>Version: <!--VARIABLE FirmwareVersion --></p>
</footer>
<script src="scripts/main.js"></script>
</body>
</html>

Testing Strategy

Web Application Testing Flow
────────────────────────────
1. Unit Test Callbacks
┌──────────────────────┐
│ Test each CPPCALL │
│ function in │
│ isolation │
└──────────┬───────────┘
|
v
2. Validate Output
┌──────────────────────┐
│ Verify VARIABLE tags │
│ display correctly │
└──────────┬───────────┘
|
v
3. Test URL Parsing
┌──────────────────────┐
│ Various query params │
│ Edge cases │
└──────────┬───────────┘
|
v
4. Load Testing
┌──────────────────────┐
│ Multiple concurrent │
│ connections │
└──────────┬───────────┘
|
v
5. Security Testing
┌──────────────────────┐
│ Invalid inputs │
│ Buffer limits │
└──────────────────────┘

Debugging Tips

// Enable debug output in callbacks
void debugCallback(int sock, PCSTR url)
{
printf("Callback called: %s\r\n", url); // To serial console
// Parse and display
char *param = strstr(url, "cmd=");
if (param) {
printf("Command parameter: %s\r\n", param);
}
// Write response
writestring(sock, "Response sent");
printf("Response complete\r\n");
}

Common Pitfalls to Avoid

Common Mistakes and Solutions
─────────────────────────────
MISTAKE SOLUTION
─────── ────────
Using printf() in callback Use writestring() or fdprintf()
┌──────────────────────┐ ┌──────────────────────┐
void bad(int sock) { │ │ void good(int sock) {│
│ printf("Hi"); │ │ writestring(sock, │
│ } │ │ "Hi"); │
└──────────────────────┘ │ } │
Output goes nowhere! └──────────────────────┘
Output to browser
Forgetting extern Declare in htmlvar.h
┌──────────────────────┐ ┌──────────────────────┐
// In main.cpp │ │ // In htmlvar.h │
int Temperature; │ │ extern int
│ │ │ Temperature; │
// Link error! │ └──────────────────────┘
└──────────────────────┘ htmldata.cpp can link
Blocking in callback Quick exit pattern
┌──────────────────────┐ ┌──────────────────────┐
void bad(int sock) { │ │ void good(int sock) {│
│ OSTimeDly(...); │ │ writestring(sock, │
// Blocks server! │ │ "OK"); │
│ } │ │ // Exit fast │
└──────────────────────┘ │ } │
└──────────────────────┘
Not validating input Always validate
┌──────────────────────┐ ┌──────────────────────┐
int val = │ │ char *p = strstr(url,│
│ atoi(url+5); │ │ "val="); │
// May crash! │ │ if (p) { │
└──────────────────────┘ │ int val=atoi(p+4); │
│ } │
└──────────────────────┘

Quick Reference

Tag Summary

NetBurner Web Tags Quick Reference
──────────────────────────────────
Tag Purpose Syntax
─── ─────── ──────
CPPCALL Execute C++ <!--CPPCALL FuncName -->
function void FuncName(int sock,
PCSTR url)
VARIABLE Display variable <!--VARIABLE VarName -->
or expression <!--VARIABLE expr -->
INCLUDE Link header file <!--INCLUDE header.h -->
for variable access
VARIABLE Function Parameterized <!--VARIABLE Func(fd, var) -->
callback const char* Func(int fd,
int var)

Function Signatures

// CPPCALL signature
void CallbackFunction(int sock, PCSTR url);
// VARIABLE function signature
const char *VariableFunction(int fd, <param_type> param);
// Custom type support
void WriteHtmlVariable(int fd, CustomType data);

Common Patterns

// Pattern 1: Simple status display
void webStatus(int sock, PCSTR url) {
fdprintf(sock, "Uptime: %lu seconds", Secs);
}
// Pattern 2: URL parameter parsing
void webControl(int sock, PCSTR url) {
if (strstr(url, "action=reset")) {
// Handle reset
writestring(sock, "Device reset");
}
}
// Pattern 3: Variable formatting
const char *FormatData(int fd, int value) {
fdprintf(fd, "<b>%d</b>", value);
return "";
}
// Pattern 4: Custom type display
void WriteHtmlVariable(int fd, MyStruct s) {
fdprintf(fd, "%s: %d", s.name, s.value);
}

Summary

The NetBurner web server provides a powerful platform for embedded web applications:

Web Server Capabilities Overview
────────────────────────────────
Static Content Dynamic Content Integration
────────────── ─────────────── ───────────
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ HTML Files │ │ CPPCALL │ │ Real-time │
│ CSS Styles │ │ - Callbacks │ │ Data │
│ JavaScript │ │ - Control │ │ Display │
│ Images │ │ │ │ │
│ Resources │ │ VARIABLE │ │ Device │
│ │ │ - Variables │ │ Control │
│ All embedded│ │ - Functions │ │ │
│ in binary │ │ - Custom │ │ Interactive │
└─────────────┘ └─────────────┘ └─────────────┘
| | |
└───────────────────────────┴─────────────────────────────┘
|
v
┌──────────────────┐
│ Unified Web │
│ Application │
└──────────────────┘

Key Takeaways

  1. Static content is compiled into the application binary
  2. CPPCALL provides flexible callback functions for dynamic control
  3. VARIABLE tags display real-time data with automatic type handling
  4. Custom types can be added by overloading WriteHtmlVariable()
  5. Security and input validation are critical for robust applications
  6. Performance is maintained by keeping callbacks fast and efficient