|
@@ -1961,6 +1961,7 @@ enum {
|
|
|
#if defined(USE_TIMERS)
|
|
|
CGI_TIMEOUT,
|
|
|
#endif
|
|
|
+ CGI_BUFFERING,
|
|
|
|
|
|
CGI2_EXTENSIONS,
|
|
|
CGI2_ENVIRONMENT,
|
|
@@ -1969,6 +1970,7 @@ enum {
|
|
|
#if defined(USE_TIMERS)
|
|
|
CGI2_TIMEOUT,
|
|
|
#endif
|
|
|
+ CGI2_BUFFERING,
|
|
|
|
|
|
#if defined(USE_4_CGI)
|
|
|
CGI3_EXTENSIONS,
|
|
@@ -1978,6 +1980,7 @@ enum {
|
|
|
#if defined(USE_TIMERS)
|
|
|
CGI3_TIMEOUT,
|
|
|
#endif
|
|
|
+ CGI3_BUFFERING,
|
|
|
|
|
|
CGI4_EXTENSIONS,
|
|
|
CGI4_ENVIRONMENT,
|
|
@@ -1986,6 +1989,7 @@ enum {
|
|
|
#if defined(USE_TIMERS)
|
|
|
CGI4_TIMEOUT,
|
|
|
#endif
|
|
|
+ CGI4_BUFFERING,
|
|
|
#endif
|
|
|
|
|
|
PUT_DELETE_PASSWORDS_FILE, /* must follow CGI_* */
|
|
@@ -2100,6 +2104,7 @@ static const struct mg_option config_options[] = {
|
|
|
#if defined(USE_TIMERS)
|
|
|
{"cgi_timeout_ms", MG_CONFIG_TYPE_NUMBER, NULL},
|
|
|
#endif
|
|
|
+ {"cgi_buffering", MG_CONFIG_TYPE_BOOLEAN, "yes"},
|
|
|
|
|
|
{"cgi2_pattern", MG_CONFIG_TYPE_EXT_PATTERN, NULL},
|
|
|
{"cgi2_environment", MG_CONFIG_TYPE_STRING_LIST, NULL},
|
|
@@ -2108,6 +2113,7 @@ static const struct mg_option config_options[] = {
|
|
|
#if defined(USE_TIMERS)
|
|
|
{"cgi2_timeout_ms", MG_CONFIG_TYPE_NUMBER, NULL},
|
|
|
#endif
|
|
|
+ {"cgi2_buffering", MG_CONFIG_TYPE_BOOLEAN, "yes"},
|
|
|
|
|
|
#if defined(USE_4_CGI)
|
|
|
{"cgi3_pattern", MG_CONFIG_TYPE_EXT_PATTERN, NULL},
|
|
@@ -2117,6 +2123,7 @@ static const struct mg_option config_options[] = {
|
|
|
#if defined(USE_TIMERS)
|
|
|
{"cgi3_timeout_ms", MG_CONFIG_TYPE_NUMBER, NULL},
|
|
|
#endif
|
|
|
+ {"cgi3_buffering", MG_CONFIG_TYPE_BOOLEAN, "yes"},
|
|
|
|
|
|
{"cgi4_pattern", MG_CONFIG_TYPE_EXT_PATTERN, NULL},
|
|
|
{"cgi4_environment", MG_CONFIG_TYPE_STRING_LIST, NULL},
|
|
@@ -2125,6 +2132,8 @@ static const struct mg_option config_options[] = {
|
|
|
#if defined(USE_TIMERS)
|
|
|
{"cgi4_timeout_ms", MG_CONFIG_TYPE_NUMBER, NULL},
|
|
|
#endif
|
|
|
+ {"cgi4_buffering", MG_CONFIG_TYPE_BOOLEAN, "yes"},
|
|
|
+
|
|
|
#endif
|
|
|
|
|
|
{"put_delete_auth_file", MG_CONFIG_TYPE_FILE, NULL},
|
|
@@ -9920,7 +9929,8 @@ static void
|
|
|
send_file_data(struct mg_connection *conn,
|
|
|
struct mg_file *filep,
|
|
|
int64_t offset,
|
|
|
- int64_t len)
|
|
|
+ int64_t len,
|
|
|
+ int no_buffering)
|
|
|
{
|
|
|
char buf[MG_BUF_LEN];
|
|
|
int to_read, num_read, num_written;
|
|
@@ -9993,8 +10003,8 @@ send_file_data(struct mg_connection *conn,
|
|
|
"Error: Unable to access file at requested position.");
|
|
|
} else {
|
|
|
while (len > 0) {
|
|
|
- /* Calculate how much to read from the file in the buffer */
|
|
|
- to_read = sizeof(buf);
|
|
|
+ /* Calculate how much to read from the file into the buffer */
|
|
|
+ to_read = no_buffering ? 1 : sizeof(buf);
|
|
|
if ((int64_t)to_read > len) {
|
|
|
to_read = (int)len;
|
|
|
}
|
|
@@ -10295,7 +10305,7 @@ handle_static_file_request(struct mg_connection *conn,
|
|
|
#endif
|
|
|
{
|
|
|
/* Send file directly */
|
|
|
- send_file_data(conn, filep, r1, cl);
|
|
|
+ send_file_data(conn, filep, r1, cl, 0); /* send static file */
|
|
|
}
|
|
|
}
|
|
|
(void)mg_fclose(&filep->access); /* ignore error on read only file */
|
|
@@ -10310,7 +10320,7 @@ mg_send_file_body(struct mg_connection *conn, const char *path)
|
|
|
return -1;
|
|
|
}
|
|
|
fclose_on_exec(&file.access, conn);
|
|
|
- send_file_data(conn, &file, 0, INT64_MAX);
|
|
|
+ send_file_data(conn, &file, 0, INT64_MAX, 0); /* send static file */
|
|
|
(void)mg_fclose(&file.access); /* Ignore errors for readonly files */
|
|
|
return 0; /* >= 0 for OK */
|
|
|
}
|
|
@@ -11452,6 +11462,8 @@ handle_cgi_request(struct mg_connection *conn,
|
|
|
struct mg_file fout = STRUCT_FILE_INITIALIZER;
|
|
|
pid_t pid = (pid_t)-1;
|
|
|
struct process_control_data *proc = NULL;
|
|
|
+ char *cfg_buffering = conn->dom_ctx->config[CGI_BUFFERING + cgi_config_idx];
|
|
|
+ int no_buffering = 0;
|
|
|
|
|
|
#if defined(USE_TIMERS)
|
|
|
double cgi_timeout;
|
|
@@ -11463,8 +11475,12 @@ handle_cgi_request(struct mg_connection *conn,
|
|
|
cgi_timeout =
|
|
|
atof(config_options[REQUEST_TIMEOUT].default_value) * 0.001;
|
|
|
}
|
|
|
-
|
|
|
#endif
|
|
|
+ if (cfg_buffering != NULL) {
|
|
|
+ if (!mg_strcasecmp(cfg_buffering, "no")) {
|
|
|
+ no_buffering = 1;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
buf = NULL;
|
|
|
buflen = conn->phys_ctx->max_request_size;
|
|
@@ -11713,7 +11729,7 @@ handle_cgi_request(struct mg_connection *conn,
|
|
|
|
|
|
/* Read the rest of CGI output and send to the client */
|
|
|
DEBUG_TRACE("CGI: %s", "forward all data");
|
|
|
- send_file_data(conn, &fout, 0, INT64_MAX);
|
|
|
+ send_file_data(conn, &fout, 0, INT64_MAX, no_buffering); /* send CGI data */
|
|
|
DEBUG_TRACE("CGI: %s", "all data sent");
|
|
|
|
|
|
done:
|
|
@@ -12257,7 +12273,7 @@ do_ssi_include(struct mg_connection *conn,
|
|
|
> 0) {
|
|
|
send_ssi_file(conn, path, &file, include_level + 1);
|
|
|
} else {
|
|
|
- send_file_data(conn, &file, 0, INT64_MAX);
|
|
|
+ send_file_data(conn, &file, 0, INT64_MAX, 0); /* send static file */
|
|
|
}
|
|
|
(void)mg_fclose(&file.access); /* Ignore errors for readonly files */
|
|
|
}
|
|
@@ -12281,7 +12297,7 @@ do_ssi_exec(struct mg_connection *conn, char *tag)
|
|
|
cmd,
|
|
|
strerror(ERRNO));
|
|
|
} else {
|
|
|
- send_file_data(conn, &file, 0, INT64_MAX);
|
|
|
+ send_file_data(conn, &file, 0, INT64_MAX, 0); /* send static file */
|
|
|
pclose(file.access.fp);
|
|
|
}
|
|
|
}
|
|
@@ -15189,7 +15205,7 @@ handle_file_based_request(struct mg_connection *conn,
|
|
|
> 0) {
|
|
|
if (is_in_script_path(conn, path)) {
|
|
|
/* CGI scripts may support all HTTP methods */
|
|
|
- handle_cgi_request(conn, path, 0);
|
|
|
+ handle_cgi_request(conn, path, cgi_config_idx);
|
|
|
} else {
|
|
|
/* Script was in an illegal path */
|
|
|
mg_send_http_error(conn, 403, "%s", "Forbidden");
|