WebClientRepeating Example

I am trying the code for web client repeating in the WiFi library. The output I am getting isn't the content in the url supplied in the reference page.

My output looks like this:

connecting...
HTTP/1.1 301 Moved Permanently
Content-Type: text/html
Date: Fri, 02 Jun 2017 06:17:32 GMT
Location: https://www.arduino.cc/latest.txt
Server: nginx/1.4.2
Content-Length: 184
Connection: Close

What am I doing wrong?

From the HTTP specs:

RFC2616:
10.3 Redirection 3xx

This class of status code indicates that further action needs to be taken by the user agent in order to fulfill the request. The action required MAY be carried out by the user agent without interaction with the user if and only if the method used in the second request is GET or HEAD. A client SHOULD detect infinite redirection loops, since such loops generate network traffic for each redirection.

[...]

10.3.2 301 Moved Permanently

The requested resource has been assigned a new permanent URI and any future references to this resource SHOULD use one of the returned URIs. Clients with link editing capabilities ought to automatically re-link references to the Request-URI to one or more of the new references returned by the server, where possible. This response is cacheable unless indicated otherwise.
The new permanent URI SHOULD be given by the Location field in the response. Unless the request method was HEAD, the entity of the response SHOULD contain a short hypertext note with a hyperlink to the new URI(s).
If the 301 status code is received in response to a request other than GET or HEAD, the user agent MUST NOT automatically redirect the request unless it can be confirmed by the user, since this might change the conditions under which the request was issued.

This means that when you get a HTTP 301 response to a GET request, you have to send a new GET request to the URI specified in the Location header.

Pieter

The URL used to be http://www.arduino.cc/latest.txt but it now redirects to https://www.arduino.cc/latest.txt, which broke update notifications in the IDE and the WebClientRepeating example sketch in the WiFi and Ethernet libraries.

abhir24:
I am trying the code for web client repeating in the WiFi library. The output I am getting isn't the content in the url supplied in the reference page.

What am I doing wrong?

You are missing to do another request:

Statuscode 301 (redirection" along with "Location: https://www.arduino.cc/latest.txt" tells you clearly what to do:

Use secure https:// protocol instead of normal http:// and do another request to the given locaton!

Maybe you try to ask a server for a file, which is not available
Or you ask the server by using http, while the server insists on htttps://

In case you see statuscode 301 or302 with a Location: header, IT IS UP TO YOU:

In case you follow the HTTP standards, you have to do another request as the server tells you in the location header!

The problem is: You dont't seem to follow the Location:" and simply ignore the server response.

They're using the WebClientRepeating example sketch included with the official WiFi library:

I don't think the WiFi library even supports https://

PieterP:
From the HTTP specs:
This means that when you get a HTTP 301 response to a GET request, you have to send a new GET request to the URI specified in the Location header.

Pieter

I am new to http. Can you please explain what you meant by location header? Or, rather tell me some reference where I can learn this from?

jurs:
You are missing to do another request:

Statuscode 301 (redirection" along with "Location: https://www.arduino.cc/latest.txt" tells you clearly what to do:

Use secure https:// protocol instead of normal http:// and do another request to the given locaton!

Maybe you try to ask a server for a file, which is not available
Or you ask the server by using http, while the server insists on htttps://

In case you see statuscode 301 or302 with a Location: header, IT IS UP TO YOU:

In case you follow the HTTP standards, you have to do another request as the server tells you in the location header!

The problem is: You dont't seem to follow the Location:" and simply ignore the server response.

I think this is getting a bit clearer to me. I am very new to http and https. I just started of with this example. I think I will need to learn a bit more re: http and https. Can you suggest me possible resources?

abhir24:
I am new to http. Can you please explain what you meant by location header? Or, rather tell me some reference where I can learn this from?

HTTP stands for HyperText Transfer Protocol, meaning that it is text-based. There are two important HTTP request methods: GET and POST. Let's focus on GET for now. A client (e.g. Arduino) sends a GET request to an HTTP server (e.g. https://www.arduino.cc). The request only contains a header: this is a piece of text that tells the server what to do. The header has two parts:

  1. The request line:
GET /latest.txt HTTP/1.1

It tells the server what method is used, what URI is requested, and what version of the HTTP protocol is used.
The URI (Uniform Resource Identifier) points to a unique file in the server's file system, this is handled by the web server. (A URI doesn't have to be a file, but for most web servers, it is.)
2. The header fields (sometimes called "headers"):

Host: www.arduino.cc
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
DNT: 1

These fields contain some extra information for the server: for example, the host name of the server, what kind of user agent made the request, what kind of response file types the client accepts, and so on.
Generally, these header fields are of the format "key: value". Each header field is followed by a carriage return and a line feed (\r\n). An empty line (\r\n\r\n) indicates the end of the header.

When the server processes the request, and it's able to execute that request without problems, it will respond with an HTTP status code of 200 (Ok):

HTTP/1.1 200 OK

This is then followed by the response header fields:

Date: Tue, 06 Jun 2017 09:53:05 GMT
Last-Modified: Wed, 01 Sep 2004 13:24:52 GMT
ETag: "277f-3e3073913b100-gzip"
Accept-Ranges: bytes
Vary: Accept-Encoding
Content-Type:text/html; charset=UTF-8
Content-Encoding: gzip
Cache-Control: max-age=21600
Expires: Tue, 06 Jun 2017 15:53:05 GMT

These headers contain some information about the server, and some information about the file, for example, the date it was last modified, the file type, how the file was encoded, some cache control data, and so on.
Again, an empty line (\r\n\r\n) indicates the end of the header. After the header, the actual response or file is sent.

However, if the request could not be processed, a status code other than 200 will be sent. Section 10 of the HTTP/1.1 specification tells you what to do in case of these status codes.

For example, if the server responds with

HTTP/1.1 301 Moved Permanently
Content-Type: text/html
Date: Fri, 02 Jun 2017 06:17:32 GMT
Location: https://www.arduino.cc/latest.txt
Server: nginx/1.4.2
Content-Length: 184
Connection: Close

This means that the file has been moved, and that you have to send a new GET request to the new URL, that is specified in the Location header field (https://www.arduino.cc/latest.txt, in this case).

Pieter

PieterP:
HTTP stands for HyperText Transfer Protocol, meaning that it is text-based. There are two important HTTP request methods: GET and POST. Let's focus on GET for now. A client (e.g. Arduino) sends a GET request to an HTTP server (e.g. https://www.arduino.cc). The request only contains a header: this is a piece of text that tells the server what to do. The header has two parts:

  1. The request line:
GET /latest.txt HTTP/1.1

It tells the server what method is used, what URI is requested, and what version of the HTTP protocol is used.
The URI (Uniform Resource Identifier) points to a unique file in the server's file system, this is handled by the web server. (A URI doesn't have to be a file, but for most web servers, it is.)
2. The header fields (sometimes called "headers"):

Host: www.arduino.cc

Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8
DNT: 1



These fields contain some extra information for the server: for example, the host name of the server, what kind of user agent made the request, what kind of response file types the client accepts, and so on.
Generally, these header fields are of the format "key: value". Each header field is followed by a carriage return and a line feed (\r\n). An empty line (\r\n\r\n) indicates the end of the header.

When the server processes the request, and it's able to execute that request without problems, it will respond with an HTTP status code of 200 (Ok):


HTTP/1.1 200 OK



This is then followed by the response header fields:


Date: Tue, 06 Jun 2017 09:53:05 GMT
Last-Modified: Wed, 01 Sep 2004 13:24:52 GMT
ETag: "277f-3e3073913b100-gzip"
Accept-Ranges: bytes
Vary: Accept-Encoding
Content-Type:text/html; charset=UTF-8
Content-Encoding: gzip
Cache-Control: max-age=21600
Expires: Tue, 06 Jun 2017 15:53:05 GMT



These headers contain some information about the server, and some information about the file, for example, the date it was last modified, the file type, how the file was encoded, some cache control data, and so on.
Again, an empty line (\r\n\r\n) indicates the end of the header. After the header, the actual response or file is sent.

However, if the request could not be processed, a status code other than 200 will be sent. [Section 10 of the HTTP/1.1 specification](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html) tells you what to do in case of these status codes.

For example, if the server responds with 


HTTP/1.1 301 Moved Permanently
Content-Type: text/html
Date: Fri, 02 Jun 2017 06:17:32 GMT
Location: https://www.arduino.cc/latest.txt
Server: nginx/1.4.2
Content-Length: 184
Connection: Close



This means that the file has been moved, and that you have to send a new GET request to the new URL, that is specified in the *Location* header field (https://www.arduino.cc/latest.txt, in this case).

Pieter

Thank you Pieter for such a beautiful explanation. Now I am clearer about a few things and I also have got a direction into what all I need to learn and look at. I was trying out a post request like this and have been getting errors in what I am doing. The status I get is -2 (Can't find this among the standard error codes) and the response is empty. Any clue as to how to do it? I am using the ArduinoHttpClient library for this.

I am using the ArduinoHttpClient library for this.

The name of the library is a useful search term. YOU do the searching, and post a link to the library you found. That way, we'll all be talking about the SAME library.

PaulS:
The name of the library is a useful search term. YOU do the searching, and post a link to the library you found. That way, we'll all be talking about the SAME library.

It is a library available in the manage libraries tab. I downloaded it from there. And, having tried the post example with some modifications, I was saying that I got are response which looked like below...

#include <ArduinoHttpClient.h>
#include <SPI.h>
#include <WiFi.h>
#include "config.h"

//char ssid[] = "JioFi2_C5E559"; //  your network SSID (name)
//char pass[] = "8nfdtyc8jf";    // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0;            // your network key Index number (needed only for WEP)

int status = WL_IDLE_STATUS;
char serverAddress[] = "http://35.154.192.57/smart_stove/api.php/checkText";    // name address for Google (using DNS)
int port = 8080;

WiFiClient client;
HttpClient client1 = HttpClient(client, serverAddress, port);
String response;
int statusCode = 0;

void setup() {
  //Initialize serial and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only
  }

  // check for the presence of the shield:
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // don't continue:
    while (true);
  }

  String fv = WiFi.firmwareVersion();
  if (fv != "1.1.0") {
    Serial.println("Please upgrade the firmware");
  }

  // attempt to connect to Wifi network:
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);

    // wait 10 seconds for connection:
    delay(10000);
  }
  Serial.println("Connected to wifi");
  printWifiStatus();

}


void loop() {
  // if there are incoming bytes available
  // from the server, read them and print them:
  
  Serial.println("making POST request");
  String contentType = "application/json";
  String postData = "one";

  client1.post("/", contentType, postData);

  // read the status code and body of the response
  statusCode = client1.responseStatusCode();
  response = client1.responseBody();

  Serial.print("Status code: ");
  Serial.println(statusCode);
  Serial.print("Response: ");
  Serial.println(response);

  //Serial.println("Wait five seconds");
  //delay(5000);
  
  // if the server's disconnected, stop the client:
  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting from server.");
    client.stop();

    // do nothing forevermore:
    while (true);
  }
}


void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}

response:

Attempting to connect to SSID: JioFi2_C5E559
Connected to wifi
SSID: JioFi2_C5E559
IP Address: 192.168.1.101
signal strength (RSSI):-56 dBm
making POST request
Status code: -2
Response:

disconnecting from server.

char serverAddress[] = "http://35.154.192.57/smart_stove/api.php/checkText";    // name address for Google (using DNS)

That is NOT a server address. NO server anywhere uses http in its name. The server address is "35.154.192.57". NONE of the rest of that mess is the server address.

If the VALUE is supposed to be more than the address, then the name is stupid.

PaulS:

char serverAddress[] = "http://35.154.192.57/smart_stove/api.php/checkText";    // name address for Google (using DNS)

That is NOT a server address. NO server anywhere uses http in its name. The server address is "35.154.192.57". NONE of the rest of that mess is the server address.

If the VALUE is supposed to be more than the address, then the name is stupid.

I am new to this. I am glad you shared your input. So the server is just that. I will try going over the code again to make it work, because just changing the server address part didnt seem to change the output for me.

Also to find relevant documents which describe the variables going into the function in the library is a problem I am facing.

abhir24:
Also to find relevant documents which describe the variables going into the function in the library is a problem I am facing.

"I found the library in the library manager" is NO help. The library got downloaded from somewhere, and I'm pretty sure you were told where. If you elect not to share that information, you can't expect us to help you.

The repository of the library:

abhir24's issue report:

PaulS:
"I found the library in the library manager" is NO help. The library got downloaded from somewhere, and I'm pretty sure you were told where. If you elect not to share that information, you can't expect us to help you.

To be very honest, I am not choosing to NOT share information. I searched for HTTP post supporting libraries on include library > Manage library > http post, where I found this ArduinoHttpClient library, version 0.3.0

I have only done a IoT related project using an mqtt server adafruit.io
This all is very new to me and I am struggling to get through with a post request. I am basically a mechanical engineer with some experience in Arduino in using sensors and running motors and nothing more.

Typically, one makes either a GET request or a POST request, to send data to a script. The GET request is far simpler. The POST request is used when you want to hide data. I can't imagine why you want to hide "one".

Obviously you knew that information since you knew where to submit an issue report.

I don't know why you created an issue report when you have multiple people here actively trying to help you.

From ArduinoHttpClient/src/HttpClient.h at master · arduino-libraries/ArduinoHttpClient · GitHub

// This call was made when the HttpClient class wasn't expecting it

// to be called.  Usually indicates your code is using the class
// incorrectly
static const int HTTP_ERROR_API =-2;

PaulS:
Typically, one makes either a GET request or a POST request, to send data to a script. The GET request is far simpler. The POST request is used when you want to hide data. I can't imagine why you want to hide "one".

I do not want to hide it. I imagined it as GET as in getting data from a server and POST as posting data to a server. I have been able to get GET working.