Hi,
I’m trying to send a HTTP POST request to a Mastodon instance.
This is being done on an old Nanode, which has an ATmega328 microcontroller and built in ENC28J60 ethernet.
Nanode is an Arduino like 8 bit microcontroller board with integrated Ethernet connectivity.
As it is the same chip as the Arduino, it uses the Arduino IDE and has a dedicated library for ethernet connectivity: EtherCard.
I have all of this working; getting the network up, connecting to the remote server, receiving a response etc, but the POST seems malformed and I cannot figure out why.
There are numerous forum posts about how to do this, and all of them look like my sketch, yet mine doesn’t work and I cannot figure out why.
Sketch
//
// Based on the EtherCard library example 'twitter.ino'
//
// License: GPLv2
//
// POSTs to Mastodon
//
#include <EtherCard.h>
// Mastodon info
const char website[] PROGMEM = "botsin.space";
#define TOKEN "dgpAlS.........._Ai_gVTWf4M"
// ethernet interface mac address
static byte mymac[] = { 0x4e, 0x61, 0x6e, 0x6f, 0x64, 0x65 };
// ethernet interface ip address
static byte myip[] = { 192, 168, 0, 250 };
// gateway ip address
static byte gwip[] = { 192, 168, 0, 1 };
// DNS address
static byte dnsip[] = { 194, 168, 4, 100 };
// network mask
static byte netmask[] = { 255, 255, 255, 0 };
static byte session;
byte Ethernet::buffer[700];
Stash stash;
static void sendToMastodon() {
Serial.println("Sending toot...");
byte sd = stash.create();
const char toot[] = "hello";
stash.print("Authorization: Bearer ");
stash.print(TOKEN);
stash.print("&status=");
stash.println(toot);
stash.save();
int stash_size = stash.size();
Serial.println("");
Serial.println("[Debugging:]");
Serial.print("stash_size:");
Serial.println(stash_size);
Serial.println("");
// Compose the http POST request, taking the headers below and appending
// previously created stash in the sd holder.
Stash::prepare(PSTR("POST /api/v1/statuses HTTP/1.1" "\r\n"
"Host: $F" "\r\n"
"Content-Type: application/x-www-form-urlencoded" "\r\n"
"Content-Length: $D" "\r\n"
"\r\n"
"$H"),
website, stash_size, sd);
// send the packet - this also releases all stash buffers once done
// Save the session ID so we can watch for it in the main loop.
session = ether.tcpSend();
}
void setup() {
Serial.begin(57600);
Serial.println("\n[Mastodon Client]");
// Change 'SS' to your Slave Select pin, if you arn't using the default pin
// Use pin8 for a Nanode
if (ether.begin(sizeof Ethernet::buffer, mymac, 8) == 0)
Serial.println(F("Failed to access Ethernet controller"));
if (!ether.dhcpSetup())
Serial.println(F("DHCP failed"));
//Static IP
//ether.staticSetup(myip, gwip, dnsip, netmask);
//Dynamic IP
ether.dhcpSetup();
ether.printIp("My IP: ", ether.myip);
ether.printIp("Gateway: ", ether.gwip);
ether.printIp("My DNS: ", ether.dnsip);
ether.printIp("Subnet Mask: ", ether.netmask);
if (!ether.dnsLookup(website))
Serial.println(F("Remote DNS lookup failed"));
ether.printIp("Remote DNS: ", ether.hisip);
sendToMastodon();
}
void loop() {
ether.packetLoop(ether.packetReceive());
const char* reply = ether.tcpReply(session);
if (reply != 0) {
Serial.println("Got a response!");
Serial.println(reply);
}
}
Serial Output
[Mastodon Client]
My IP: 192.168.0.124
Gateway: 192.168.0.1
My DNS: 194.168.4.100
Subnet Mask: 255.255.255.0
Remote DNS: 147.182.217.82
Sending toot...
[Debugging:]
stash_size:80
Got a response!
HTTP/1.1 301 Moved Permanently
Server: nginx/1.18.0 (Ubuntu)
Date: Sat, 10 Dec 2022 10:10:25 GMT
Content-Type: text/html
Content-Length: 178
Connection: keep-alive
Location: https://botsin.space/api/v1/statuses
<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/1.18.0 (Ubuntu)</center>
</body>
</html>
The response suggets that the URL is incorrect but the documentation states to POST to:
POST https://mastodon.example/api/v1/statuses HTTP/1.1
I think the error is somewhere in here, but cannot find it.
// Compose the http POST request, taking the headers below and appending
// previously created stash in the sd holder.
Stash::prepare(PSTR("POST /api/v1/statuses HTTP/1.1" "\r\n"
"Host: $F" "\r\n"
"Content-Type: application/x-www-form-urlencoded" "\r\n"
"Content-Length: $D" "\r\n"
"\r\n"
"$H"),
website, stash_size, sd);
Any help gratefully appreciated.
Simon.