#include <WiFi.h>
#include <WiFiClientSecure.h>
#include <HTTPClient.h>
// ============================================================================
// NETWORK CONFIGURATION
// ============================================================================
const char* WIFI_SSID = "Wokwi-GUEST";
const char* WIFI_PASS = "";
const char* URL_EXAMPLE = "https://example.com/";
const char* URL_NGROK = "https://outright-entangled-powdery.ngrok-free.dev/api/status";
// Helper to test HTTPS GET via HTTPClient
void testHttpsGet(const char* label, const char* url, bool isNgrok) {
Serial.println("\n--------------------------------------------------------");
Serial.printf("TEST: %s\n", label);
Serial.printf("Target URL: %s\n", url);
Serial.println("--------------------------------------------------------");
WiFiClientSecure client;
client.setInsecure(); // Disable strict certificate validation for diagnostic
client.setTimeout(10000); // 10s timeout
HTTPClient http;
http.setReuse(false);
http.setTimeout(10000);
http.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
Serial.println("[STEP 1] Calling http.begin(client, url)...");
if (!http.begin(client, url)) {
Serial.println("[FAIL] http.begin() returned false. Unable to initialize connection.");
return;
}
// Add headers
http.addHeader("User-Agent", "SmartFlow-ESP32-Diagnostic");
http.addHeader("Accept", "*/*");
if (isNgrok) {
http.addHeader("ngrok-skip-browser-warning", "true");
}
Serial.println("[STEP 2] Sending HTTP GET request...");
unsigned long startMs = millis();
int httpCode = http.GET();
unsigned long durationMs = millis() - startMs;
Serial.printf("[RESULT] Duration: %lu ms\n", durationMs);
Serial.printf("[RESULT] HTTP Status Code: %d\n", httpCode);
Serial.printf("[RESULT] HTTPClient Message: %s\n", http.errorToString(httpCode).c_str());
// Check for underlying mbedTLS errors
char tlsErrBuf[128] = {0};
int tlsErrCode = client.lastError(tlsErrBuf, sizeof(tlsErrBuf));
if (tlsErrCode != 0) {
Serial.printf("[mbedTLS] Code: %d\n", tlsErrCode);
Serial.printf("[mbedTLS] Detail: %s\n", tlsErrBuf);
} else {
Serial.println("[mbedTLS] No explicit mbedTLS error reported by client.lastError().");
}
if (httpCode > 0) {
String payload = http.getString();
Serial.printf("[PAYLOAD] Length: %d bytes\n", payload.length());
String preview = payload.substring(0, 180);
preview.replace("\r", "");
preview.replace("\n", " ");
Serial.printf("[PAYLOAD] Preview: %s...\n", preview.c_str());
} else {
Serial.println("[FAIL] Request failed without receiving an HTTP status code.");
}
http.end();
}
// Helper to test raw TLS handshake with explicit SNI
void testRawTlsHandshake(const char* host, uint16_t port) {
Serial.println("\n--------------------------------------------------------");
Serial.printf("TEST: Direct WiFiClientSecure TLS Handshake (Explicit SNI)\n");
Serial.printf("Host: %s | Port: %d\n", host, port);
Serial.println("--------------------------------------------------------");
WiFiClientSecure client;
client.setInsecure();
client.setTimeout(10000);
Serial.println("[STEP 1] Connecting socket and performing TLS handshake...");
unsigned long startMs = millis();
bool connected = client.connect(host, port);
unsigned long durationMs = millis() - startMs;
if (connected) {
Serial.printf("[SUCCESS] TLS connected in %lu ms!\n", durationMs);
Serial.println("[STEP 2] Sending raw minimal HTTP/1.1 request...");
client.printf("GET /api/status HTTP/1.1\r\n"
"Host: %s\r\n"
"User-Agent: ESP32-Raw-TLS\r\n"
"ngrok-skip-browser-warning: true\r\n"
"Connection: close\r\n\r\n", host);
unsigned long waitStart = millis();
while (client.connected() && !client.available() && (millis() - waitStart < 5000)) {
delay(50);
}
if (client.available()) {
Serial.println("[RESPONSE HEADERS]:");
int lines = 0;
while (client.available() && lines < 5) {
String line = client.readStringUntil('\n');
line.trim();
if (line.length() > 0) {
Serial.printf(" > %s\n", line.c_str());
lines++;
}
}
} else {
Serial.println("[WARN] Connected, but no response bytes available.");
}
client.stop();
} else {
Serial.printf("[FAIL] Direct TLS connect failed after %lu ms.\n", durationMs);
char errBuf[128] = {0};
int errCode = client.lastError(errBuf, sizeof(errBuf));
Serial.printf("[mbedTLS] Code: %d\n", errCode);
Serial.printf("[mbedTLS] Detail: %s\n", errBuf);
}
}
void setup() {
Serial.begin(115200);
delay(300);
Serial.println("\n========================================================");
Serial.println(" SMARTFLOW HTTPS / TLS DIAGNOSTIC SUITE ");
Serial.println("========================================================");
// 1. Connect to WiFi
Serial.print("[WiFi] Connecting to: ");
Serial.println(WIFI_SSID);
WiFi.begin(WIFI_SSID, WIFI_PASS);
int attempts = 0;
while (WiFi.status() != WL_CONNECTED && attempts < 30) {
delay(300);
Serial.print(".");
attempts++;
}
if (WiFi.status() != WL_CONNECTED) {
Serial.println("\n[WiFi] Connection failed. Halting diagnostic.");
return;
}
Serial.println("\n[WiFi] Connected!");
Serial.print("[WiFi] IP Address: ");
Serial.println(WiFi.localIP());
// 2. Test 1: Public HTTPS (https://example.com/)
testHttpsGet("Standard Public HTTPS (example.com)", URL_EXAMPLE, false);
// 3. Test 2: User's ngrok Endpoint via HTTPClient
testHttpsGet("User ngrok API (HTTPClient)", URL_NGROK, true);
// 4. Test 3: User's ngrok Host via Direct WiFiClientSecure (Explicit SNI)
testRawTlsHandshake("outright-entangled-powdery.ngrok-free.dev", 443);
Serial.println("\n========================================================");
Serial.println(" DIAGNOSTIC SUITE COMPLETE ");
Serial.println("========================================================");
}
void loop() {
delay(2000);
}