1
0
mirror of https://github.com/lammertb/libhttp.git synced 2026-01-27 08:02:47 +03:00

Moved SSI functions to own file

This commit is contained in:
Lammert Bies
2016-12-10 22:11:48 +01:00
parent d695b40c5e
commit e7ccb97c19
4 changed files with 272 additions and 234 deletions

View File

@@ -95,6 +95,7 @@ LIB_SOURCES = src/libhttp.c \
src/httplib_set_throttle.c \
src/httplib_set_uid_option.c \
src/httplib_set_websocket_handler.c \
src/httplib_ssi.c \
src/httplib_ssl_error.c \
src/httplib_ssl_get_client_cert_info.c \
src/httplib_ssl_get_protocol.c \

239
src/httplib_ssi.c Normal file
View File

@@ -0,0 +1,239 @@
/*
* Copyright (c) 2016 Lammert Bies
* Copyright (c) 2013-2016 the Civetweb developers
* Copyright (c) 2004-2013 Sergey Lyubka
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "libhttp-private.h"
static void send_ssi_file(struct mg_connection *, const char *, struct file *, int);
static void do_ssi_include(struct mg_connection *conn, const char *ssi, char *tag, int include_level) {
char file_name[MG_BUF_LEN];
char path[512];
char *p;
struct file file = STRUCT_FILE_INITIALIZER;
size_t len;
int truncated = 0;
if ( conn == NULL ) return;
/* sscanf() is safe here, since send_ssi_file() also uses buffer
* of size MG_BUF_LEN to get the tag. So strlen(tag) is
* always < MG_BUF_LEN. */
if (sscanf(tag, " virtual=\"%511[^\"]\"", file_name) == 1) {
/* File name is relative to the webserver root */
file_name[511] = 0;
XX_httplib_snprintf(conn, &truncated, path, sizeof(path), "%s/%s", conn->ctx->config[DOCUMENT_ROOT], file_name);
} else if (sscanf(tag, " abspath=\"%511[^\"]\"", file_name) == 1) {
/* File name is relative to the webserver working directory
* or it is absolute system path */
file_name[511] = 0;
XX_httplib_snprintf(conn, &truncated, path, sizeof(path), "%s", file_name);
} else if (sscanf(tag, " file=\"%511[^\"]\"", file_name) == 1
|| sscanf(tag, " \"%511[^\"]\"", file_name) == 1) {
/* File name is relative to the currect document */
file_name[511] = 0;
XX_httplib_snprintf(conn, &truncated, path, sizeof(path), "%s", ssi);
if (!truncated) {
if ((p = strrchr(path, '/')) != NULL) p[1] = '\0';
len = strlen(path);
XX_httplib_snprintf(conn, &truncated, path + len, sizeof(path) - len, "%s", file_name);
}
} else {
mg_cry(conn, "Bad SSI #include: [%s]", tag);
return;
}
if (truncated) {
mg_cry(conn, "SSI #include path length overflow: [%s]", tag);
return;
}
if (!XX_httplib_fopen(conn, path, "rb", &file)) {
mg_cry(conn, "Cannot open SSI #include: [%s]: fopen(%s): %s", tag, path, strerror(ERRNO));
} else {
XX_httplib_fclose_on_exec(&file, conn);
if (XX_httplib_match_prefix(conn->ctx->config[SSI_EXTENSIONS], strlen(conn->ctx->config[SSI_EXTENSIONS]), path) > 0) {
send_ssi_file(conn, path, &file, include_level + 1);
} else {
XX_httplib_send_file_data(conn, &file, 0, INT64_MAX);
}
XX_httplib_fclose(&file);
}
}
#if !defined(NO_POPEN)
static void do_ssi_exec(struct mg_connection *conn, char *tag) {
char cmd[1024] = "";
struct file file = STRUCT_FILE_INITIALIZER;
if (sscanf(tag, " \"%1023[^\"]\"", cmd) != 1) {
mg_cry(conn, "Bad SSI #exec: [%s]", tag);
} else {
cmd[1023] = 0;
if ((file.fp = popen(cmd, "r")) == NULL) {
mg_cry(conn, "Cannot SSI #exec: [%s]: %s", cmd, strerror(ERRNO));
} else {
XX_httplib_send_file_data(conn, &file, 0, INT64_MAX);
pclose(file.fp);
}
}
}
#endif /* !NO_POPEN */
static int mg_fgetc( struct file *filep, int offset ) {
if ( filep == NULL ) return EOF;
if ( filep->membuf != NULL && offset >= 0 && ((unsigned int)(offset)) < filep->size ) return ((const unsigned char *)filep->membuf)[offset];
if ( filep->fp != NULL ) return fgetc( filep->fp );
return EOF;
} /* mg_fgetc */
static void send_ssi_file( struct mg_connection *conn, const char *path, struct file *filep, int include_level ) {
char buf[MG_BUF_LEN];
int ch;
int offset;
int len;
int in_ssi_tag;
if (include_level > 10) {
mg_cry(conn, "SSI #include level is too deep (%s)", path);
return;
}
in_ssi_tag = len = offset = 0;
while ((ch = mg_fgetc(filep, offset)) != EOF) {
if (in_ssi_tag && ch == '>') {
in_ssi_tag = 0;
buf[len++] = (char)ch;
buf[len] = '\0';
/* assert(len <= (int) sizeof(buf)); */
if (len > (int)sizeof(buf)) break;
if (len < 6 || memcmp(buf, "<!--#", 5) != 0) {
/* Not an SSI tag, pass it */
mg_write( conn, buf, (size_t)len );
} else {
if (!memcmp(buf + 5, "include", 7)) {
do_ssi_include(conn, path, buf + 12, include_level);
#if !defined(NO_POPEN)
} else if (!memcmp(buf + 5, "exec", 4)) {
do_ssi_exec(conn, buf + 9);
#endif /* !NO_POPEN */
} else mg_cry(conn, "%s: unknown SSI " "command: \"%s\"", path, buf);
}
len = 0;
} else if (in_ssi_tag) {
if (len == 5 && memcmp(buf, "<!--#", 5) != 0) {
/* Not an SSI tag */
in_ssi_tag = 0;
} else if (len == (int)sizeof(buf) - 2) {
mg_cry(conn, "%s: SSI tag is too large", path);
len = 0;
}
buf[len++] = (char)(ch & 0xff);
} else if (ch == '<') {
in_ssi_tag = 1;
if (len > 0) {
mg_write(conn, buf, (size_t)len);
}
len = 0;
buf[len++] = (char)(ch & 0xff);
} else {
buf[len++] = (char)(ch & 0xff);
if (len == (int)sizeof(buf)) {
mg_write(conn, buf, (size_t)len);
len = 0;
}
}
}
/* Send the rest of buffered data */
if (len > 0) mg_write(conn, buf, (size_t)len);
}
void XX_httplib_handle_ssi_file_request( struct mg_connection *conn, const char *path, struct file *filep ) {
char date[64];
time_t curtime;
const char *cors1;
const char *cors2;
const char *cors3;
if ( conn == NULL || path == NULL || filep == NULL ) return;
curtime = time( NULL );
if (mg_get_header(conn, "Origin")) {
/* Cross-origin resource sharing (CORS). */
cors1 = "Access-Control-Allow-Origin: ";
cors2 = conn->ctx->config[ACCESS_CONTROL_ALLOW_ORIGIN];
cors3 = "\r\n";
} else {
cors1 = "";
cors2 = "";
cors3 = "";
}
if (!XX_httplib_fopen(conn, path, "rb", filep)) {
/* File exists (precondition for calling this function),
* but can not be opened by the server. */
XX_httplib_send_http_error(conn, 500, "Error: Cannot read file\nfopen(%s): %s", path, strerror(ERRNO));
} else {
conn->must_close = 1;
XX_httplib_gmt_time_string(date, sizeof(date), &curtime);
XX_httplib_fclose_on_exec(filep, conn);
mg_printf(conn, "HTTP/1.1 200 OK\r\n");
XX_httplib_send_no_cache_header(conn);
mg_printf(conn,
"%s%s%s"
"Date: %s\r\n"
"Content-Type: text/html\r\n"
"Connection: %s\r\n\r\n",
cors1,
cors2,
cors3,
date,
XX_httplib_suggest_connection_header(conn));
send_ssi_file(conn, path, filep, 0);
XX_httplib_fclose(filep);
}
} /* XX_httplib_handle_ssi_file_request */

View File

@@ -657,6 +657,14 @@ struct mg_workerTLS {
};
#define PASSWORDS_FILE_NAME ".htpasswd"
#define CGI_ENVIRONMENT_SIZE (4096)
#define MAX_CGI_ENVIR_VARS (256)
#define MG_BUF_LEN (8192)
mg_static_assert(MAX_REQUEST_SIZE >= 256, "request size length must be a positive number");
/* Describes listening socket, or socket which was accept()-ed by the master
* thread and queued for future handling by the worker thread. */
struct socket {
@@ -864,6 +872,7 @@ void XX_httplib_delete_file( struct mg_connection *conn, const char *path );
void XX_httplib_discard_unread_request_data( struct mg_connection *conn );
struct mg_connection * XX_httplib_fc( struct mg_context *ctx );
void XX_httplib_fclose( struct file *filep );
void XX_httplib_fclose_on_exec( struct file *filep, struct mg_connection *conn );
int XX_httplib_fopen( const struct mg_connection *conn, const char *path, const char *mode, struct file *filep );
void XX_httplib_free_context( struct mg_context *ctx );
int XX_httplib_get_first_ssl_listener_index( const struct mg_context *ctx );
@@ -917,7 +926,9 @@ void XX_httplib_remove_double_dots_and_double_slashes( char *s );
void XX_httplib_reset_per_request_attributes( struct mg_connection *conn );
int XX_httplib_scan_directory( struct mg_connection *conn, const char *dir, void *data, void (*cb)(struct de *, void *) );
void XX_httplib_send_authorization_request( struct mg_connection *conn );
void XX_httplib_send_http_error( struct mg_connection *, int, PRINTF_FORMAT_STRING(const char *fmt), ... ) PRINTF_ARGS(3, 4);
void XX_httplib_send_file_data( struct mg_connection *conn, struct file *filep, int64_t offset, int64_t len );
void XX_httplib_send_http_error( struct mg_connection *, int, PRINTF_FORMAT_STRING(const char *fmt), ... ) PRINTF_ARGS(3, 4);
int XX_httplib_send_no_cache_header( struct mg_connection *conn );
void XX_httplib_send_options( struct mg_connection *conn );
int XX_httplib_send_static_cache_header( struct mg_connection *conn );
int XX_httplib_send_websocket_handshake( struct mg_connection *conn, const char *websock_key );

View File

@@ -162,13 +162,6 @@ pthread_mutexattr_t XX_httplib_pthread_mutex_attr;
#endif /* _WIN32 */
#define PASSWORDS_FILE_NAME ".htpasswd"
#define CGI_ENVIRONMENT_SIZE (4096)
#define MAX_CGI_ENVIR_VARS (256)
#define MG_BUF_LEN (8192)
mg_static_assert(MAX_REQUEST_SIZE >= 256, "request size length must be a positive number");
#if !defined(DEBUG_TRACE)
#if defined(DEBUG)
@@ -1482,7 +1475,7 @@ const char * XX_httplib_suggest_connection_header( const struct mg_connection *c
} /* XX_httplib_suggest_connection_header */
static int send_no_cache_header(struct mg_connection *conn) {
int XX_httplib_send_no_cache_header( struct mg_connection *conn ) {
/* Send all current and obsolete cache opt-out directives. */
return mg_printf(conn,
@@ -1490,7 +1483,8 @@ static int send_no_cache_header(struct mg_connection *conn) {
"must-revalidate, private, max-age=0\r\n"
"Pragma: no-cache\r\n"
"Expires: 0\r\n");
}
} /* XX_httplib_send_no_cache_header */
int XX_httplib_send_static_cache_header(struct mg_connection *conn) {
@@ -1504,7 +1498,7 @@ int XX_httplib_send_static_cache_header(struct mg_connection *conn) {
* and may be used differently in the future. */
/* If a file should not be cached, do not only send
* max-age=0, but also pragmas and Expires headers. */
return send_no_cache_header(conn);
return XX_httplib_send_no_cache_header(conn);
}
/* Use "Cache-Control: max-age" instead of "Expires" header.
@@ -1517,7 +1511,7 @@ int XX_httplib_send_static_cache_header(struct mg_connection *conn) {
* as undefined. */
return mg_printf(conn, "Cache-Control: max-age=%u\r\n", (unsigned)max_age);
#else /* NO_CACHING */
return send_no_cache_header(conn);
return XX_httplib_send_no_cache_header(conn);
#endif /* !NO_CACHING */
} /* XX_httplib_send_static_cache_header */
@@ -1605,7 +1599,7 @@ void XX_httplib_send_http_error( struct mg_connection *conn, int status, const c
conn->must_close = 1;
mg_printf(conn, "HTTP/1.1 %d %s\r\n", status, status_text);
send_no_cache_header(conn);
XX_httplib_send_no_cache_header(conn);
if (has_body) mg_printf(conn, "%s", "Content-Type: text/plain; charset=utf-8\r\n");
mg_printf(conn, "Date: %s\r\n" "Connection: close\r\n\r\n", date);
@@ -4182,7 +4176,7 @@ void XX_httplib_send_authorization_request( struct mg_connection *conn ) {
XX_httplib_gmt_time_string(date, sizeof(date), &curtime);
mg_printf(conn, "HTTP/1.1 401 Unauthorized\r\n");
send_no_cache_header(conn);
XX_httplib_send_no_cache_header(conn);
mg_printf(conn,
"Date: %s\r\n"
"Connection: %s\r\n"
@@ -4771,7 +4765,7 @@ void XX_httplib_handle_directory_request( struct mg_connection *conn, const char
/* Send len bytes from the opened file to the client. */
static void send_file_data(struct mg_connection *conn, struct file *filep, int64_t offset, int64_t len) {
void XX_httplib_send_file_data( struct mg_connection *conn, struct file *filep, int64_t offset, int64_t len ) {
char buf[MG_BUF_LEN];
int to_read;
@@ -4861,7 +4855,8 @@ static void send_file_data(struct mg_connection *conn, struct file *filep, int64
}
}
}
}
} /* XX_httplib_send_file_data */
static int parse_range_header(const char *header, int64_t *a, int64_t *b) {
@@ -4878,7 +4873,7 @@ static void construct_etag(char *buf, size_t buf_len, const struct file *filep)
}
static void fclose_on_exec(struct file *filep, struct mg_connection *conn) {
void XX_httplib_fclose_on_exec( struct file *filep, struct mg_connection *conn ) {
if (filep != NULL && filep->fp != NULL) {
#ifdef _WIN32
@@ -4889,7 +4884,9 @@ static void fclose_on_exec(struct file *filep, struct mg_connection *conn) {
}
#endif
}
}
} /* XX_httplib_fclose_on_exec */
void XX_httplib_handle_static_file_request( struct mg_connection *conn, const char *path, struct file *filep, const char *mime_type, const char *additional_headers ) {
@@ -4947,7 +4944,7 @@ void XX_httplib_handle_static_file_request( struct mg_connection *conn, const ch
return;
}
fclose_on_exec(filep, conn);
XX_httplib_fclose_on_exec(filep, conn);
/* If Range: header specified, act accordingly */
r1 = r2 = 0;
@@ -5019,7 +5016,7 @@ void XX_httplib_handle_static_file_request( struct mg_connection *conn, const ch
mg_printf(conn, "%.*s\r\n\r\n", (int)strlen(additional_headers), additional_headers);
} else mg_printf(conn, "\r\n");
if (strcmp(conn->request_info.request_method, "HEAD") != 0) send_file_data(conn, filep, r1, cl);
if (strcmp(conn->request_info.request_method, "HEAD") != 0) XX_httplib_send_file_data(conn, filep, r1, cl);
XX_httplib_fclose(filep);
} /* XX_handle_static_file_request */
@@ -5922,7 +5919,7 @@ void XX_httplib_handle_cgi_request( struct mg_connection *conn, const char *prog
mg_write(conn, buf + headers_len, (size_t)(data_len - headers_len));
/* Read the rest of CGI output and send to the client */
send_file_data(conn, &fout, 0, INT64_MAX);
XX_httplib_send_file_data(conn, &fout, 0, INT64_MAX);
done:
XX_httplib_free(blk.var);
@@ -6059,7 +6056,7 @@ void XX_httplib_put_file( struct mg_connection *conn, const char *path ) {
/* put_dir returns 0 if path is a directory */
XX_httplib_gmt_time_string(date, sizeof(date), &curtime);
mg_printf(conn, "HTTP/1.1 %d %s\r\n", conn->status_code, mg_get_response_code_text(NULL, conn->status_code));
send_no_cache_header(conn);
XX_httplib_send_no_cache_header(conn);
mg_printf(conn, "Date: %s\r\n" "Content-Length: 0\r\n" "Connection: %s\r\n\r\n", date, XX_httplib_suggest_connection_header(conn));
/* Request to create a directory has been fulfilled successfully.
@@ -6086,7 +6083,7 @@ void XX_httplib_put_file( struct mg_connection *conn, const char *path ) {
return;
}
fclose_on_exec(&file, conn);
XX_httplib_fclose_on_exec(&file, conn);
range = mg_get_header(conn, "Content-Range");
r1 = r2 = 0;
if (range != NULL && parse_range_header(range, &r1, &r2) > 0) {
@@ -6104,7 +6101,7 @@ void XX_httplib_put_file( struct mg_connection *conn, const char *path ) {
XX_httplib_gmt_time_string(date, sizeof(date), &curtime);
mg_printf(conn, "HTTP/1.1 %d %s\r\n", conn->status_code, mg_get_response_code_text(NULL, conn->status_code));
send_no_cache_header(conn);
XX_httplib_send_no_cache_header(conn);
mg_printf(conn, "Date: %s\r\n" "Content-Length: 0\r\n" "Connection: %s\r\n\r\n", date, XX_httplib_suggest_connection_header(conn));
XX_httplib_fclose(&file);
@@ -6160,213 +6157,3 @@ void XX_httplib_delete_file( struct mg_connection *conn, const char *path ) {
} /* XX_httplib_delete_file */
#endif /* !NO_FILES */
static void send_ssi_file(struct mg_connection *, const char *, struct file *, int);
static void do_ssi_include(struct mg_connection *conn, const char *ssi, char *tag, int include_level) {
char file_name[MG_BUF_LEN], path[512];
char *p;
struct file file = STRUCT_FILE_INITIALIZER;
size_t len;
int truncated = 0;
if ( conn == NULL ) return;
/* sscanf() is safe here, since send_ssi_file() also uses buffer
* of size MG_BUF_LEN to get the tag. So strlen(tag) is
* always < MG_BUF_LEN. */
if (sscanf(tag, " virtual=\"%511[^\"]\"", file_name) == 1) {
/* File name is relative to the webserver root */
file_name[511] = 0;
XX_httplib_snprintf(conn, &truncated, path, sizeof(path), "%s/%s", conn->ctx->config[DOCUMENT_ROOT], file_name);
} else if (sscanf(tag, " abspath=\"%511[^\"]\"", file_name) == 1) {
/* File name is relative to the webserver working directory
* or it is absolute system path */
file_name[511] = 0;
XX_httplib_snprintf(conn, &truncated, path, sizeof(path), "%s", file_name);
} else if (sscanf(tag, " file=\"%511[^\"]\"", file_name) == 1
|| sscanf(tag, " \"%511[^\"]\"", file_name) == 1) {
/* File name is relative to the currect document */
file_name[511] = 0;
XX_httplib_snprintf(conn, &truncated, path, sizeof(path), "%s", ssi);
if (!truncated) {
if ((p = strrchr(path, '/')) != NULL) p[1] = '\0';
len = strlen(path);
XX_httplib_snprintf(conn, &truncated, path + len, sizeof(path) - len, "%s", file_name);
}
} else {
mg_cry(conn, "Bad SSI #include: [%s]", tag);
return;
}
if (truncated) {
mg_cry(conn, "SSI #include path length overflow: [%s]", tag);
return;
}
if (!XX_httplib_fopen(conn, path, "rb", &file)) {
mg_cry(conn, "Cannot open SSI #include: [%s]: fopen(%s): %s", tag, path, strerror(ERRNO));
} else {
fclose_on_exec(&file, conn);
if (XX_httplib_match_prefix(conn->ctx->config[SSI_EXTENSIONS], strlen(conn->ctx->config[SSI_EXTENSIONS]), path) > 0) {
send_ssi_file(conn, path, &file, include_level + 1);
} else {
send_file_data(conn, &file, 0, INT64_MAX);
}
XX_httplib_fclose(&file);
}
}
#if !defined(NO_POPEN)
static void do_ssi_exec(struct mg_connection *conn, char *tag) {
char cmd[1024] = "";
struct file file = STRUCT_FILE_INITIALIZER;
if (sscanf(tag, " \"%1023[^\"]\"", cmd) != 1) {
mg_cry(conn, "Bad SSI #exec: [%s]", tag);
} else {
cmd[1023] = 0;
if ((file.fp = popen(cmd, "r")) == NULL) {
mg_cry(conn, "Cannot SSI #exec: [%s]: %s", cmd, strerror(ERRNO));
} else {
send_file_data(conn, &file, 0, INT64_MAX);
pclose(file.fp);
}
}
}
#endif /* !NO_POPEN */
static int mg_fgetc( struct file *filep, int offset ) {
if ( filep == NULL ) return EOF;
if ( filep->membuf != NULL && offset >= 0 && ((unsigned int)(offset)) < filep->size ) return ((const unsigned char *)filep->membuf)[offset];
if ( filep->fp != NULL ) return fgetc( filep->fp );
return EOF;
} /* mg_fgetc */
static void send_ssi_file( struct mg_connection *conn, const char *path, struct file *filep, int include_level ) {
char buf[MG_BUF_LEN];
int ch;
int offset;
int len;
int in_ssi_tag;
if (include_level > 10) {
mg_cry(conn, "SSI #include level is too deep (%s)", path);
return;
}
in_ssi_tag = len = offset = 0;
while ((ch = mg_fgetc(filep, offset)) != EOF) {
if (in_ssi_tag && ch == '>') {
in_ssi_tag = 0;
buf[len++] = (char)ch;
buf[len] = '\0';
/* assert(len <= (int) sizeof(buf)); */
if (len > (int)sizeof(buf)) break;
if (len < 6 || memcmp(buf, "<!--#", 5) != 0) {
/* Not an SSI tag, pass it */
mg_write( conn, buf, (size_t)len );
} else {
if (!memcmp(buf + 5, "include", 7)) {
do_ssi_include(conn, path, buf + 12, include_level);
#if !defined(NO_POPEN)
} else if (!memcmp(buf + 5, "exec", 4)) {
do_ssi_exec(conn, buf + 9);
#endif /* !NO_POPEN */
} else mg_cry(conn, "%s: unknown SSI " "command: \"%s\"", path, buf);
}
len = 0;
} else if (in_ssi_tag) {
if (len == 5 && memcmp(buf, "<!--#", 5) != 0) {
/* Not an SSI tag */
in_ssi_tag = 0;
} else if (len == (int)sizeof(buf) - 2) {
mg_cry(conn, "%s: SSI tag is too large", path);
len = 0;
}
buf[len++] = (char)(ch & 0xff);
} else if (ch == '<') {
in_ssi_tag = 1;
if (len > 0) {
mg_write(conn, buf, (size_t)len);
}
len = 0;
buf[len++] = (char)(ch & 0xff);
} else {
buf[len++] = (char)(ch & 0xff);
if (len == (int)sizeof(buf)) {
mg_write(conn, buf, (size_t)len);
len = 0;
}
}
}
/* Send the rest of buffered data */
if (len > 0) mg_write(conn, buf, (size_t)len);
}
void XX_httplib_handle_ssi_file_request( struct mg_connection *conn, const char *path, struct file *filep ) {
char date[64];
time_t curtime;
const char *cors1;
const char *cors2;
const char *cors3;
if ( conn == NULL || path == NULL || filep == NULL ) return;
curtime = time( NULL );
if (mg_get_header(conn, "Origin")) {
/* Cross-origin resource sharing (CORS). */
cors1 = "Access-Control-Allow-Origin: ";
cors2 = conn->ctx->config[ACCESS_CONTROL_ALLOW_ORIGIN];
cors3 = "\r\n";
} else {
cors1 = "";
cors2 = "";
cors3 = "";
}
if (!XX_httplib_fopen(conn, path, "rb", filep)) {
/* File exists (precondition for calling this function),
* but can not be opened by the server. */
XX_httplib_send_http_error(conn, 500, "Error: Cannot read file\nfopen(%s): %s", path, strerror(ERRNO));
} else {
conn->must_close = 1;
XX_httplib_gmt_time_string(date, sizeof(date), &curtime);
fclose_on_exec(filep, conn);
mg_printf(conn, "HTTP/1.1 200 OK\r\n");
send_no_cache_header(conn);
mg_printf(conn,
"%s%s%s"
"Date: %s\r\n"
"Content-Type: text/html\r\n"
"Connection: %s\r\n\r\n",
cors1,
cors2,
cors3,
date,
XX_httplib_suggest_connection_header(conn));
send_ssi_file(conn, path, filep, 0);
XX_httplib_fclose(filep);
}
} /* XX_httplib_handle_ssi_file_request */