Understanding the Arduino Web Server Example

Hi,

I have a question in regards to the web server example for the Arduino MKR1000. I assumed that essentially different endpoints could have different functions, but I'm not sure how to implement that. I see in the example:

client.print("Click <a href=\"/H\">here</a> turn the LED on<br>");            
client.print("Click <a href=\"/L\">here</a> turn the LED off<br><br>");

Which creates links that open either "/H" or "/L". However, the code below checks for "GET /H" and "GET /L" in currentLine:

if (currentLine.endsWith("GET /H")) {       
    digitalWrite(ledPin, HIGH); 
}      
 if (currentLine.endsWith("GET /L")) {
    digitalWrite(ledPin, LOW);       
}

And I have three questions about that:

  1. Where does the "GET" come from?

  2. What is currentline and where is that data coming from?

  3. What does .endsWidth() do?

Any help or guidance would be greatly appreciated. Thank you.

The "GET" is part of the data received from the client

The currentLine String is built by concatenating each character to it as it is received

          currentLine += c;      // add it to the end of the currentLine

The endsWith() function tests whether the String used as a parameter ends with the string given

Okay thank you. And if I want to make an HTTP request to the web server from a mobile device or webpage, how would I structure the request? Is "GET" in the url, or header, or the HTTP request type (other types are POST, PATCH)? How does pressing the "/H" or "/L" button create a request with "GET" in the structure? Is that because clicking on a href link is a GET request essentially? Are there any headers required to send a HTTP request to the server, such as Content-Type?

HTML really is not my area, but using a mobile device to access the Web server is no different from using a browser on a PC when the devices are on the same network. The "magic" happens when you click on the link sent by the server

These line of code

            // the content of the HTTP response follows the header:
            client.print("<p style=\"font-size:7vw;\">Click <a href=\"/H\">here</a> turn the LED on<br></p>");
            client.print("<p style=\"font-size:7vw;\">Click <a href=\"/L\">here</a> turn the LED off<br></p>");

create the links containing /H and /L which tell the browser what to send when the links are clicked

If the devices are not on the same network then things are more complicated. What is it that you are trying to do using a mobile device ?

Essentially I'd like to build a button on a mobile app with the following logic:

if (buttonPressed) {
    sendHTTPRequest()
}

The device and Arduino would be on the same network. I'd need the following parameters: HTTP Method, Headers (content-type, auth)

Side note: Is it possible to parse headers with the Arduino WiFi library? Does the entire request go through char c = client.read() one character at a time?

Thank you for the help thus far.

Could have done with the rest of the code, but I found it here:

https://docs.arduino.cc/tutorials/mkr-1000-wifi/mkr-1000-hosting-a-webserver/

  1. GET is a HTTP protocol command that requests and fetches a resource. The resource requested in response to a button click is either "/H" or "/L".

  2. currentLine is a String variable that collects characters read from the webClient connection. This will include the the sequence "GET /H" or "GET /L" which will appear at the end of the line.

while (client.connected()) {            // loop while the client's connected
      if (client.available()) {             // if there's bytes to read from the client,
        char c = client.read();
...
        else if (c != '\r') {    // if you got anything else but a carriage return character,

      currentLine += c;      // add it to the end of the currentLine

        }
  1. .endsWith() is a built-in String method that checks whether the String being operated on (which contains the last read line) ends with the character sequence provided:
    endsWith() - Arduino Reference
1 Like

I am afraid that with my limited knowledge of HTTP I can be of very little help in that area

More generally, yes, of course you can parse a header once it has been received

1 Like

One way to learn HTTP is to use curl

$ curl -v google.com
*   Trying 2607:f8b0:4005:813::200e:80...
* Connected to google.com (2607:f8b0:4005:813::200e) port 80 (#0)
> GET / HTTP/1.1
> Host: google.com
> User-Agent: curl/7.81.0
> Accept: */*
> 
* Mark bundle as not supporting multiuse
< HTTP/1.1 301 Moved Permanently
< Location: http://www.google.com/
< Content-Type: text/html; charset=UTF-8
< Content-Security-Policy-Report-Only: object-src 'none';base-uri 'self';script-src 'nonce-yiy3q6ZL2lKLCnJyGUVTUw' 'strict-dynamic' 'report-sample' 'unsafe-eval' 'unsafe-inline' https: http:;report-uri https://csp.withgoogle.com/csp/gws/other-hp
< Date: Tue, 12 Mar 2024 08:17:29 GMT
< Expires: Thu, 11 Apr 2024 08:17:29 GMT
< Cache-Control: public, max-age=2592000
< Server: gws
< Content-Length: 219
< X-XSS-Protection: 0
< X-Frame-Options: SAMEORIGIN
< 
<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8">
<TITLE>301 Moved</TITLE></HEAD><BODY>
<H1>301 Moved</H1>
The document has moved
<A HREF="http://www.google.com/">here</A>.
</BODY></HTML>
* Connection #0 to host google.com left intact
  • -v means verbose, show both request and response
  • * are status messages
    This connected to the host google.com, defaulting to HTTP on port 80. Using https://google.com would have used TLS on port 443 instead (and even more status messages)
  • > is the (hidden when not verbose) request. Both request and response comprise four parts
    1. A single start-line. In the request, it's called the request-line
    2. Any number of headers, one per line. There's usually at least a Host, because a single IP address and port can serve multiple hosts.
    3. A blank line
    4. An optional body. GETs don't have a request body
  • < is the (normally hidden) response.
    • The start-line of the response is called the status line, which includes the status code like 200 or 404
  • The response body does not start with the < because you're supposed to get that as it was sent. (Adding an extra < will mangle HTML, for example)

GET is the default HTTP method for pretty much everything, including curl and a browser. Looking at those first two lines again

> GET / HTTP/1.1
> Host: google.com

it's trying to load google.com/. Adding the default parts, it's the more familiar http://google.com/. But what about the HTTP/1.1?

The example code has

if (currentLine.endsWith("GET /H"))

It's reading and accumulating the request, character by character into the currentLine. The server knows it only has something to do for /H and /L; and to distinguish between those two, it only has to read 6 characters total.

  • Given that logic: instead of endsWith, startsWith or equals or == would have worked as well. (Subtle differences when the request is not one of the two expected.)
  • If for example, you tried to request /Hello, that would be considered /H
  • Slightly more robust would be to look for the space between the path (plus possible query parameters) and the HTTP since spaces in URLs are encoded as %20
    "GET /H "
    "GET /L "
    

To make the request, most client libraries will do a GET by default implicitly and/or allow you to use GET explicitly. They will include the Host header. A GET doesn't really need anything else. (Accept is used for "content negotiation"; using the same URL, but requesting JSON versus HTML, or a specific image format.) Of course, if you need auth, that's a whole 'nother can of worms.

A WiFi library wouldn't help to parse HTTP headers; you'd need an HTTP client and/or server library.

1 Like

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.