Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
cpq committed May 21, 2020
2 parents 359060a + 43a0b50 commit 80d74e9
Show file tree
Hide file tree
Showing 12 changed files with 335 additions and 181 deletions.
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,11 @@ the functionality:

# Contributions

To submit contributions, sign [Cesanta CLA](https://cesanta.com/cla.html)
and send GitHub pull request.
Contributions are welcome! Please follow the guidelines below:

- Sign [Cesanta CLA](https://cesanta.com/cla.html) and send GitHub pull request
- When making pull requests, please make sure that it has only one commit,
and imlements/fixes only one piece of functionality

# Looking for a pre-compiled Mongoose web server Windows or Mac binary?
- [Download pre-compiled Mongoose web server binary.](https://www.cesanta.com/binary.html)
4 changes: 4 additions & 0 deletions examples/http_proxy_client/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
PROG = http_proxy_client
#SSL_LIB=openssl
CFLAGS_EXTRA = -DMG_ENABLE_CALLBACK_USERDATA=1
include ../examples.mk
108 changes: 108 additions & 0 deletions examples/http_proxy_client/http_proxy_client.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
/*
* Copyright (c) 2014 Cesanta Software Limited
* All rights reserved
*
* This program fetches HTTP URLs.
*/

#define MG_ENABLE_CALLBACK_USERDATA 1
#include "mongoose.h"

static int s_exit_flag = 0;
static int s_show_headers = 0;

static void ev_handler(struct mg_connection *c, int ev, void *ev_data,
void *userdata) {
struct http_message *hm = (struct http_message *) ev_data;

switch (ev) {
case MG_EV_CONNECT:
if (*(int *) ev_data != 0) {
fprintf(stderr, "connect() failed: %s\n", strerror(*(int *) ev_data));
s_exit_flag = 1;
} else {
// Stage 2. Connection to the HTTP proxy is established.
// Write CONNECT request, and turn this connection to HTTP.
// NOTE: target URL is passed to us as userdata.
unsigned port = 80;
struct mg_str scheme, host;
mg_parse_uri(mg_mk_str((char *) userdata), &scheme, NULL, &host, &port,
NULL, NULL, NULL);
if (port == 0) port = (scheme.len == 5) ? 443 : 80;
mg_printf(c, "CONNECT %.*s:%u HTTP/1.1\r\n\r\n", (int) host.len, host.p,
port);
// Now set the flag and wait for the connection establishment
c->flags |= MG_F_USER_1;
}
break;
case MG_EV_RECV:
// Stage 3. Check if proxy replied. Here, we don't parse the reply
// for simplicity. Assume success, and write HTTP request.
if (c->flags & MG_F_USER_1) {
struct mg_str host, path;
c->flags &= ~MG_F_USER_1;
mg_parse_uri(mg_mk_str((char *) userdata), NULL, NULL, &host, NULL,
&path, NULL, NULL);
if (path.len == 0) path = mg_mk_str("/");
mg_printf(c, "GET %.*s HTTP/1.0\r\nHost: %.*s\r\n\r\n", (int) path.len,
path.p, (int) host.len, host.p);
mg_set_protocol_http_websocket(c);
}
break;
case MG_EV_HTTP_REPLY:
c->flags |= MG_F_CLOSE_IMMEDIATELY;
if (s_show_headers) {
fwrite(hm->message.p, 1, hm->message.len, stdout);
} else {
fwrite(hm->body.p, 1, hm->body.len, stdout);
}
putchar('\n');
s_exit_flag = 1;
break;
case MG_EV_CLOSE:
if (s_exit_flag == 0) {
printf("Server closed connection\n");
s_exit_flag = 1;
}
break;
default:
break;
}
}

int main(int argc, char *argv[]) {
struct mg_mgr mgr;
int i;

mg_mgr_init(&mgr, NULL);

/* Process command line arguments */
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "--show-headers") == 0) {
s_show_headers = 1;
} else if (strcmp(argv[i], "--hexdump") == 0 && i + 1 < argc) {
mgr.hexdump_file = argv[++i];
} else {
break;
}
}

if (i + 2 != argc) {
fprintf(stderr,
"Usage: %s [--hexdump <file>] "
"[--show-headers] PROXY_HOST:PROXY_PORT URL\n",
argv[0]);
exit(EXIT_FAILURE);
}

// Stage 1. Connect to the HTTP proxy as to a plain TCP server.
// Pass URL as a callback argument
mg_connect(&mgr, argv[i], ev_handler, argv[i + 1]);

while (s_exit_flag == 0) {
mg_mgr_poll(&mgr, 1000);
}
mg_mgr_free(&mgr);

return 0;
}
46 changes: 32 additions & 14 deletions mongoose.c
Original file line number Diff line number Diff line change
Expand Up @@ -4469,10 +4469,13 @@ struct mg_iface *mg_socks_mk_iface(struct mg_mgr *mgr, const char *proxy_addr) {
#endif

#include <openssl/ssl.h>
#include <openssl/err.h>
#ifndef KR_VERSION
#include <openssl/tls1.h>
#endif

static const char *mg_default_session_id_context = "mongoose";

struct mg_ssl_if_ctx {
SSL *ssl;
SSL_CTX *ssl_ctx;
Expand Down Expand Up @@ -4534,6 +4537,9 @@ enum mg_ssl_if_result mg_ssl_if_conn_init(
SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv2);
SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv3);
SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1);
SSL_CTX_set_session_id_context(ctx->ssl_ctx,
(void *) mg_default_session_id_context,
strlen(mg_default_session_id_context));
#ifdef MG_SSL_OPENSSL_NO_COMPRESSION
SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_COMPRESSION);
#endif
Expand Down Expand Up @@ -4591,6 +4597,17 @@ static enum mg_ssl_if_result mg_ssl_if_ssl_err(struct mg_connection *nc,
int res) {
struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
int err = SSL_get_error(ctx->ssl, res);
/*
* We've just fetched the last error from the queue.
* Now we need to clear the error queue. If we do not, then the following
* can happen (actually reported):
* - A new connection is accept()-ed with cert error (e.g. self-signed cert)
* - Since all accept()-ed connections share listener's context,
* - *ALL* SSL accepted connection report read error on the next poll cycle.
* Thus a single errored connection can close all the rest, unrelated ones.
* Clearing the error keeps the shared SSL_CTX in an OK state.
*/
ERR_clear_error();
if (err == SSL_ERROR_WANT_READ) return MG_SSL_WANT_READ;
if (err == SSL_ERROR_WANT_WRITE) return MG_SSL_WANT_WRITE;
DBG(("%p %p SSL error: %d %d", nc, ctx->ssl_ctx, res, err));
Expand Down Expand Up @@ -5865,7 +5882,7 @@ static void mg_http_free_proto_data_endpoints(struct mg_http_endpoint **ep) {
current = tmp;
}

ep = NULL;
*ep = NULL;
}

static void mg_http_free_reverse_proxy_data(struct mg_reverse_proxy_data *rpd) {
Expand Down Expand Up @@ -7731,7 +7748,7 @@ static void mg_print_dir_entry(struct mg_connection *nc, const char *file_name,
href = mg_url_encode(mg_mk_str(file_name));
mg_printf_http_chunk(nc,
"<tr><td><a href=\"%s%s\">%s%s</a></td>"
"<td>%s</td><td name=%" INT64_FMT ">%s</td></tr>\n",
"<td>%s</td><td name=\"%" INT64_FMT "\">%s</td></tr>",
href.p, slash, path, slash, mod, is_dir ? -1 : fsize,
size);
free((void *) href.p);
Expand Down Expand Up @@ -7797,23 +7814,24 @@ static void mg_send_directory_listing(struct mg_connection *nc, const char *dir,

mg_printf_http_chunk(
nc,
"<html><head><title>Index of %.*s</title>%s%s"
"<!DOCTYPE html><html><head><title>Index of %.*s</title>%s%s"
"<style>th,td {text-align: left; padding-right: 1em; "
"font-family: monospace; }</style></head>\n"
"<body><h1>Index of %.*s</h1>\n<table cellpadding=0><thead>"
"<tr><th><a href=# rel=0>Name</a></th><th>"
"<a href=# rel=1>Modified</a</th>"
"<th><a href=# rel=2>Size</a></th></tr>"
"<tr><td colspan=3><hr></td></tr>\n"
"</thead>\n"
"<tbody id=tb>",
"font-family: monospace; }</style></head>"
"<body><h1>Index of %.*s</h1><table cellpadding=\"0\"><thead>"
"<tr><th><a href=\"#\" rel=\"0\">Name</a></th><th>"
"<a href=\"#\" rel=\"1\">Modified</a></th>"
"<th><a href=\"#\" rel=\"2\">Size</a></th></tr>"
"<tr><td colspan=\"3\"><hr></td></tr>"
"</thead>"
"<tbody id=\"tb\">",
(int) hm->uri.len, hm->uri.p, sort_js_code, sort_js_code2,
(int) hm->uri.len, hm->uri.p);
mg_scan_directory(nc, dir, opts, mg_print_dir_entry);
mg_printf_http_chunk(nc,
"</tbody><tr><td colspan=3><hr></td></tr>\n"
"</table>\n"
"<address>%s</address>\n"
"</tbody>"
"<tfoot><tr><td colspan=\"3\"><hr></td></tr></tfoot>"
"</table>"
"<address>%s</address>"
"</body></html>",
mg_version_header);
mg_send_http_chunk(nc, "", 0);
Expand Down
4 changes: 2 additions & 2 deletions mongoose.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
#ifndef CS_MONGOOSE_SRC_COMMON_H_
#define CS_MONGOOSE_SRC_COMMON_H_

#define MG_VERSION "6.17"
#define MG_VERSION "6.18"

/* Local tweaks, applied before any of Mongoose's own headers. */
#ifdef MG_LOCALS
Expand Down Expand Up @@ -228,7 +228,7 @@
#include <windows.h>
#include <process.h>

#if _MSC_VER < 1700
#if defined(_MSC_VER) && (_MSC_VER < 1700)
typedef int bool;
#else
#include <stdbool.h>
Expand Down
2 changes: 1 addition & 1 deletion src/common/platforms/platform_windows.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
#include <windows.h>
#include <process.h>

#if _MSC_VER < 1700
#if defined(_MSC_VER) && (_MSC_VER < 1700)
typedef int bool;
#else
#include <stdbool.h>
Expand Down
29 changes: 15 additions & 14 deletions src/mg_http.c
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ static void mg_http_free_proto_data_endpoints(struct mg_http_endpoint **ep) {
current = tmp;
}

ep = NULL;
*ep = NULL;
}

static void mg_http_free_reverse_proxy_data(struct mg_reverse_proxy_data *rpd) {
Expand Down Expand Up @@ -2102,7 +2102,7 @@ static void mg_print_dir_entry(struct mg_connection *nc, const char *file_name,
href = mg_url_encode(mg_mk_str(file_name));
mg_printf_http_chunk(nc,
"<tr><td><a href=\"%s%s\">%s%s</a></td>"
"<td>%s</td><td name=%" INT64_FMT ">%s</td></tr>\n",
"<td>%s</td><td name=\"%" INT64_FMT "\">%s</td></tr>",
href.p, slash, path, slash, mod, is_dir ? -1 : fsize,
size);
free((void *) href.p);
Expand Down Expand Up @@ -2168,23 +2168,24 @@ static void mg_send_directory_listing(struct mg_connection *nc, const char *dir,

mg_printf_http_chunk(
nc,
"<html><head><title>Index of %.*s</title>%s%s"
"<!DOCTYPE html><html><head><title>Index of %.*s</title>%s%s"
"<style>th,td {text-align: left; padding-right: 1em; "
"font-family: monospace; }</style></head>\n"
"<body><h1>Index of %.*s</h1>\n<table cellpadding=0><thead>"
"<tr><th><a href=# rel=0>Name</a></th><th>"
"<a href=# rel=1>Modified</a</th>"
"<th><a href=# rel=2>Size</a></th></tr>"
"<tr><td colspan=3><hr></td></tr>\n"
"</thead>\n"
"<tbody id=tb>",
"font-family: monospace; }</style></head>"
"<body><h1>Index of %.*s</h1><table cellpadding=\"0\"><thead>"
"<tr><th><a href=\"#\" rel=\"0\">Name</a></th><th>"
"<a href=\"#\" rel=\"1\">Modified</a></th>"
"<th><a href=\"#\" rel=\"2\">Size</a></th></tr>"
"<tr><td colspan=\"3\"><hr></td></tr>"
"</thead>"
"<tbody id=\"tb\">",
(int) hm->uri.len, hm->uri.p, sort_js_code, sort_js_code2,
(int) hm->uri.len, hm->uri.p);
mg_scan_directory(nc, dir, opts, mg_print_dir_entry);
mg_printf_http_chunk(nc,
"</tbody><tr><td colspan=3><hr></td></tr>\n"
"</table>\n"
"<address>%s</address>\n"
"</tbody>"
"<tfoot><tr><td colspan=\"3\"><hr></td></tr></tfoot>"
"</table>"
"<address>%s</address>"
"</body></html>",
mg_version_header);
mg_send_http_chunk(nc, "", 0);
Expand Down
17 changes: 17 additions & 0 deletions src/mg_ssl_if_openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,13 @@
#endif

#include <openssl/ssl.h>
#include <openssl/err.h>
#ifndef KR_VERSION
#include <openssl/tls1.h>
#endif

static const char *mg_default_session_id_context = "mongoose";

struct mg_ssl_if_ctx {
SSL *ssl;
SSL_CTX *ssl_ctx;
Expand Down Expand Up @@ -75,6 +78,9 @@ enum mg_ssl_if_result mg_ssl_if_conn_init(
SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv2);
SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_SSLv3);
SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_TLSv1);
SSL_CTX_set_session_id_context(ctx->ssl_ctx,
(void *) mg_default_session_id_context,
strlen(mg_default_session_id_context));
#ifdef MG_SSL_OPENSSL_NO_COMPRESSION
SSL_CTX_set_options(ctx->ssl_ctx, SSL_OP_NO_COMPRESSION);
#endif
Expand Down Expand Up @@ -132,6 +138,17 @@ static enum mg_ssl_if_result mg_ssl_if_ssl_err(struct mg_connection *nc,
int res) {
struct mg_ssl_if_ctx *ctx = (struct mg_ssl_if_ctx *) nc->ssl_if_data;
int err = SSL_get_error(ctx->ssl, res);
/*
* We've just fetched the last error from the queue.
* Now we need to clear the error queue. If we do not, then the following
* can happen (actually reported):
* - A new connection is accept()-ed with cert error (e.g. self-signed cert)
* - Since all accept()-ed connections share listener's context,
* - *ALL* SSL accepted connection report read error on the next poll cycle.
* Thus a single errored connection can close all the rest, unrelated ones.
* Clearing the error keeps the shared SSL_CTX in an OK state.
*/
ERR_clear_error();
if (err == SSL_ERROR_WANT_READ) return MG_SSL_WANT_READ;
if (err == SSL_ERROR_WANT_WRITE) return MG_SSL_WANT_WRITE;
DBG(("%p %p SSL error: %d %d", nc, ctx->ssl_ctx, res, err));
Expand Down
Loading

0 comments on commit 80d74e9

Please sign in to comment.