Duplicate TCP Packet with Spark Core

I’ve been able to send a packet with the correct structure using the Chrome Extension Advanced Rest Client, but I haven’t been able to duplicate the success with the Core itself. Can anyone point at any differences between the two that might cause the Spark Core one to not work?

Here is the packet that is sent via the Chrome extension(and works) to this host http://10.0.0.1:10000/sony/camera

POST /sony/camera HTTP/1.1
Host: 10.0.0.1:10000
Connection: keep-alive
Content-Length: 66
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.71 Safari/537.36
Origin: chrome-extension://hgmloofddffdnphfgcellkdfbfbjeloo
Content-Type: application/json-rpc
Accept: */*
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8

{"method": "actTakePicture","params": [],"id": 1,"version": "1.0"}

Here is the packet I’ve been sending with the Spark Core(does not work)

POST /sony/camera HTTP/1.1
Host:10.0.0.1:10000
Accept:*/*
Content-Length: 72
Content-Type: application/json-rpc
{"method": "actTakePicture", "params":"[]", "id": "1", "version": "1.0"}

Here is the code used to send the packet. I’ve been attempting to duplicate the second packet, so it doesn’t quite match the first packet’s structure

byte server[] = { 10, 0, 0, 1 };
if (client.connect(server, 10000))
    {
      Serial.println("Connected");

            String request = "{\"method\": \"actTakePicture\", \"params\":\"[]\", \"id\": \"1\", \"version\": \"1.0\"}";

            client.println("POST /sony/camera HTTP/1.1");
            client.println("Host: 10.0.0.1:10000");
            client.println("Connection: keep-alive");
            client.print("Content-Length:");
            client.println(request.length());
            client.println("Accept:*/*"); 
            client.println("Content-Type: application/json-rpc");
            client.println("Accept-Encoding: gzip, deflate");
            client.println("Accept-Language: en-US,en;q=0.8");
            client.println("{\"method\": \"actTakePicture\", \"params\":\"[]\", \"id\": \"1\", \"version\": \"1.0\"}");
            client.println();
            // client.flush();
            // client.stop();
            Spark.process();
      Serial.println("Packet Sent");
      delay(500);
    }

I can’t see any error message packets, as only one host can connect to the camera at a time, and I haven’t figured out how to either view received packets on the Core or insert Wireshark into the mix somehow. Can anyone tell me why the first one works and the second one does not? When I captured these via Wireshark by looking at the packets sent via a regular network, Wireshark recognized the first as an HTTP POST packet, while leaving the last one as a TCP packet. I’m not why that is though.

Hi @benwis

The formatting here is critical. You need a blank line between the headers and the data which in this case is the {“method”: …} line.

The content-length refers to the length of the data, so I think you should have 66 as well since the \" counts as one character, not two. It is just a way of putting a " in char array more easily.

1 Like

@bko Good to know. That fixes a few things, but it’s not there yet. Here’s the sampled response from a web server with the above changes. Note the addition of a nice 404 error code!

POST /sony/camera HTTP/1.1
Host: 10.0.0.1:10000
Connection: keep-alive
Content-Length:66
Accept:*/*
Content-Type: application/json-rpc
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8

{"method": "actTakePicture", "params":"[]", "id": "1", "version": "1.0"}HTTP/1.1 404 Not Found
Date: Thu, 04 Dec 2014 03:16:54 GMT
Server: Apache
Content-Length: 209
Keep-Alive: timeout=5, max=100
Connection: Keep-Alive
Content-Type: text/html; charset=iso-8859-1

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>404 Not Found</title>
</head><body>
<h1>Not Found</h1>
<p>The requested URL /sony/camera was not found on this server.</p>
</body></html>

There’s still some difference between the new packet and the working one, as it doesn’t trigger the camera, but it’s recognized as HTML POST by a web server, so nice!

New transmit code:

if (client.connect(server, 80))
// if (client.connect(server2, 10000))
    {
      Serial.println("Connected");

            String request = "{\"method\": \"actTakePicture\", \"params\":\"[]\", \"id\": \"1\", \"version\": \"1.0\"}";

            client.println("POST /sony/camera HTTP/1.1");
            client.println("Host: 10.0.0.1:10000");
            client.println("Connection: keep-alive");
            client.println("Content-Length:66");
            // client.println(request.length());
            client.println("Accept:*/*"); 
            client.println("Content-Type: application/json-rpc");
            client.println("Accept-Encoding: gzip, deflate");
            client.println("Accept-Language: en-US,en;q=0.8");
            client.println();
            client.println("{\"method\": \"actTakePicture\", \"params\":\"[]\", \"id\": \"1\", \"version\": \"1.0\"}");
            client.println();
            // client.flush();
            // client.stop();
            Spark.process();
      Serial.println("Packet Sent");
      delay(500);

I think you should try

... \"params\": [], \"id\": 1, ...

without the double-quotes around the square brackets and the number one. I am not sure that is your problem, but it seems different from the working case.

A few things:

The params array doesn’t need quotes around the brackets if it’s truly JSON…

I notice in your new code, you switched to:

if (client.connect(server, 80))

Which then your Host: header is:

10.0.0.1:10000

I’m curious if Apache is the right server to respond? Does it really respond to port 80 or 10000?

When Apache throws a 404, it truly can’t figure out where to get the content… I’m pretty sure that bad HTTP requests into Apache don’t (and can’t) through a 404… I’d look somewhere else… Is there a 301/302 redirect happening?

Can you try this and paste the output? (Unless you’re on Windows)

curl -v -H "Content-Type: application/json" -d '{"method":"actTakePicture","params":[], "id": 1, "version": "1.0"}' http://10.0.0.1:10000/sony/camera

And then the output from this:

curl -v -H "Content-Type: application/json" -d '{"method":"actTakePicture","params":[], "id": 1, "version": "1.0"}' http://10.0.0.1/sony/camera

This should help us solve any issues with posting to the correct location…