Wifi101 File Server from SD Card

Hi all,

Im working on an simple HTTP Server which serves files from the SD card. The difference to most of the ready made examples ist that it should serve most of the files and types recognized by the GET request.

The server is running on a MKR1000. It creates a Acces Point. For the beginning (testing purpose) it differentiates between two get request types. One is the simple "GET / " which will trigger when you request http://192.168.1.1 and everything else which will trigger (for example) at http://192.168.1.1/index.htm

The first function is working,it just sends the GET answer and the index.htm. But somehow 192.168.1.1/index.htm doesnt work and I get the Parsing error on my browser.

Otherwise, here is my code:

#include <SPI.h>
#include <SD.h>
#include <WiFi101.h>
// size of buffer used to capture HTTP requests
#define REQ_BUF_SZ   20

// MAC address from Ethernet shield sticker under board
char ssid[] = "wifi101-network"; // created AP name
int status = WL_IDLE_STATUS;
WiFiServer server(80);
File webFile;
char HTTP_req[REQ_BUF_SZ] = {0}; // buffered HTTP request stored as null terminated string
char FileName[10];
char req_index = 0;              // index into HTTP_req buffer

void setup()
{
  Serial.begin(9600);       // for debugging
  delay(2000);
  //digitalWrite(10, HIGH);



  // initialize SD card
  Serial.println("Initializing SD card...");
  if (!SD.begin(6)) {
    Serial.println("ERROR - SD card initialization failed!");
    return;    // init failed
  }
  Serial.println("SUCCESS - SD card initialized.");
  // check for index.htm file
  if (!SD.exists("index.htm")) {
    Serial.println("ERROR - Can't find index.htm file!");
    return;  // can't find index file
  }
  Serial.println("SUCCESS - Found index.htm file.");

  status = WiFi.beginAP(ssid);
  if (status != WL_AP_LISTENING) {
    Serial.println("Creating access point failed");
    // don't continue
    while (true);
  }

  // wait 10 seconds for connection:
  delay(10000);

  // start the web server on port 80
  server.begin();
}

void loop()
{
  WiFiClient client = server.available();  // try to get client

  if (client) {  // got client?
    boolean currentLineIsBlank = true;
    while (client.connected()) {
      if (client.available()) {   // client data available to read
        char c = client.read(); // read 1 byte (character) from client
        // buffer first part of HTTP request in HTTP_req array (string)
        // leave last element in array as 0 to null terminate string (REQ_BUF_SZ - 1)
        if (req_index < (REQ_BUF_SZ - 1)) {
          HTTP_req[req_index] = c;          // save HTTP request character
          req_index++;
        }
        // print HTTP request character to Serial monitor
        Serial.print(c);
        // last line of client request is blank and ends with \n
        // respond to client only after last line received
        if (c == '\n' && currentLineIsBlank) {
          // open requested web page file
          
          if (strstr (HTTP_req, "GET / ") != 0) {
            client.println("HTTP/1.1 200 OK");
            client.println("Content-Type: text/html");
            client.println("Connnection: close");
            client.println();
            webFile = SD.open("index.htm");        // open web page file
          }
          else if (strstr (HTTP_req, "GET /") != 0) {
            char *fname;
            fname = HTTP_req + 5; // look after the "GET /" (5 chars)
            
            // look for the " HTTP/1.1" string and
            // turn the first character of the substring into a 0 to clear it out.
            (strstr (HTTP_req, " HTTP"))[0] = 0;

            const char *ending = get_filename_ext(fname);
            webFile = SD.open(fname);

            if (webFile) {
              client.println("HTTP/1.1 200 OK");

              if (strstr (HTTP_req, "js") != 0) {
                client.println("Content-Type: application/javascript");
              }
              else if (strstr (HTTP_req, "htm") != 0) {
                client.println("Content-Type: text/html");
              }
              else if (strstr (HTTP_req, "html") != 0) {
                client.println("Content-Type: text/html");
              }
              else if (strstr (HTTP_req, "css") != 0) {
                client.println("Content-Type: text/css");
              }
              else if (strstr (HTTP_req, "ico") != 0) {
                client.println("Content-Type: image/x-icon");
              }
            }
            else {
              Serial.print("Cant open: ");
              Serial.println(fname);
            }
          }
          if (webFile) {
            while (webFile.available()) {
              client.write(webFile.read()); // send web page to client
            }
            webFile.close();
          }
          // reset buffer index and all buffer elements to 0
          req_index = 0;
          chrClear(HTTP_req, REQ_BUF_SZ);
          break;
        }
        // every line of text received from the client ends with \r\n
        if (c == '\n') {
          // last character on line of received text
          // starting new line with next character read
          currentLineIsBlank = true;
        }
        else if (c != '\r') {
          // a text character was received from client
          currentLineIsBlank = false;
        }
      } // end if (client.available())
    } // end while (client.connected())
    delay(1);      // give the web browser time to receive the data
    client.stop(); // close the connection
  } // end if (client)
}

// sets every element of str to 0 (clears array)
void chrClear(char *str, char length)
{
  for (int i = 0; i < length; i++) {
    str[i] = 0;
  }
}


const char *get_filename_ext(const char *filename) {
  const char *dot = strrchr(filename, '.');
  if (!dot || dot == filename) return "";
  return dot + 1;
}

char StrContains(char *str, char *sfind) {
  char found = 0;
  char index = 0;
  char len;

  len = strlen(str);

  if (strlen(sfind) > len) {
    return 0;
  }
  while (index < len) {
    if (str[index] == sfind[found]) {
      found++;
      if (strlen(sfind) == found) {
        return 1;
      }
    }
    else {
      found = 0;
    }
    index++;
  }

  return 0;
}

Working if I just type 192.168.1.1

GET / HTTP/1.1
Host: 192.168.1.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: de-de
Connection: keep-alive
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/601.7.7 (KHTML, like Gecko) Version/9.1.2 Safari/601.7.7

What I get when I request 192.168.1.1/index.htm. This error appears 3 times (I think it is just because the browser requested it 3 tiimes (?)).

GET /index.htm HTTP/1.1
Host: 192.168.1.1
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: de-de
Connection: keep-alive
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/601.7.7 (KHTML, like Gecko) Version/9.1.2 Safari/601.7.7

The error on my Computer says

cannot parse response" (NSURLErrorDomain:-1017)

Thanks!

EDIT: and my index.htm looks like this

<html>
<header><title>This is title</title></header>
<body>
Hello world
</body>
</html>
  // wait 10 seconds for connection:
  delay(10000);

  // start the web server on port 80
  server.begin();

Pretty dumb comments. You are NOT waiting for the connection to happen. You are waiting uselessly.

Why do you claim that you are going to return different types of data, when you return the same type, regardless of what the client asked for?

You don't finish sending the header. In the first case you have:

            client.println("HTTP/1.1 200 OK");
            client.println("Content-Type: text/html");
            client.println("Connnection: close");
            client.println();

followed by the contents of the file.

In the second case you have:

            client.println("HTTP/1.1 200 OK");
            client.println("Content-Type: text/html");

followed by the contents of the file. You didn't send the "Connection:" header line or THE EMPTY LINE THAT SIGNALS THE END OF THE HEADER. Your file becomes part of the header and doesn't maker sense.