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:
Where does the "GET" come from?
What is currentline and where is that data coming from?
What does .endsWidth() do?
Any help or guidance would be greatly appreciated. Thank you.
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?
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".
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
}
.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
$ 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
A single start-line. In the request, it's called the request-line
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.
A blank line
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.