arduino-libraries / ArduinoHttpClient

Arduino HTTP Client library
287 stars 172 forks source link

Getting HTTP 400 Bad Request from Google Cloud Run as of March 2023 #150

Open sosandstrom opened 1 year ago

sosandstrom commented 1 year ago

As of a few days ago, the following code is getting HTTP 400 Bad Request from Google Cloud Run, where it used to get proper HTTP 200 OK:

            httpClient.beginRequest();
            httpClient.post(_cloudPostPath);
            httpClient.sendHeader(HTTP_HEADER_CONTENT_LENGTH, strlen(_cloudRequestBody));
            httpClient.sendHeader(HTTP_HEADER_CONTENT_TYPE, ApplicationJson);
            httpClient.sendHeader("Host", cloudHost);
            sprintf(value, "%s/%s", CurrentlyOne, VERSION);
            httpClient.sendHeader(HTTP_HEADER_USER_AGENT, value);
            httpClient.endRequest();
            httpClient.print(_cloudRequestBody);
            memset(_cloudRequestBody, 0, RESPONSE_BUF_SIZE);
            status = httpClient.responseStatusCode();
            LOG("HTTP %d", status);

The HttpClient is backed by a WiFiClientSecure on an ESP32C3 module.

If I instead use a custom (incomplete fwiw) implementation of the HttpClient, it starts working again:

#if(CORE_DEBUG_LEVEL>=4)
#define ENABLE_LOG4ARDUINO
#endif
#include <log4arduino.h>
#include <Arduino.h>
#include <WiFiClientSecure.h>

#include "http_client.h"

HttpClient::HttpClient(WiFiClientSecure& aClient, const char* aServerName, uint16_t aServerPort) {
    client = &aClient;
    host = aServerName;
    port = aServerPort;
    statusCode = -1;
    responseContentLength = -1;
    memset(responseData, 0, RESPONSE_BUF_SIZE);
}

void HttpClient::beginRequest() {
    client->connect(host, port);
    statusCode = -1;
    responseContentLength = -1;
    memset(responseData, 0, RESPONSE_BUF_SIZE);
}

int HttpClient::get(const char* aURLPath) {
    char buf[RESPONSE_BUF_SIZE];
    sprintf(buf, "GET %s HTTP/1.1\r\n", aURLPath);
    return print(buf);
}

int HttpClient::post(const char* aURLPath) {
    char buf[RESPONSE_BUF_SIZE];
    sprintf(buf, "POST %s HTTP/1.1\r\n", aURLPath);
    return print(buf);
}

void HttpClient::sendHeader(const char* aHeaderName, const char* aHeaderValue) {
    char buf[RESPONSE_BUF_SIZE];
    sprintf(buf, "%s: %s\r\n", aHeaderName, aHeaderValue);
    print(buf);
}

void HttpClient::sendHeader(const char* aHeaderName, const int aHeaderValue) {
    char buf[RESPONSE_BUF_SIZE];
    sprintf(buf, "%s: %d\r\n", aHeaderName, aHeaderValue);
    print(buf);
}

void HttpClient::endRequest() {
    print(HTTP_CRLF);
}

int HttpClient::print(const char *data) {
    LOGS(data);
    return client->print(data);
}

int HttpClient::responseStatusCode() {
    if (-1 == statusCode) {
        char buf[RESPONSE_BUF_SIZE], statusMessage[128];
        memset(statusMessage, 0, 128);

        readLine(buf, RESPONSE_BUF_SIZE);
        LOGS(buf);
        sscanf(buf, "HTTP/1.1 %d %s", &statusCode, statusMessage);
    }
    return statusCode;
}

int HttpClient::contentLength() {
    return responseContentLength;
}

const char * HttpClient::responseBody() {
    if (-1 == responseContentLength) {
        char buf[RESPONSE_BUF_SIZE];

        // read headers:
        readLine(buf, RESPONSE_BUF_SIZE);
        while (0 < strlen(buf) && strcmp(buf, HTTP_CRLF)) {
            LOG(buf);
            if (strstr(buf, HTTP_HEADER_CONTENT_LENGTH) || strstr(buf, "content-length")) {
                sscanf(&buf[strlen(HTTP_HEADER_CONTENT_LENGTH)], ": %d", &responseContentLength);
            }
            readLine(buf, RESPONSE_BUF_SIZE);
        }

        // read body
        client->read((uint8_t *)responseData, RESPONSE_BUF_SIZE);
        if (responseContentLength != strlen(responseData)) {
            LOG("content length mismatch, header=%d, read=%d", responseContentLength, strlen(responseData));
            responseContentLength = strlen(responseData);
        }
    }
    return responseData;
}

void HttpClient::stop() {
    client->stop();
}

int HttpClient::readLine(char *buf, int size) {
    const uint32_t ms = millis();
    int pos = 0, ch = 0;
    memset(buf, 0, size);

    while (0x0A != ch && 0 <= ch) {
        while (!client->available() && millis() < ms + 30000) {
            delay(10);
        }
        ch = client->read();
        if (pos < size-1) {
            buf[pos] = ch;
        }
        pos++;
    }
    return pos;
}