mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-01 05:52:32 +07:00
Merge pull request #3423 from cesanta/singleton
Add http singleton client example
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
PROG ?= example # Program we are building
|
||||
DELETE = rm -rf # Command to remove files
|
||||
OUT ?= -o $(PROG) # Compiler argument for output file
|
||||
SOURCES = main.c mongoose.c # Source code files
|
||||
CFLAGS = -W -Wall -Wextra -g -I. # Build options
|
||||
#CFLAGS += -fsanitize=address,undefined,alignment
|
||||
|
||||
# Mongoose build options. See https://mongoose.ws/documentation/#build-options
|
||||
CFLAGS_MONGOOSE += -DMG_ENABLE_LINES=1
|
||||
CFLAGS_MONGOOSE += -DMG_TLS=MG_TLS_BUILTIN
|
||||
#CFLAGS_MONGOOSE += -DMG_TLS=MG_TLS_OPENSSL -L/opt/homebrew/opt/openssl/lib -I/opt/homebrew/opt/openssl/include -lssl -lcrypto
|
||||
#CFLAGS_MONGOOSE += -DMG_TLS=MG_TLS_MBED -L/opt/homebrew/opt/mbedtls/lib -I/opt/homebrew/opt/mbedtls/include -lmbedtls -lmbedcrypto -lmbedx509
|
||||
|
||||
ifeq ($(OS),Windows_NT) # Windows settings. Assume MinGW compiler. To use VC: make CC=cl CFLAGS=/MD OUT=/Feprog.exe
|
||||
PROG ?= example.exe # Use .exe suffix for the binary
|
||||
CC = gcc # Use MinGW gcc compiler
|
||||
CFLAGS += -lws2_32 -lbcrypt # Link against Winsock library
|
||||
DELETE = cmd /C del /Q /F /S # Command prompt command to delete files
|
||||
endif
|
||||
|
||||
all: $(PROG) # Default target. Build and run program
|
||||
$(RUN) ./$(PROG) $(ARGS)
|
||||
|
||||
$(PROG): $(SOURCES) # Build program from sources
|
||||
$(CC) $(SOURCES) $(CFLAGS) $(CFLAGS_MONGOOSE) $(CFLAGS_EXTRA) $(OUT)
|
||||
|
||||
clean: # Cleanup. Delete built program and all build artifacts
|
||||
$(DELETE) $(PROG) *.o *.obj *.exe *.dSYM
|
||||
@@ -0,0 +1,111 @@
|
||||
// Copyright (c) 2026 Cesanta Software Limited
|
||||
// All rights reserved
|
||||
//
|
||||
// This example shows how we can poll an external HTTP server periodically, and
|
||||
// make sure that not more than one instance of the active request in flight.
|
||||
// Each request has a configured timeout.
|
||||
|
||||
#include "mongoose.h"
|
||||
|
||||
static const char *s_url = "https://mongoose.ws/tls/api/ca";
|
||||
static const char *s_post_data = "hi";
|
||||
static const uint64_t s_connect_timeout_ms = 5500; // milliseconds
|
||||
static struct mg_connection *s_conn = NULL;
|
||||
|
||||
// TLS certificate, obtained using https://mongoose.ws/tls/
|
||||
#define TLS_CA \
|
||||
"-----BEGIN CERTIFICATE-----\n" \
|
||||
"MIIEVjCCAj6gAwIBAgIQY5WTY8JOcIJxWRi/w9ftVjANBgkqhkiG9w0BAQsFADBP\n" \
|
||||
"MQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFy\n" \
|
||||
"Y2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMTAeFw0yNDAzMTMwMDAwMDBa\n" \
|
||||
"Fw0yNzAzMTIyMzU5NTlaMDIxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBF\n" \
|
||||
"bmNyeXB0MQswCQYDVQQDEwJFODB2MBAGByqGSM49AgEGBSuBBAAiA2IABNFl8l7c\n" \
|
||||
"S7QMApzSsvru6WyrOq44ofTUOTIzxULUzDMMNMchIJBwXOhiLxxxs0LXeb5GDcHb\n" \
|
||||
"R6EToMffgSZjO9SNHfY9gjMy9vQr5/WWOrQTZxh7az6NSNnq3u2ubT6HTKOB+DCB\n" \
|
||||
"9TAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsGAQUFBwMB\n" \
|
||||
"MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFI8NE6L2Ln7RUGwzGDhdWY4j\n" \
|
||||
"cpHKMB8GA1UdIwQYMBaAFHm0WeZ7tuXkAXOACIjIGlj26ZtuMDIGCCsGAQUFBwEB\n" \
|
||||
"BCYwJDAiBggrBgEFBQcwAoYWaHR0cDovL3gxLmkubGVuY3Iub3JnLzATBgNVHSAE\n" \
|
||||
"DDAKMAgGBmeBDAECATAnBgNVHR8EIDAeMBygGqAYhhZodHRwOi8veDEuYy5sZW5j\n" \
|
||||
"ci5vcmcvMA0GCSqGSIb3DQEBCwUAA4ICAQBnE0hGINKsCYWi0Xx1ygxD5qihEjZ0\n" \
|
||||
"RI3tTZz1wuATH3ZwYPIp97kWEayanD1j0cDhIYzy4CkDo2jB8D5t0a6zZWzlr98d\n" \
|
||||
"AQFNh8uKJkIHdLShy+nUyeZxc5bNeMp1Lu0gSzE4McqfmNMvIpeiwWSYO9w82Ob8\n" \
|
||||
"otvXcO2JUYi3svHIWRm3+707DUbL51XMcY2iZdlCq4Wa9nbuk3WTU4gr6LY8MzVA\n" \
|
||||
"aDQG2+4U3eJ6qUF10bBnR1uuVyDYs9RhrwucRVnfuDj29CMLTsplM5f5wSV5hUpm\n" \
|
||||
"Uwp/vV7M4w4aGunt74koX71n4EdagCsL/Yk5+mAQU0+tue0JOfAV/R6t1k+Xk9s2\n" \
|
||||
"HMQFeoxppfzAVC04FdG9M+AC2JWxmFSt6BCuh3CEey3fE52Qrj9YM75rtvIjsm/1\n" \
|
||||
"Hl+u//Wqxnu1ZQ4jpa+VpuZiGOlWrqSP9eogdOhCGisnyewWJwRQOqK16wiGyZeR\n" \
|
||||
"xs/Bekw65vwSIaVkBruPiTfMOo0Zh4gVa8/qJgMbJbyrwwG97z/PRgmLKCDl8z3d\n" \
|
||||
"tA0Z7qq7fta0Gl24uyuB05dqI5J1LvAzKuWdIjT1tP8qCoxSE/xpix8hX2dt3h+/\n" \
|
||||
"jujUgFPFZ0EVZ0xSyBNRF3MboGZnYXFUxpNjTWPKpagDHJQmqrAcDmWJnMsFY3jS\n" \
|
||||
"u1igv3OefnWjSQ==\n" \
|
||||
"-----END CERTIFICATE-----"
|
||||
|
||||
static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) {
|
||||
uint64_t *start_time = (uint64_t *) c->data; // Stored start time
|
||||
bool *success = (bool *) (start_time + 1); // Stored success flag
|
||||
if (ev == MG_EV_OPEN) {
|
||||
*start_time = mg_millis();
|
||||
MG_DEBUG(("%lu Connection started, time: %llu", c->id, *start_time));
|
||||
} else if (ev == MG_EV_POLL) {
|
||||
if (*start_time + s_connect_timeout_ms < mg_millis()) {
|
||||
mg_error(c, "Connect timeout");
|
||||
}
|
||||
} else if (ev == MG_EV_CONNECT) {
|
||||
// Connected to server. Extract host name from URL
|
||||
struct mg_str host = mg_url_host(s_url);
|
||||
if (c->is_tls) {
|
||||
struct mg_tls_opts opts = {};
|
||||
opts.ca = mg_str(TLS_CA);
|
||||
opts.name = host;
|
||||
mg_tls_init(c, &opts);
|
||||
}
|
||||
// Send request
|
||||
int content_length = s_post_data ? strlen(s_post_data) : 0;
|
||||
mg_printf(c,
|
||||
"%s %s HTTP/1.0\r\n"
|
||||
"Host: %.*s\r\n"
|
||||
"Content-Type: octet-stream\r\n"
|
||||
"Content-Length: %d\r\n"
|
||||
"\r\n",
|
||||
s_post_data ? "POST" : "GET", mg_url_uri(s_url), host.len,
|
||||
host.buf, content_length);
|
||||
mg_send(c, s_post_data, content_length);
|
||||
} else if (ev == MG_EV_HTTP_MSG) {
|
||||
// Response is received. Print it
|
||||
struct mg_http_message *hm = (struct mg_http_message *) ev_data;
|
||||
MG_INFO(("%lu Got response %lu bytes %lu", c->id, hm->body.len, c->rtls.len));
|
||||
*success = true;
|
||||
c->is_closing = 1;
|
||||
} else if (ev == MG_EV_ERROR) {
|
||||
MG_ERROR(("%lu Connection error: %s", c->id, ev_data));
|
||||
} else if (ev == MG_EV_CLOSE) {
|
||||
MG_DEBUG(("%lu Connection closed %lu", c->id, mg_millis() - *start_time));
|
||||
if (*success == false) MG_ERROR(("%lu NO RESPONSE %lu", c->id, c->rtls.len));
|
||||
if (c->is_draining == 0) s_conn = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void timer_fn(void *arg) {
|
||||
struct mg_mgr *mgr = (struct mg_mgr *) arg;
|
||||
// If connection is already there, do nothing. Otherwise, start it
|
||||
if (s_conn != NULL) {
|
||||
MG_DEBUG(("Connection is already active..."));
|
||||
} else {
|
||||
s_conn = mg_http_connect(mgr, s_url, http_ev_handler, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void) {
|
||||
struct mg_mgr mgr;
|
||||
mg_log_set(MG_LL_INFO);
|
||||
mg_mgr_init(&mgr);
|
||||
|
||||
// Attempt to start a POST request frequently
|
||||
mg_timer_add(&mgr, 50, MG_TIMER_REPEAT, timer_fn, &mgr);
|
||||
|
||||
for (;;) mg_mgr_poll(&mgr, 10);
|
||||
mg_mgr_free(&mgr);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
../../../mongoose.c
|
||||
@@ -0,0 +1 @@
|
||||
../../../mongoose.h
|
||||
Reference in New Issue
Block a user