I'm trying to use the rest API for the Firebase Realtime Database to transmit data from a Controllino MAXI (essentially an arduino mega 2560 with an ethernet chip) to the database. But I'm having trouble with the HTTP request. All types of requests fail but I'm interested in the PUT request.
Using this online tool, the PUT request works, here's the raw data:
PUT /.json HTTP/1.1
Host: *rtdb-name*.firebaseio.com
Content-Type: application/json
Content-Length: 26
{"message":"hello world!"}
That request returns this response:
{
"message": "hello world!"
}
And these headers:
Server: nginx
Date: Wed, 03 Feb 2021 17:02:55 GMT
Content-Type: application/json; charset=utf-8
Content-Length: 26
Connection: keep-alive
Access-Control-Allow-Origin: *
Cache-Control: no-cache
Strict-Transport-Security: max-age=31556926; includeSubDomains; preload
And writes the data to the root of the realtime db:
But when I do the same thing on the arduino using the Ethernet library:
char server[] = "rtdb-name.firebaseio.com"
if (client.connect(server,80)){
String data = "{\"message\":\"hello world!\"}";
Serial.println("connected");
client.println("PUT /.json HTTP/1.1");
client.println("Host: *rtdb-name*.firebaseio.com");
client.println("User-Agent: Arduino/1.0");
client.println("Cache-Control: no-cache, no-store, must-revalidate");
client.println("Pragma: no-cache");
client.println("Expires: 0");
client.println("Content-Type: application/json");
client.println("Connection: close");
client.print("Content-Length: ");
client.println(data.length());
client.println();
client.println(data);
while(client.connected()) {
while (client.available()) {
char c = client.read();
Serial.print(c);
}
}
client.stop();
Serial.println("disconnected");
}else{
Serial.println("Failed to connect to server");
}
I get a 404 error:
HTTP/1.1 404 Not Found
Content-Type: text/html; charset=UTF-8
Referrer-Policy: no-referrer
Content-Length: 1566
Date: Wed, 03 Feb 2021 17:06:07 GMT
Connection: close
I'm not entirely sure how to make this work. I think it's because the website uses HTTPS and the Mega can only do HTTP? Any assistance would be appreciated
For realtime datalogging with arduino, nodemcu, consider about using MQTT.
Should have just started with the documentation:
You can use any Firebase Realtime Database URL as a REST endpoint. All
you need to do is append .json to the end of the URL and send a
request from your favorite HTTPS client.
HTTPS is required. Firebase only responds to encrypted traffic so that
your data remains safe.
The Arduino (Nano, UNO, Mega and the like) simply don't have the power to do SSL (HTTPS) which is necessary to communicate with Firebase.
I've gone ahead and created a Netlify function that responds to a HTTP POST request from the Arduino and then that function writes the data to Firebase. I got the idea from this tutorial.
As suggested below you can use an MQTT broker.
Related
I am trying to fetch data from a website using sockets and I am getting a redirect but the redirect is same as the previous url
The below code works perfectly
import requests
r = requests.get('https://links.papareact.com/f90',
allow_redirects=False)
print(r.status_code)
print(r.headers["location"])
Here is the output Location header is new url
301
http://pngimg.com/uploads/amazon/amazon_PNG11.png
Here is the socket code which behaves weird
import socket
HOST = "links.papareact.com"
PORT = 80
path = "f90"
headers = f"GET /{path} HTTP/1.1\r\n" + \
f"Host: {HOST}\r\n\r\n"
connection = (HOST, PORT)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect(connection)
s.send(headers.encode())
while True:
data = s.recv(4096).decode().strip()
if data.endswith("\r\n\r\n") or not data:
break
print(data)
Output
HTTP/1.1 301 Moved Permanently
Date: Tue, 17 Aug 2021 09:15:33 GMT
Transfer-Encoding: chunked
Connection: keep-alive
Cache-Control: max-age=3600
Expires: Tue, 17 Aug 2021 10:15:33 GMT
Location: https://links.papareact.com/f90
Report-To: {"endpoints":[{"url":"https:\/\/a.nel.cloudflare.com\/report\/v3?s=0ptwEG6zbfCPDGYczBruC%2FNuMmmsfwqSd6emUpu2aRIa9JtNvIpV3rcWZjfdMrP7EV9EM94UxTx4XbEk4P6KBk4PIb%2BLxPrwitq1Fo10u%2FtGnJnCFqFFh8XGutpJsIy13zCaUYGf"}],"group":"cf-nel","max_age":604800}
NEL: {"success_fraction":0,"report_to":"cf-nel","max_age":604800}
Server: cloudflare
CF-RAY: 6801cc6c5d301d14-BLR
alt-svc: h3-27=":443"; ma=86400, h3-28=":443"; ma=86400, h3-29=":443"; ma=86400, h3=":443"; ma=86400
Here the Location Header is same as the previous url
Please explain why is this happening and a possible solution to get the expected result ? :(
Here is the socket code which behaves weird
Nothing weird here. The redirect is according to the location header to https:// (encrypted, port 443) while your original request was for http:// (not encrypted, port 80).
This is a pretty common behavior of web sites that they redirect a plain HTTP request to the same path with HTTPS. If you then access this new (HTTPS) location you would likely get the same redirect as you did with your requests.get('https://..., i.e. to http://pngimg.com/uploads/amazon/amazon_PNG11.png.
I have a server using the google Drive API. I tried with a curl PUT request to upload a simple file (test.txt) at http://myserver/test.txt. As you can see, I did the PUT request at the root of my server. The response I get is the following:
HTTP/1.1 200 OK
X-GUploader-UploadID: AEnB2UqANa4Bj6ilL7z5HZH0wlQi_ufxDiHPtb2zq1Gzcx7IxAEcOt-AOlWsbX1q_lsZUwWt_hyKOA3weAeVpQvPQTwbQhLhIA
ETag: "6e809cbda0732ac4845916a59016f954"
x-goog-generation: 1548877817413782
x-goog-metageneration: 1
x-goog-hash: crc32c=jwfJwA==
x-goog-hash: md5=boCcvaBzKsSEWRalkBb5VA==
x-goog-stored-content-length: 6
x-goog-stored-content-encoding: identity
Content-Type: text/html; charset=UTF-8
Accept-Ranges: bytes
Via: 1.1 varnish
Content-Length: 0
Accept-Ranges: bytes
Date: Wed, 30 Jan 2019 19:50:17 GMT
Via: 1.1 varnish
Connection: close
X-Served-By: cache-bwi5139-BWI, cache-cdg20732-CDG
X-Cache: MISS, MISS
X-Cache-Hits: 0, 0
X-Timer: S1548877817.232336,VS0,VE241
Vary: Origin
Access-Control-Allow-Methods: POST,PUT,PATCH,GET,DELETE,OPTIONS
Access-Control-Allow-Headers: Cache-Control,X-Requested-With,Authorization,Content-Type,Location,Range
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 300
I know you're not supposed to use the API that way. I did that for testing purposes. I understand every headers returned but can't figure out if my file has been uploaded because I don't have enough knowledge of this API.
My question is very simple :
Just by looking at the response, can you tell me if my file has been uploaded ?
If yes can I retrieve it and how ?
The HTTP status code traditionally indicates, for any given request, if it was successful. The status code in the response is always on the first line:
HTTP/1.1 200 OK
200 type status codes mean success. You should take some time to familiarize yourself with HTTP status codes if you intend to work with HTTP APIs.
I'm using a java application the provide a REST interface for mongodb database called "RESTHeart"
When I make a normal GET request.
http -a admin:temp http://172.18.18.122:8080/_logic/roles/admin
I get an auth token Auth-Token: 10dc2eeb-9624-47f2-a542-c97e0af82b23, how can I use it subsequent requests?
Here is the full response
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: Location, ETag, Auth-Token, Auth-Token-Valid-Until, Auth-Token-Location, X-Powered-By
Auth-Token: 10dc2eeb-9624-47f2-a542-c97e0af82b23
Auth-Token-Location: /_authtokens/admin
Auth-Token-Valid-Until: 2016-04-25T14:37:22.290Z
Connection: keep-alive
Content-Encoding: gzip
Content-Length: 109
Content-Type: application/hal+json
Date: Mon, 25 Apr 2016 14:22:22 GMT
X-Powered-By: restheart.org
{
"_links": {
"self": {
"href": "/_logic/roles/admin"
}
},
"authenticated": true,
"roles": [
"ADMIN"
]
}
I have tried the following:
http http://172.18.18.122:8080/_logic/roles/admin Auth-Token:'10dc2eeb-9624-47f2-a542-c97e0af82b23'
Response:
HTTP/1.1 403 Forbidden
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: Location, ETag, Auth-Token, Auth-Token-Valid-Until, Auth-Token-Location, X-Powered-By
Connection: keep-alive
Content-Length: 0
Date: Mon, 25 Apr 2016 14:30:27 GMT
X-Powered-By: restheart.org
I'm not sure what I'm doing wrong here, any ideas?
with httpie you can simply do:
http -a <username>:<Auth-Token> GET http://172.18.18.122:8080/auth/users
I found the solution for this question, all what I needed was to pass authorization header along with 'username:password' encoded in base64 format
http GET http://172.18.18.122:8080/auth/users authorization:'Basic YWRtaW46dGVtcA=='
Clients authenticate passing credentials via the standard basic authentication, a standard method for an HTTP user agent to provide a username and password when making a request.
RESTHeart is stateless: there isn't any authentication session and credentials must be sent on every request.
Of course, it means you must secure your communications with HTTPS.
There's documentation on how the authentication process works in restheart at https://softinstigate.atlassian.net/wiki/x/JgDM
I'm trying to upload a file to Skydrive where I don't a-priori know the Content-Length. With other storage services I can do this with chunked HTTP upload, but Skydrive always complains about Content-Length being invalid.
Here are the full headers I'm sending:
PUT /v5.0/me/skydrive/files/skydrive_test.js?overwrite=ChooseNewName HTTP/1.1
Authorization: Bearer <TOKEN_REDACTED>
host: apis.live.net
content-type: application/javascript
Connection: keep-alive
Transfer-Encoding: chunked
Here's the response I get back:
cache-control: private, no-cache, no-store, must-revalidate
transfer-encoding: chunked
content-type: application/json; charset=UTF-8
server: Live-API/16.4.1731.327 Microsoft-HTTPAPI/2.0
x-content-type-options: nosniff
x-http-live-request-id: API.c6afda25-2d9f-4248-9f49-001ccb3a9007
x-http-live-server: BAYMSG1010836
date: Wed, 15 May 2013 14:33:00 GMT
{ "error": { "code": "request_invalid_content_length",
"message": "The value for the Content-Length header isn't valid." }}
Is there any way I can do this without setting Content-Length (i.e. using chunked encoding)?
I'm using node.js to do this, but it should apply equally with any language using the REST API, hence I haven't tagged this with a particular language.
For example Dropbox offers the Chunked Upload command: https://www.dropbox.com/developers/core/docs#chunked-upload
And Google Drive, even though it says it wants Content-Length, doesn't need it for it's resumable upload API: https://developers.google.com/drive/manage-uploads#resumable
Is there an API I'm missing?
Edit: Things I've tried: Setting Content-Length: 0 results in it working, but the file is zero bytes. Setting Content-length:0 and Transfer-Encoding: chunked, results in the original error above.
Try setting a dummy content-length to see if it is acceptable. Otherwise set the file size.
If you are using node.js you can get the file size you are trying to upload and set the size to content-length in OCTETs. You can get the file size requiring the fs (filesystem) module in node.
var fs = require('fs');
fs.watchFile('some.file', function () {
fs.stat('some.file', function (err, stats) {
console.log(stats.size);
});
});
#Resource
As stated here:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec5.html
To allow for transition to absoluteURIs in all requests in future versions of HTTP, all HTTP/1.1 servers MUST accept the absoluteURI form in requests, even though HTTP/1.1 clients will only generate them in requests to proxies.
I have client which sends POST-requests to my play-2.1.1 server. He sends it this way:
POST http://172.16.1.227:9000/A8%3aF9%3a4B%3a20%3a89%3a40/1089820966/ HTTP/1.1
Content-Length: 473
Content-Type: application/json
Date: Thu, 25 Apr 2013 15:44:43 GMT
Host: 172.16.1.227:9000
User-Agent: my-client
...some data...
All requests are rejected with "Action not found" error. The very same request which I send using curl is just fine and the only difference between them is curl send it with relative URI:
POST /A8%3aF9%3a4B%3a20%3a89%3a40/1089820966/ HTTP/1.1
Accept: */*
Content-Length: 593
Content-Type: application/json
Host: 172.16.1.227:9000
User-Agent: curl/7.30.0
I created the following simple workaround in Global.scala:
override def onRouteRequest(request: RequestHeader): Option[Handler] = {
if (request.path.startsWith("http://")) {
super.onRouteRequest(request.copy(
path = request.path.replace("http://"+request.host, "")
))
} else super.onRouteRequest(request)
}
And with this workaround all requests from my client are handled correctly.
So, is there more straightforward way to do it in Play Framework or thats the only way?
Thanks to #nraychaudhuri Play 2.2 supports absoluteURI-style request headers.
Here's the issue and pull request: https://github.com/playframework/playframework/pull/1060