# Help with crafting a HTTP POST response

**URL:** <https://forums.pimoroni.com/t/help-with-crafting-a-http-post-response/20939>\
**Category:** Arduino & AVR\
**Created:** [December 10, 2022, 10:27am UTC](https://forums.pimoroni.com/t/help-with-crafting-a-http-post-response/20939 "2022-12-10T10:27:47Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![anon83280986](https://avatars.discourse-cdn.com/v4/letter/a/8e7dd6/32.png) [@anon83280986](https://forums.pimoroni.com/u/anon83280986)\
**Post date:** [December 10, 2022, 10:27am UTC](https://forums.pimoroni.com/t/help-with-crafting-a-http-post-response/20939/1 "2022-12-10T10:27:47Z")

</div>

Hi,

I’m trying to send a HTTP POST request to a Mastodon instance.

This is being done on an old [Nanode](https://wiki.london.hackspace.org.uk/view/Project:Nanode/Applications), 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](https://www.arduinolibraries.info/libraries/ether-card).

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**

```auto
//
// 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**

```auto
[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](https://docs.joinmastodon.org/methods/statuses/#create) states to POST to:

> POST [https://mastodon.example/api/v1/statuses](https://mastodon.example/api/v1/statuses) HTTP/1.1

I think the error is somewhere in here, but cannot find it.

```auto
  // 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.

---

<div class="post-metadata">

**Author:** ![anon83280986](https://avatars.discourse-cdn.com/v4/letter/a/8e7dd6/32.png) [@anon83280986](https://forums.pimoroni.com/u/anon83280986)\
**Post date:** [December 10, 2022, 10:05pm UTC](https://forums.pimoroni.com/t/help-with-crafting-a-http-post-response/20939/2 "2022-12-10T22:05:57Z")

</div>

hmmm, it looks as if POST’ing to HTTPS is the problem here.

**“Host: [https://botsin.space](https://botsin.space)”**

```auto
  // 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: https://botsin.space" "\r\n"
    "Content-Type: application/x-www-form-urlencoded" "\r\n"
    "Content-Length: $D" "\r\n"
    "\r\n"
    "$H" "\r\n"),
    stash_size, sd);

```

Produces:

> HTTP/1.1 400 Bad Request

While the non-HTTPS POST:

**“Host: botsin.space”**

```auto

  // 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: botsin.space" "\r\n"
    "Content-Type: application/x-www-form-urlencoded" "\r\n"
    "Content-Length: $D" "\r\n"
    "\r\n"
    "$H" "\r\n"),
    stash_size, sd);

```

Produces:

> HTTP/1.1 301 Moved Permanently

And points me to POST to:

> Location: [https://botsin.space/api/v1/statuses](https://botsin.space/api/v1/statuses)

Not sure what to do about this.

I guess more rabbit holes have to be investigated.

---

<div class="post-metadata">

**Author:** ![anon83280986](https://avatars.discourse-cdn.com/v4/letter/a/8e7dd6/32.png) [@anon83280986](https://forums.pimoroni.com/u/anon83280986)\
**Post date:** [December 10, 2022, 10:14pm UTC](https://forums.pimoroni.com/t/help-with-crafting-a-http-post-response/20939/3 "2022-12-10T22:14:59Z")

</div>

oh.

> **// WARNING: This example uses insecure HTTP and not HTTPS.**

[From the actual documentation for the library.](https://github.com/njh/EtherCard/blob/main/examples/twitter/twitter.ino)

![image](https://us1.discourse-cdn.com/flex016/uploads/pimoroni/original/2X/9/9cef7249bc59f45f18878658e82f504096fed691.png)
