Skip to content

Commit

Permalink
sendRequestToOctoprint():
Browse files Browse the repository at this point in the history
- Resole issue chunkysteveo#28
- Reduce memory footprint with less variables
- Split header sending in sendHeader()
- Timeout run through all request
- Refactor main loop for a better readability

WARNING: Only tested with GET (Octoprint up and down with Haproxy, with printer up and down).
	 Not tested yet with POST commands.

Reduce variable memory for octoPrintPrintHeadRelativeJog() and remove a potential buffer overflow.

Remove unsued maxMessageLength and httpErrorBody
  • Loading branch information
fmatray committed Jun 2, 2020
1 parent e6169c6 commit 920890c
Show file tree
Hide file tree
Showing 2 changed files with 101 additions and 110 deletions.
201 changes: 93 additions & 108 deletions OctoPrintAPI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ OctoprintApi::OctoprintApi(Client &client, IPAddress octoPrintIp, int octoPrintP
_octoPrintIp = octoPrintIp;
_octoPrintPort = octoPrintPort;
_usingIpAddress = true;
snprintf(_useragent, USER_AGENT_SIZE, "User-Agent: %s", USER_AGENT);
}

/** OctoprintApi()
Expand All @@ -31,6 +32,7 @@ OctoprintApi::OctoprintApi(Client &client, char *octoPrintUrl, int octoPrintPort
_octoPrintUrl = octoPrintUrl;
_octoPrintPort = octoPrintPort;
_usingIpAddress = false;
snprintf(_useragent, USER_AGENT_SIZE, "User-Agent: %s", USER_AGENT);
}

/** GET YOUR ASS TO OCTOPRINT...
Expand All @@ -46,119 +48,78 @@ String OctoprintApi::sendRequestToOctoprint(String type, String command, const c
return "";
}

String statusCode = "";
String headers = "";
String body = "";
bool finishedStatusCode = false;
bool finishedHeaders = false;
bool currentLineIsBlank = true;
int ch_count = 0;
int headerCount = 0;
int headerLineStart = 0;
int bodySize = -1;
unsigned long now;

bool connected;
String buffer = "";
char c = 0;
long bodySize = -1;
unsigned long start_waiting = 0;
bool connected = false;

if (_usingIpAddress)
connected = _client->connect(_octoPrintIp, _octoPrintPort);
else
connected = _client->connect(_octoPrintUrl, _octoPrintPort);

if (connected) {
if (_debug)
Serial.println(".... connected to server");

char useragent[64];
snprintf(useragent, 64, "User-Agent: %s", USER_AGENT);

_client->println(type + " " + command + " HTTP/1.1");
_client->print("Host: ");
if (_usingIpAddress)
_client->println(_octoPrintIp);
else
_client->println(_octoPrintUrl);
_client->print("X-Api-Key: ");
_client->println(_apiKey);
_client->println(useragent);
_client->println("Connection: keep-alive");
if (data != NULL) {
_client->println("Content-Type: application/json");
_client->print("Content-Length: ");
_client->println(strlen(data)); // number of bytes in the payload
_client->println(); // important need an empty line here
_client->println(data); // the payload
} else
_client->println();

now = millis();
if (_debug) {
Serial.print("Request sent. Waiting for the answer:");
Serial.println(now);
}
while (millis() - now < OPAPI_TIMEOUT || now < millis()) {
while (_client->available()) {
char c = _client->read();

if (_debug)
Serial.print(c);

if (!finishedStatusCode) {
if (c == '\n')
finishedStatusCode = true;
else
statusCode = statusCode + c;
}

if (!finishedHeaders) {
if (c == '\n') {
if (currentLineIsBlank)
finishedHeaders = true;
else {
if (headers.substring(headerLineStart).startsWith("Content-Length: "))
bodySize = (headers.substring(headerLineStart + 16)).toInt();
headers = headers + c;
headerCount++;
headerLineStart = headerCount;
}
} else {
headers = headers + c;
headerCount++;
}
} else {
if (ch_count < maxMessageLength) {
body = body + c;
ch_count++;
if (ch_count == bodySize)
break;
}
}
if (c == '\n')
currentLineIsBlank = true;
else if (c != '\r') {
currentLineIsBlank = false;
}
}
if (ch_count == bodySize)
break;
}
} else {
if (_debug) {
Serial.println("connection failed");
Serial.println(connected);
}
if (!connected) {
if (_debug) Serial.println("connection failed.");
closeClient();
return "";
}
if (_debug) Serial.println("...connected to server.");

closeClient();
sendHeader(type, command, data);

start_waiting = millis();
if (_debug) Serial.println("Request sent. Waiting for the answer.");

while (!_client->available() && OPAPI_RUN_TIMEOUT) // wait for a reply
delay(1);
if (!_client->available()) {
if (_debug) Serial.println("Timeout during waiting for a reply");
closeClient();
return "";
}

// Read Status code
if (_debug) Serial.println("Reading status code");
while (_client->available() && (c = _client->read()) != '\n' && OPAPI_RUN_TIMEOUT)
buffer = buffer + c;

int httpCode = extractHttpCode(statusCode);
httpStatusCode = extractHttpCode(buffer);
if (_debug) {
Serial.print("\nhttpCode:");
Serial.println(httpCode);
Serial.print("httpCode:");
Serial.println(httpStatusCode);
}
if (!(200 <= httpStatusCode && httpStatusCode <= 204) && httpStatusCode != 409) {
closeClient();
return "";
}
// Read headers
if (_debug) Serial.println("Reading headers");
for (buffer = ""; _client->available() && OPAPI_RUN_TIMEOUT;) { // read headers
c = _client->read();
buffer = buffer + c;
if (_debug) Serial.print(c);
if (c == '\n') {
if (buffer.startsWith("Content-Length: "))
bodySize = buffer.substring(16).toInt();
else if (buffer == "\n" || buffer == "\r\n")
break;
buffer = "";
}
}
if (bodySize <= 0) {
if (_debug) Serial.println("Header 'Content-Length' not found");
closeClient();
return "";
}
httpStatusCode = httpCode;

return body;
if (_debug) Serial.println("Reading body");
for (buffer = ""; _client->available() && bodySize-- && OPAPI_RUN_TIMEOUT;)
buffer = buffer + (char)_client->read();
if (_debug) Serial.println(buffer);

closeClient();
return buffer;
}

String OctoprintApi::sendGetToOctoprint(String command) {
Expand Down Expand Up @@ -394,25 +355,25 @@ bool OctoprintApi::octoPrintPrintHeadRelativeJog(double x, double y, double z, d
// "absolute": false,
// "speed": 30
// }
char postData[1024];
char tmp[128];
char postData[POSTDATA_SIZE];
char tmp[TEMPDATA_SIZE];
postData[0] = '\0';

strcat(postData, "{\"command\": \"jog\"");
strncat(postData, "{\"command\": \"jog\"", POSTDATA_SIZE);
if (x != 0) {
snprintf(tmp, 128, ", \"x\": %f", x);
snprintf(tmp, TEMPDATA_SIZE, ", \"x\": %f", x);
strcat(postData, tmp);
}
if (y != 0) {
snprintf(tmp, 128, ", \"y\": %f", y);
snprintf(tmp, TEMPDATA_SIZE, ", \"y\": %f", y);
strcat(postData, tmp);
}
if (z != 0) {
snprintf(tmp, 128, ", \"z\": %f", z);
snprintf(tmp, TEMPDATA_SIZE, ", \"z\": %f", z);
strcat(postData, tmp);
}
if (f != 0) {
snprintf(tmp, 128, ", \"speed\": %f", f);
snprintf(tmp, TEMPDATA_SIZE, ", \"speed\": %f", f);
strcat(postData, tmp);
}
strcat(postData, ", \"absolute\": false");
Expand Down Expand Up @@ -562,3 +523,27 @@ int OctoprintApi::extractHttpCode(String statusCode) { // HTTP/1.1 200 OK || H

return statusCodeInt ? statusCodeInt : -1;
}

/**
* Send HTTP Headers
* */
void OctoprintApi::sendHeader(const String type, const String command, const char *data) {
_client->println(type + " " + command + " HTTP/1.1");
_client->print("Host: ");
if (_usingIpAddress)
_client->println(_octoPrintIp);
else
_client->println(_octoPrintUrl);
_client->print("X-Api-Key: ");
_client->println(_apiKey);
_client->println(_useragent);
_client->println("Connection: keep-alive");
if (data != NULL) {
_client->println("Content-Type: application/json");
_client->print("Content-Length: ");
_client->println(strlen(data)); // number of bytes in the payload
_client->println(); // important need an empty line here
_client->println(data); // the payload
} else
_client->println();
}
10 changes: 8 additions & 2 deletions OctoPrintAPI.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,15 @@
#include <ArduinoJson.h>
#include <Client.h>

#define OPAPI_TIMEOUT 3000
#define OPAPI_TIMEOUT 3000 // 3s timetout
#define OPAPI_RUN_TIMEOUT (millis() - start_waiting < OPAPI_TIMEOUT && start_waiting <= millis())

#define POSTDATA_SIZE 256
#define TEMPDATA_SIZE 32
#define POSTDATA_GCODE_SIZE 50
#define JSONDOCUMENT_SIZE 1024
#define USER_AGENT "OctoPrintAPI/1.1.4 (Arduino)"
#define USER_AGENT_SIZE 64

struct printerStatistics {
String printerState;
Expand Down Expand Up @@ -134,10 +138,12 @@ class OctoprintApi {
bool _usingIpAddress;
char *_octoPrintUrl;
int _octoPrintPort;
char _useragent[USER_AGENT_SIZE];
const int maxMessageLength = 1000;
void closeClient();
void sendHeader(const String type, const String command, const char *data);
int extractHttpCode(String statusCode);
String sendRequestToOctoprint(String type, String command, const char *data);
String sendRequestToOctoprint(const String type, const String command, const char *data);
};

#endif

0 comments on commit 920890c

Please sign in to comment.