Starting Electronics needs your help! Please make a donation to help cover our hosting and other costs. Click the donate button to send a donation of any amount.

Basic Arduino Web Server Code

Created on: 28 May 2015

Basic Web Server Code Version 0.1

This basic Arduino web server sketch supports hosting various file types stored on an SD card. The purpose of the web server is for educational purposes and is a supplement to the Arduino Ethernet shield web server tutorial.

The web server tutorial explains several technologies and concepts that enable anyone to design a web server, but uses hard-coded web page files. This web server code shows how to handle requests for web pages with different names as well as external files such as images, CSS and JavaScript.

The web server code is commented and with an understanding of the web server tutorial, should make a good starting point for anyone wanting to make a web server that handles multiple file types. JavaScript and CSS files that were embedded in the HTML web page file can now be stored as external files and used by multiple web pages.

Example web pages and external files are available to download below and copy to an SD card.

Web Server Specification and Limitations

Specification

This basic web server has the following specifications:

  • Hosts web pages and files on an SD card.
  • Runs on the Arduino Uno and MEGA with Ethernet shield.
  • Runs on the Arduino Ethernet board (Arduino with built-in Ethernet).
  • Supports the following file types:
    • HTML – HTML web pages.
    • ICO – icon file for favicon.
    • CSS – style sheets.
    • JavaScript – script files.
    • JPG images.
    • PNG images.
    • GIF images.
    • Plain text files.
  • Should run on other Arduino boards with Ethernet capabilities.

Limitations

The web server is intended for educational purposes and does not contain any security that prevents hacking or operations that are not expected.

Files names are limited to 8.3 format – maximum file name length of eight characters; maximum file name extension of three characters.

Web Server Code

The form below allows you to cusomize the code for your own system. Fill in the form with your parameters and then click the Generate Code button to update the code with your personal settings. The code can then be copied and pasted to the Arduino IDE.

Change these settings to suit your network and Arduino board. After making changes, click the Generate Code button to apply the changes to the Arduino sketch below. Click the Select Code button to select the code for copying.

MAC:

: : : : :
MAC address found on sticker on bottom of Ethernet shield

IP:

. . .
IP address that the Arduino will be at

Gateway:

. . .
Router gateway address

Subnet:

. . .
Subnet mask

Port:


Port of the Arduino – default for HTTP is 80


After making changes in any of the fields above, click this button to update the code below


Select the code below before copying

// Basic Arduino Web Server version 0.1 
// 27 May 2015
// References and further information at:
// http://startingelectronics.org/software/arduino/web-server/basic-01/
#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>

// maximum length of file name including path
#define FILE_NAME_LEN  20
// HTTP request type
#define HTTP_invalid   0
#define HTTP_GET       1
#define HTTP_POST      2

// file types
#define FT_HTML       0
#define FT_ICON       1
#define FT_CSS        2
#define FT_JAVASCRIPT 3
#define FT_JPG        4
#define FT_PNG        5
#define FT_GIF        6
#define FT_TEXT       7
#define FT_INVALID    8

// pin used for Ethernet chip SPI chip select
#define PIN_ETH_SPI   10

// the media access control (ethernet hardware) address for the shield:
const byte mac[] PROGMEM = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
//the IP address for the shield:
const byte ip[] = { 192, 168, 0, 20 };  // does not work if this is put into Flash
// the router's gateway address:
const byte gateway[] PROGMEM = { 192, 168, 0, 1 };
// the subnet:
const byte subnet[] PROGMEM = { 255, 255, 255, 0 };

EthernetServer server(80);

void setup() {
  // deselect Ethernet chip on SPI bus
  pinMode(PIN_ETH_SPI, OUTPUT);
  digitalWrite(PIN_ETH_SPI, HIGH);
  
  Serial.begin(115200);       // for debugging
  
  if (!SD.begin(4)) {
    return;  // SD card initialization failed
  }
  Ethernet.begin((uint8_t*)mac, ip, gateway, subnet);
  server.begin();  // start listening for clients
}

void loop() {
  // if an incoming client connects, there will be bytes available to read:
  EthernetClient client = server.available();
  if (client) {
    while (client.connected()) {
      if (ServiceClient(&client)) {
        // received request from client and finished responding
        break;
      }
    }  // while (client.connected())
    delay(1);
    client.stop();
  }  // if (client)
}// void loop()

bool ServiceClient(EthernetClient *client)
{
  static boolean currentLineIsBlank = true;
  char cl_char;
  File webFile;
  // file name from request including path + 1 of null terminator
  char file_name[FILE_NAME_LEN + 1] = {0};  // requested file name
  char http_req_type = 0;
  char req_file_type = FT_INVALID;
  const char *file_types[] = {"text/html", "image/x-icon", "text/css", "application/javascript", "image/jpeg", "image/png", "image/gif", "text/plain"};
  
  static char req_line_1[40] = {0};  // stores the first line of the HTTP request
  static unsigned char req_line_index = 0;
  static bool got_line_1 = false;

  if (client->available()) {   // client data available to read
    cl_char = client->read();
    
    if ((req_line_index < 39) && (got_line_1 == false)) {
      if ((cl_char != '\r') && (cl_char != '\n')) {
        req_line_1[req_line_index] = cl_char;
        req_line_index++;
      }
      else {
        got_line_1 = true;
        req_line_1[39] = 0;
      }
    }
    
    if ((cl_char == '\n') && currentLineIsBlank) {
      // get HTTP request type, file name and file extension type index
      http_req_type = GetRequestedHttpResource(req_line_1, file_name, &req_file_type);
      if (http_req_type == HTTP_GET) {         // HTTP GET request
        if (req_file_type < FT_INVALID) {      // valid file type
          webFile = SD.open(file_name);        // open requested file
          if (webFile) {
            // send a standard http response header
            client->println(F("HTTP/1.1 200 OK"));
            client->print(F("Content-Type: "));
            client->println(file_types[req_file_type]);
            client->println(F("Connection: close"));
            client->println();
            // send web page
            while(webFile.available()) {
              int num_bytes_read;
              char byte_buffer[64];
              // get bytes from requested file
              num_bytes_read = webFile.read(byte_buffer, 64);
              // send the file bytes to the client
              client->write(byte_buffer, num_bytes_read);
            }
            webFile.close();
          }
          else {
            // failed to open file
          }
        }
        else {
          // invalid file type
        }
      }
      else if (http_req_type == HTTP_POST) {
        // a POST HTTP request was received
      }
      else {
        // unsupported HTTP request received
      }
      req_line_1[0] = 0;
      req_line_index = 0;
      got_line_1 = false;
      // finished sending response and web page
      return 1;
    }
    if (cl_char == '\n') {
      currentLineIsBlank = true;
    }
    else if (cl_char != '\r') {
      currentLineIsBlank = false;
    }
  }  // if (client.available())
  return 0;
}

// extract file name from first line of HTTP request
char GetRequestedHttpResource(char *req_line, char *file_name, char *file_type)
{
  char request_type = HTTP_invalid;  // 1 = GET, 2 = POST. 0 = invalid
  char *str_token;
  
  *file_type = FT_INVALID;
  
  str_token =  strtok(req_line, " ");    // get the request type
  if (strcmp(str_token, "GET") == 0) {
    request_type = HTTP_GET;
    str_token =  strtok(NULL, " ");      // get the file name
    if (strcmp(str_token, "/") == 0) {
      strcpy(file_name, "index.htm");
      *file_type = FT_HTML;
    }
    else if (strlen(str_token) <= FILE_NAME_LEN) {
      // file name is within allowed length
      strcpy(file_name, str_token);
      // get the file extension
      str_token = strtok(str_token, ".");
      str_token = strtok(NULL, ".");
      
      if      (strcmp(str_token, "htm") == 0) {*file_type = 0;}
      else if (strcmp(str_token, "ico") == 0) {*file_type = 1;}
      else if (strcmp(str_token, "css") == 0) {*file_type = 2;}
      else if (strcmp(str_token, "js")  == 0) {*file_type = 3;}
      else if (strcmp(str_token, "jpg") == 0) {*file_type = 4;}
      else if (strcmp(str_token, "png") == 0) {*file_type = 5;}
      else if (strcmp(str_token, "gif") == 0) {*file_type = 6;}
      else if (strcmp(str_token, "txt") == 0) {*file_type = 7;}
      else {*file_type = 8;}
    }
    else {
      // file name too long
    }
  }
  else if (strcmp(str_token, "POST") == 0) {
    request_type = HTTP_POST;
  }

  return request_type;
}

SD Card Files

These sample files can be copied to the SD card to demonstrate use of the supported file types:

Download the files: SD_files.zip (101.3 kB)

The files have the following purpose:

  • index.htm – web server home page, demonstrates linking to another page, runs a simple JavaScript function.
  • pics.htm – second HTML page that links back to the home page.
  • favicon.ico – small icon requested by browser and displayed in browser next to page tab and bookmark.
  • styles.css – CSS styles are stored in this external file and used by both HTML pages.
  • script.js – external JavaScript file used by the home page to run a simple function.
  • arduino.jpg – JPEG image file displayed on the second HTML page.
  • websrvr.png – PNG image file displayed on the second HTML page.
  • p1.gif – animated GIF image file displayed on the second HTML page.
  • robots.txt – text file set to discourage robots from indexing the website.

References

Arduino (arduino.cc)

Arduino web server example WebServer. Code can be found in the Arduino IDE under File → Examples → Ethernet → WebServer

Arduino Ethernet Library Reference.

Arduino SD Library Reference and examples from the IDE found under File → Examples → SD

Starting Electronics

Arduino Ethernet shield web server tutorial – explains web and web server technology in a series of tutorials.

Programming and using an Arduino Ethernet board – an Arduino Ethernet board is like an Arduino Uno, but has built in Ethernet and no USB port.

Connecting and testing an Arduino Ethernet shield – how to test an Arduino Ethernet shield or other Arduino Ethernet enabled board.

Testing an Arduino Ethernet shield SD card – testing the SD card socket on an Arduino Ethernet shield or other Arduino board that has an SD card.

Arduino User Contributed Code and Discussion

WebServerST – web server by SurferTim.

More information and discussion at the Arduino forum.

Books that may interest you:

C Programming with Arduino Book Ultimate Arduino MEGA 2560 Hardware Manual Ultimage Arduino Uno Hardware Manual

New Book: Explore ATtiny Microcontrollers using C and Assembly Language

Explore ATtiny Microcontrollers using C and Assembly Language book Ultimate Arduino Uno Hardware Manual

As an Amazon Associate I earn from qualifying purchases: