Skip to content

Commit b3a34ad

Browse files
committed
Merge branch 'master' of https://github.com/civetweb/civetweb
2 parents 3e7eced + 98dab2e commit b3a34ad

File tree

6 files changed

+72
-21
lines changed

6 files changed

+72
-21
lines changed

.github/workflows/cibuild.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,7 @@ jobs:
392392

393393
steps:
394394
- name: Checkout code
395-
uses: actions/checkout@v4.1.7
395+
uses: actions/checkout@v5
396396

397397
- name: Export number of CPUs
398398
run: |

.github/workflows/codeql.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ jobs:
4545

4646
steps:
4747
- name: Checkout repository
48-
uses: actions/checkout@v4
48+
uses: actions/checkout@v5
4949
with:
5050
submodules: recursive
5151

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ CivetWeb is based on the [Mongoose project](https://github.com/cesanta/mongoose)
172172
Sergey Lyubka(2004-2013) who released it under the MIT license.
173173
However, on August 16, 2013,
174174
[Mongoose was relicensed to a dual GPL V2 + commercial license](https://groups.google.com/forum/#!topic/mongoose-users/aafbOnHonkI)
175-
and CiwetWeb was created by Thomas Davis (sunsetbrew) as "the MIT fork of mongoose".
175+
and CivetWeb was created by Thomas Davis (sunsetbrew) as "the MIT fork of mongoose".
176176
The license change and CivetWeb fork was mentioned on the Mongoose
177177
[Wikipedia](https://en.wikipedia.org/wiki/Mongoose_(web_server))
178178
page as well, but it's getting deleted (and added again) there every

src/civetweb.c

Lines changed: 65 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2087,7 +2087,7 @@ enum {
20872087
#if defined(USE_LUA) && defined(USE_WEBSOCKET)
20882088
LUA_WEBSOCKET_EXTENSIONS,
20892089
#endif
2090-
2090+
REPLACE_ASTERISK_WITH_ORIGIN,
20912091
ACCESS_CONTROL_ALLOW_ORIGIN,
20922092
ACCESS_CONTROL_ALLOW_METHODS,
20932093
ACCESS_CONTROL_ALLOW_HEADERS,
@@ -2253,6 +2253,7 @@ static const struct mg_option config_options[] = {
22532253
#if defined(USE_LUA) && defined(USE_WEBSOCKET)
22542254
{"lua_websocket_pattern", MG_CONFIG_TYPE_EXT_PATTERN, "**.lua$"},
22552255
#endif
2256+
{"replace_asterisk_with_origin", MG_CONFIG_TYPE_BOOLEAN, "no"},
22562257
{"access_control_allow_origin", MG_CONFIG_TYPE_STRING, "*"},
22572258
{"access_control_allow_methods", MG_CONFIG_TYPE_STRING, "*"},
22582259
{"access_control_allow_headers", MG_CONFIG_TYPE_STRING, "*"},
@@ -4234,16 +4235,27 @@ send_cors_header(struct mg_connection *conn)
42344235
conn->dom_ctx->config[ACCESS_CONTROL_EXPOSE_HEADERS];
42354236
const char *cors_meth_cfg =
42364237
conn->dom_ctx->config[ACCESS_CONTROL_ALLOW_METHODS];
4237-
4238-
if (cors_orig_cfg && *cors_orig_cfg && origin_hdr && *origin_hdr) {
4238+
const char *cors_repl_asterisk_with_orig_cfg =
4239+
conn->dom_ctx->config[REPLACE_ASTERISK_WITH_ORIGIN];
4240+
4241+
if (cors_orig_cfg && *cors_orig_cfg && origin_hdr && *origin_hdr && cors_repl_asterisk_with_orig_cfg && *cors_repl_asterisk_with_orig_cfg) {
4242+
int cors_repl_asterisk_with_orig = mg_strcasecmp(cors_repl_asterisk_with_orig_cfg, "yes");
4243+
42394244
/* Cross-origin resource sharing (CORS), see
42404245
* http://www.html5rocks.com/en/tutorials/cors/,
42414246
* http://www.html5rocks.com/static/images/cors_server_flowchart.png
42424247
* CORS preflight is not supported for files. */
4243-
mg_response_header_add(conn,
4248+
if (cors_repl_asterisk_with_orig == 0 && cors_orig_cfg[0] == '*') {
4249+
mg_response_header_add(conn,
4250+
"Access-Control-Allow-Origin",
4251+
origin_hdr,
4252+
-1);
4253+
} else {
4254+
mg_response_header_add(conn,
42444255
"Access-Control-Allow-Origin",
42454256
cors_orig_cfg,
42464257
-1);
4258+
}
42474259
}
42484260

42494261
if (cors_cred_cfg && *cors_cred_cfg && origin_hdr && *origin_hdr) {
@@ -15088,7 +15100,7 @@ handle_request(struct mg_connection *conn)
1508815100
}
1508915101
return;
1509015102
}
15091-
uri_len = (int)strlen(ri->local_uri);
15103+
1509215104

1509315105
/* 1.3. decode url (if config says so) */
1509415106
if (should_decode_url(conn)) {
@@ -15116,6 +15128,12 @@ handle_request(struct mg_connection *conn)
1511615128
}
1511715129
remove_dot_segments(tmp);
1511815130
ri->local_uri = tmp;
15131+
#if !defined(NO_FILES) /* Only compute if later code can actually use it */
15132+
/* Cache URI length once; recompute only if the buffer changes later. */
15133+
uri_len = (int)strlen(ri->local_uri);
15134+
#endif
15135+
15136+
1511915137

1512015138
/* step 1. completed, the url is known now */
1512115139
DEBUG_TRACE("REQUEST: %s %s", ri->request_method, ri->local_uri);
@@ -15168,13 +15186,18 @@ handle_request(struct mg_connection *conn)
1516815186
const char *cors_acrm = get_header(ri->http_headers,
1516915187
ri->num_headers,
1517015188
"Access-Control-Request-Method");
15171-
15189+
const char *cors_repl_asterisk_with_orig_cfg =
15190+
conn->dom_ctx->config[REPLACE_ASTERISK_WITH_ORIGIN];
15191+
1517215192
/* Todo: check if cors_origin is in cors_orig_cfg.
1517315193
* Or, let the client check this. */
1517415194

1517515195
if ((cors_meth_cfg != NULL) && (*cors_meth_cfg != 0)
1517615196
&& (cors_orig_cfg != NULL) && (*cors_orig_cfg != 0)
15177-
&& (cors_origin != NULL) && (cors_acrm != NULL)) {
15197+
&& (cors_origin != NULL) && (cors_acrm != NULL)
15198+
&& (cors_repl_asterisk_with_orig_cfg != NULL) && (*cors_repl_asterisk_with_orig_cfg != 0)) {
15199+
int cors_repl_asterisk_with_orig = mg_strcasecmp(cors_repl_asterisk_with_orig_cfg, "yes");
15200+
1517815201
/* This is a valid CORS preflight, and the server is configured
1517915202
* to handle it automatically. */
1518015203
const char *cors_acrh =
@@ -15195,7 +15218,7 @@ handle_request(struct mg_connection *conn)
1519515218
"Content-Length: 0\r\n"
1519615219
"Connection: %s\r\n",
1519715220
date,
15198-
cors_orig_cfg,
15221+
(cors_repl_asterisk_with_orig == 0 && cors_orig_cfg[0] == '*') ? cors_origin : cors_orig_cfg,
1519915222
((cors_meth_cfg[0] == '*') ? cors_acrm : cors_meth_cfg),
1520015223
suggest_connection_header(conn));
1520115224

@@ -15586,8 +15609,9 @@ handle_request(struct mg_connection *conn)
1558615609
}
1558715610

1558815611
/* 12. Directory uris should end with a slash */
15589-
if (file.stat.is_directory && ((uri_len = (int)strlen(ri->local_uri)) > 0)
15590-
&& (ri->local_uri[uri_len - 1] != '/')) {
15612+
if (file.stat.is_directory && (uri_len > 0)
15613+
&& (ri->local_uri[uri_len - 1] != '/')) {
15614+
1559115615

1559215616
/* Path + server root */
1559315617
size_t buflen = UTF8_PATH_MAX * 2 + 2;
@@ -15601,12 +15625,26 @@ handle_request(struct mg_connection *conn)
1560115625
mg_send_http_error(conn, 500, "out or memory");
1560215626
} else {
1560315627
mg_get_request_link(conn, new_path, buflen - 1);
15604-
strcat(new_path, "/");
15628+
15629+
size_t len = strlen(new_path);
15630+
if (len + 1 < buflen) {
15631+
new_path[len] = '/';
15632+
new_path[len + 1] = '\0';
15633+
len++;
15634+
}
15635+
1560515636
if (ri->query_string) {
15606-
/* Append ? and query string */
15607-
strcat(new_path, "?");
15608-
strcat(new_path, ri->query_string);
15637+
if (len + 1 < buflen) {
15638+
new_path[len] = '?';
15639+
new_path[len + 1] = '\0';
15640+
len++;
15641+
}
15642+
15643+
/* Append with size of space left for query string + null terminator */
15644+
size_t max_append = buflen - len - 1;
15645+
strncat(new_path, ri->query_string, max_append);
1560915646
}
15647+
1561015648
mg_send_http_redirect(conn, new_path, 301);
1561115649
mg_free(new_path);
1561215650
}
@@ -18867,6 +18905,19 @@ get_uri_type(const char *uri)
1886718905
* and % encoded symbols.
1886818906
*/
1886918907
for (i = 0; uri[i] != 0; i++) {
18908+
/* Check for CRLF injection attempts */
18909+
if (uri[i] == '%') {
18910+
if (uri[i+1] == '0' && (uri[i+2] == 'd' || uri[i+2] == 'D')) {
18911+
/* Found %0d (CR) */
18912+
DEBUG_TRACE("CRLF injection attempt detected: %s\r\n", uri);
18913+
return 0;
18914+
}
18915+
if (uri[i+1] == '0' && (uri[i+2] == 'a' || uri[i+2] == 'A')) {
18916+
/* Found %0a (LF) */
18917+
DEBUG_TRACE("CRLF injection attempt detected: %s\r\n", uri);
18918+
return 0;
18919+
}
18920+
}
1887018921
if ((unsigned char)uri[i] < 33) {
1887118922
/* control characters and spaces are invalid */
1887218923
return 0;

test/page4.lp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ the "Kepler syntax" uses <code>&lt;?lua chunk ?&gt;</code>, <code>&lt;?lua= expr
2222
<h2>Tags</h2>
2323

2424
<code>
25-
&lt;? greeting = 'CiwetWeb' ?&gt;<br/>
25+
&lt;? greeting = 'CivetWeb' ?&gt;<br/>
2626
&lt;strong&gt;&lt;?= greeting %&gt;&lt;/strong&gt;<br/>
2727
</code><br/>
28-
<? greeting = 'CiwetWeb' ?>
28+
<? greeting = 'CivetWeb' ?>
2929
==> <strong><?= greeting ?></strong><br/>
3030

3131
<br/>

test/page4kepler.lp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,10 @@ the "Kepler syntax" uses <code>&lt;?lua chunk ?&gt;</code>, <code>&lt;?lua= expr
1919
<h2>Tags</h2>
2020

2121
<code>
22-
&lt;? greeting = 'CiwetWeb' ?&gt;<br/>
22+
&lt;? greeting = 'CivetWeb' ?&gt;<br/>
2323
&lt;strong&gt;&lt;?= greeting %&gt;&lt;/strong&gt;<br/>
2424
</code><br/>
25-
<? greeting = 'CiwetWeb' ?>
25+
<? greeting = 'CivetWeb' ?>
2626
==> <strong><?= greeting ?></strong><br/>
2727

2828
<br/>

0 commit comments

Comments
 (0)