mirror of
https://github.com/lammertb/libhttp.git
synced 2026-01-27 08:02:47 +03:00
Moved log_access to own file
This commit is contained in:
1
Makefile
1
Makefile
@@ -60,6 +60,7 @@ LIB_SOURCES = src/libhttp.c \
|
||||
src/httplib_getreq.c \
|
||||
src/httplib_initialize_ssl.c \
|
||||
src/httplib_load_dll.c \
|
||||
src/httplib_log_access.c \
|
||||
src/httplib_master_thread.c \
|
||||
src/httplib_process_new_connection.c \
|
||||
src/httplib_produce_socket.c \
|
||||
|
||||
@@ -20,35 +20,27 @@
|
||||
*/
|
||||
|
||||
|
||||
static int
|
||||
url_encoded_field_found(const struct mg_connection *conn,
|
||||
static int url_encoded_field_found(const struct mg_connection *conn,
|
||||
const char *key,
|
||||
size_t key_len,
|
||||
const char *filename,
|
||||
size_t filename_len,
|
||||
char *path,
|
||||
size_t path_len,
|
||||
struct mg_form_data_handler *fdh)
|
||||
{
|
||||
struct mg_form_data_handler *fdh) {
|
||||
|
||||
char key_dec[1024];
|
||||
char filename_dec[1024];
|
||||
int key_dec_len;
|
||||
int filename_dec_len;
|
||||
int ret;
|
||||
|
||||
key_dec_len =
|
||||
mg_url_decode(key, (int)key_len, key_dec, (int)sizeof(key_dec), 1);
|
||||
key_dec_len = mg_url_decode(key, (int)key_len, key_dec, (int)sizeof(key_dec), 1);
|
||||
|
||||
if (((size_t)key_dec_len >= (size_t)sizeof(key_dec)) || (key_dec_len < 0)) {
|
||||
return FORM_FIELD_STORAGE_SKIP;
|
||||
}
|
||||
if (((size_t)key_dec_len >= (size_t)sizeof(key_dec)) || (key_dec_len < 0)) return FORM_FIELD_STORAGE_SKIP;
|
||||
|
||||
if (filename) {
|
||||
filename_dec_len = mg_url_decode(filename,
|
||||
(int)filename_len,
|
||||
filename_dec,
|
||||
(int)sizeof(filename_dec),
|
||||
1);
|
||||
filename_dec_len = mg_url_decode(filename, (int)filename_len, filename_dec, (int)sizeof(filename_dec), 1);
|
||||
|
||||
if (((size_t)filename_dec_len >= (size_t)sizeof(filename_dec))
|
||||
|| (filename_dec_len < 0)) {
|
||||
@@ -56,9 +48,8 @@ url_encoded_field_found(const struct mg_connection *conn,
|
||||
mg_cry(conn, "%s: Cannot decode filename", __func__);
|
||||
return FORM_FIELD_STORAGE_SKIP;
|
||||
}
|
||||
} else {
|
||||
filename_dec[0] = 0;
|
||||
}
|
||||
|
||||
} else filename_dec[0] = 0;
|
||||
|
||||
ret =
|
||||
fdh->field_found(key_dec, filename_dec, path, path_len, fdh->user_data);
|
||||
@@ -80,14 +71,13 @@ url_encoded_field_found(const struct mg_connection *conn,
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
url_encoded_field_get(const struct mg_connection *conn,
|
||||
static int url_encoded_field_get(const struct mg_connection *conn,
|
||||
const char *key,
|
||||
size_t key_len,
|
||||
const char *value,
|
||||
size_t value_len,
|
||||
struct mg_form_data_handler *fdh)
|
||||
{
|
||||
struct mg_form_data_handler *fdh) {
|
||||
|
||||
char key_dec[1024];
|
||||
|
||||
char *value_dec = XX_httplib_malloc(value_len + 1);
|
||||
@@ -95,23 +85,15 @@ url_encoded_field_get(const struct mg_connection *conn,
|
||||
|
||||
if (!value_dec) {
|
||||
/* Log error message and stop parsing the form data. */
|
||||
mg_cry(conn,
|
||||
"%s: Not enough memory (required: %lu)",
|
||||
__func__,
|
||||
(unsigned long)(value_len + 1));
|
||||
mg_cry(conn, "%s: Not enough memory (required: %lu)", __func__, (unsigned long)(value_len + 1));
|
||||
return FORM_FIELD_STORAGE_ABORT;
|
||||
}
|
||||
|
||||
mg_url_decode(key, (int)key_len, key_dec, (int)sizeof(key_dec), 1);
|
||||
|
||||
value_dec_len =
|
||||
mg_url_decode(value, (int)value_len, value_dec, (int)value_len + 1, 1);
|
||||
|
||||
ret = fdh->field_get(key_dec,
|
||||
value_dec,
|
||||
(size_t)value_dec_len,
|
||||
fdh->user_data);
|
||||
value_dec_len = mg_url_decode(value, (int)value_len, value_dec, (int)value_len + 1, 1);
|
||||
|
||||
ret = fdh->field_get(key_dec, value_dec, (size_t)value_dec_len, fdh->user_data);
|
||||
XX_httplib_free(value_dec);
|
||||
|
||||
return ret;
|
||||
@@ -124,8 +106,8 @@ unencoded_field_get(const struct mg_connection *conn,
|
||||
size_t key_len,
|
||||
const char *value,
|
||||
size_t value_len,
|
||||
struct mg_form_data_handler *fdh)
|
||||
{
|
||||
struct mg_form_data_handler *fdh) {
|
||||
|
||||
char key_dec[1024];
|
||||
(void)conn;
|
||||
|
||||
@@ -135,12 +117,8 @@ unencoded_field_get(const struct mg_connection *conn,
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
field_stored(const struct mg_connection *conn,
|
||||
const char *path,
|
||||
long long file_size,
|
||||
struct mg_form_data_handler *fdh)
|
||||
{
|
||||
static int field_stored(const struct mg_connection *conn, const char *path, long long file_size, struct mg_form_data_handler *fdh) {
|
||||
|
||||
/* Equivalent to "upload" callback of "mg_upload". */
|
||||
|
||||
(void)conn; /* we do not need mg_cry here, so conn is currently unused */
|
||||
@@ -149,12 +127,8 @@ field_stored(const struct mg_connection *conn,
|
||||
}
|
||||
|
||||
|
||||
static const char *
|
||||
search_boundary(const char *buf,
|
||||
size_t buf_len,
|
||||
const char *boundary,
|
||||
size_t boundary_len)
|
||||
{
|
||||
static const char * search_boundary(const char *buf, size_t buf_len, const char *boundary, size_t boundary_len) {
|
||||
|
||||
/* We must do a binary search here, not a string search, since the buffer
|
||||
* may contain '\x00' bytes, if binary data is transferred. */
|
||||
int clen = (int)buf_len - (int)boundary_len - 4;
|
||||
@@ -171,10 +145,8 @@ search_boundary(const char *buf,
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
mg_handle_form_request(struct mg_connection *conn,
|
||||
struct mg_form_data_handler *fdh)
|
||||
{
|
||||
int mg_handle_form_request(struct mg_connection *conn, struct mg_form_data_handler *fdh) {
|
||||
|
||||
const char *content_type;
|
||||
char path[512];
|
||||
char buf[1024];
|
||||
@@ -186,8 +158,7 @@ mg_handle_form_request(struct mg_connection *conn,
|
||||
int64_t file_size = 0; /* init here, to a avoid a false positive
|
||||
"uninitialized variable used" warning */
|
||||
|
||||
int has_body_data =
|
||||
(conn->request_info.content_length > 0) || (conn->is_chunked);
|
||||
int has_body_data = (conn->request_info.content_length > 0) || (conn->is_chunked);
|
||||
|
||||
/* There are three ways to encode data from a HTML form:
|
||||
* 1) method: GET (default)
|
||||
@@ -243,14 +214,7 @@ mg_handle_form_request(struct mg_connection *conn,
|
||||
*/
|
||||
memset(path, 0, sizeof(path));
|
||||
field_count++;
|
||||
field_storage = url_encoded_field_found(conn,
|
||||
data,
|
||||
(size_t)keylen,
|
||||
NULL,
|
||||
0,
|
||||
path,
|
||||
sizeof(path) - 1,
|
||||
fdh);
|
||||
field_storage = url_encoded_field_found(conn, data, (size_t)keylen, NULL, 0, path, sizeof(path) - 1, fdh);
|
||||
|
||||
val++;
|
||||
next = strchr(val, '&');
|
||||
@@ -269,18 +233,13 @@ mg_handle_form_request(struct mg_connection *conn,
|
||||
}
|
||||
if (field_storage == FORM_FIELD_STORAGE_STORE) {
|
||||
/* Store the content to a file */
|
||||
if (mg_fopen(conn, path, "wb", &fstore) == 0) {
|
||||
fstore.fp = NULL;
|
||||
}
|
||||
if (XX_httplib_fopen(conn, path, "wb", &fstore) == 0) fstore.fp = NULL;
|
||||
file_size = 0;
|
||||
if (fstore.fp != NULL) {
|
||||
size_t n =
|
||||
(size_t)fwrite(val, 1, (size_t)vallen, fstore.fp);
|
||||
if ((n != (size_t)vallen) || (ferror(fstore.fp))) {
|
||||
mg_cry(conn,
|
||||
"%s: Cannot write file %s",
|
||||
__func__,
|
||||
path);
|
||||
mg_cry(conn, "%s: Cannot write file %s", __func__, path);
|
||||
fclose(fstore.fp);
|
||||
fstore.fp = NULL;
|
||||
remove_bad_file(conn, path);
|
||||
@@ -293,18 +252,13 @@ mg_handle_form_request(struct mg_connection *conn,
|
||||
/* stored successfully */
|
||||
field_stored(conn, path, file_size, fdh);
|
||||
} else {
|
||||
mg_cry(conn,
|
||||
"%s: Error saving file %s",
|
||||
__func__,
|
||||
path);
|
||||
mg_cry(conn, "%s: Error saving file %s", __func__, path);
|
||||
remove_bad_file(conn, path);
|
||||
}
|
||||
fstore.fp = NULL;
|
||||
}
|
||||
|
||||
} else {
|
||||
mg_cry(conn, "%s: Cannot create file %s", __func__, path);
|
||||
}
|
||||
} else mg_cry(conn, "%s: Cannot create file %s", __func__, path);
|
||||
}
|
||||
|
||||
/* if (field_storage == FORM_FIELD_STORAGE_READ) { */
|
||||
@@ -320,8 +274,7 @@ mg_handle_form_request(struct mg_connection *conn,
|
||||
*/
|
||||
/* } */
|
||||
|
||||
if ((field_storage & FORM_FIELD_STORAGE_ABORT)
|
||||
== FORM_FIELD_STORAGE_ABORT) {
|
||||
if ((field_storage & FORM_FIELD_STORAGE_ABORT) == FORM_FIELD_STORAGE_ABORT) {
|
||||
/* Stop parsing the request */
|
||||
break;
|
||||
}
|
||||
@@ -373,9 +326,7 @@ mg_handle_form_request(struct mg_connection *conn,
|
||||
}
|
||||
buf_fill += r;
|
||||
buf[buf_fill] = 0;
|
||||
if (buf_fill < 1) {
|
||||
break;
|
||||
}
|
||||
if (buf_fill < 1) break;
|
||||
}
|
||||
|
||||
val = strchr(buf, '=');
|
||||
@@ -389,14 +340,7 @@ mg_handle_form_request(struct mg_connection *conn,
|
||||
/* Call callback */
|
||||
memset(path, 0, sizeof(path));
|
||||
field_count++;
|
||||
field_storage = url_encoded_field_found(conn,
|
||||
buf,
|
||||
(size_t)keylen,
|
||||
NULL,
|
||||
0,
|
||||
path,
|
||||
sizeof(path) - 1,
|
||||
fdh);
|
||||
field_storage = url_encoded_field_found(conn, buf, (size_t)keylen, NULL, 0, path, sizeof(path) - 1, fdh);
|
||||
|
||||
if ((field_storage & FORM_FIELD_STORAGE_ABORT)
|
||||
== FORM_FIELD_STORAGE_ABORT) {
|
||||
@@ -405,13 +349,9 @@ mg_handle_form_request(struct mg_connection *conn,
|
||||
}
|
||||
|
||||
if (field_storage == FORM_FIELD_STORAGE_STORE) {
|
||||
if (mg_fopen(conn, path, "wb", &fstore) == 0) {
|
||||
fstore.fp = NULL;
|
||||
}
|
||||
if (XX_httplib_fopen(conn, path, "wb", &fstore) == 0) fstore.fp = NULL;
|
||||
file_size = 0;
|
||||
if (!fstore.fp) {
|
||||
mg_cry(conn, "%s: Cannot create file %s", __func__, path);
|
||||
}
|
||||
if (!fstore.fp) mg_cry(conn, "%s: Cannot create file %s", __func__, path);
|
||||
}
|
||||
|
||||
get_block = 0;
|
||||
@@ -447,13 +387,9 @@ mg_handle_form_request(struct mg_connection *conn,
|
||||
get_block++;
|
||||
}
|
||||
if (fstore.fp) {
|
||||
size_t n =
|
||||
(size_t)fwrite(val, 1, (size_t)vallen, fstore.fp);
|
||||
size_t n = (size_t)fwrite(val, 1, (size_t)vallen, fstore.fp);
|
||||
if ((n != (size_t)vallen) || (ferror(fstore.fp))) {
|
||||
mg_cry(conn,
|
||||
"%s: Cannot write file %s",
|
||||
__func__,
|
||||
path);
|
||||
mg_cry(conn, "%s: Cannot write file %s", __func__, path);
|
||||
fclose(fstore.fp);
|
||||
fstore.fp = NULL;
|
||||
remove_bad_file(conn, path);
|
||||
@@ -463,9 +399,7 @@ mg_handle_form_request(struct mg_connection *conn,
|
||||
|
||||
if (!end_of_key_value_pair_found) {
|
||||
used = next - buf;
|
||||
memmove(buf,
|
||||
buf + (size_t)used,
|
||||
sizeof(buf) - (size_t)used);
|
||||
memmove(buf, buf + (size_t)used, sizeof(buf) - (size_t)used);
|
||||
buf_fill -= (int)used;
|
||||
if ((size_t)buf_fill < (sizeof(buf) - 1)) {
|
||||
|
||||
@@ -485,9 +419,7 @@ mg_handle_form_request(struct mg_connection *conn,
|
||||
}
|
||||
buf_fill += r;
|
||||
buf[buf_fill] = 0;
|
||||
if (buf_fill < 1) {
|
||||
break;
|
||||
}
|
||||
if (buf_fill < 1) break;
|
||||
val = buf;
|
||||
}
|
||||
}
|
||||
@@ -523,7 +455,12 @@ mg_handle_form_request(struct mg_connection *conn,
|
||||
size_t bl;
|
||||
ptrdiff_t used;
|
||||
struct mg_request_info part_header;
|
||||
char *hbuf, *hend, *fbeg, *fend, *nbeg, *nend;
|
||||
char *hbuf;
|
||||
char *hend;
|
||||
char *fbeg;
|
||||
char *fend;
|
||||
char *nbeg;
|
||||
char *nend;
|
||||
const char *content_disp;
|
||||
const char *next;
|
||||
|
||||
@@ -531,9 +468,7 @@ mg_handle_form_request(struct mg_connection *conn,
|
||||
|
||||
/* Skip all spaces between MULTIPART/FORM-DATA; and BOUNDARY= */
|
||||
bl = 20;
|
||||
while (content_type[bl] == ' ') {
|
||||
bl++;
|
||||
}
|
||||
while (content_type[bl] == ' ') bl++;
|
||||
|
||||
/* There has to be a BOUNDARY definition in the Content-Type header */
|
||||
if (mg_strncasecmp(content_type + bl, "BOUNDARY=", 9)) {
|
||||
@@ -560,9 +495,7 @@ mg_handle_form_request(struct mg_connection *conn,
|
||||
size_t towrite, n;
|
||||
int get_block;
|
||||
|
||||
r = mg_read(conn,
|
||||
buf + (size_t)buf_fill,
|
||||
sizeof(buf) - 1 - (size_t)buf_fill);
|
||||
r = mg_read(conn, buf + (size_t)buf_fill, sizeof(buf) - 1 - (size_t)buf_fill);
|
||||
if (r < 0) {
|
||||
/* read error */
|
||||
return -1;
|
||||
@@ -648,38 +581,22 @@ mg_handle_form_request(struct mg_connection *conn,
|
||||
/* TODO: check Content-Type */
|
||||
/* Content-Type: application/octet-stream */
|
||||
|
||||
} else {
|
||||
fend = fbeg;
|
||||
}
|
||||
} else fend = fbeg;
|
||||
|
||||
memset(path, 0, sizeof(path));
|
||||
field_count++;
|
||||
field_storage = url_encoded_field_found(conn,
|
||||
nbeg,
|
||||
(size_t)(nend - nbeg),
|
||||
fbeg,
|
||||
(size_t)(fend - fbeg),
|
||||
path,
|
||||
sizeof(path) - 1,
|
||||
fdh);
|
||||
field_storage = url_encoded_field_found(conn, nbeg, (size_t)(nend - nbeg), fbeg, (size_t)(fend - fbeg), path, sizeof(path) - 1, fdh);
|
||||
|
||||
/* If the boundary is already in the buffer, get the address,
|
||||
* otherwise next will be NULL. */
|
||||
next = search_boundary(hbuf,
|
||||
(size_t)((buf - hbuf) + buf_fill),
|
||||
boundary,
|
||||
bl);
|
||||
next = search_boundary(hbuf, (size_t)((buf - hbuf) + buf_fill), boundary, bl);
|
||||
|
||||
if (field_storage == FORM_FIELD_STORAGE_STORE) {
|
||||
/* Store the content to a file */
|
||||
if (mg_fopen(conn, path, "wb", &fstore) == 0) {
|
||||
fstore.fp = NULL;
|
||||
}
|
||||
if (XX_httplib_fopen(conn, path, "wb", &fstore) == 0) fstore.fp = NULL;
|
||||
file_size = 0;
|
||||
|
||||
if (!fstore.fp) {
|
||||
mg_cry(conn, "%s: Cannot create file %s", __func__, path);
|
||||
}
|
||||
if (!fstore.fp) mg_cry(conn, "%s: Cannot create file %s", __func__, path);
|
||||
}
|
||||
|
||||
get_block = 0;
|
||||
@@ -710,10 +627,7 @@ mg_handle_form_request(struct mg_connection *conn,
|
||||
/* Store the content of the buffer. */
|
||||
n = (size_t)fwrite(hend, 1, towrite, fstore.fp);
|
||||
if ((n != towrite) || (ferror(fstore.fp))) {
|
||||
mg_cry(conn,
|
||||
"%s: Cannot write file %s",
|
||||
__func__,
|
||||
path);
|
||||
mg_cry(conn, "%s: Cannot write file %s", __func__, path);
|
||||
fclose(fstore.fp);
|
||||
fstore.fp = NULL;
|
||||
remove_bad_file(conn, path);
|
||||
@@ -727,9 +641,7 @@ mg_handle_form_request(struct mg_connection *conn,
|
||||
hend = buf;
|
||||
|
||||
/* Read new data */
|
||||
r = mg_read(conn,
|
||||
buf + (size_t)buf_fill,
|
||||
sizeof(buf) - 1 - (size_t)buf_fill);
|
||||
r = mg_read(conn, buf + (size_t)buf_fill, sizeof(buf) - 1 - (size_t)buf_fill);
|
||||
if (r < 0) {
|
||||
/* read error */
|
||||
return -1;
|
||||
@@ -763,10 +675,7 @@ mg_handle_form_request(struct mg_connection *conn,
|
||||
if (fstore.fp) {
|
||||
n = (size_t)fwrite(hend, 1, towrite, fstore.fp);
|
||||
if ((n != towrite) || (ferror(fstore.fp))) {
|
||||
mg_cry(conn,
|
||||
"%s: Cannot write file %s",
|
||||
__func__,
|
||||
path);
|
||||
mg_cry(conn, "%s: Cannot write file %s", __func__, path);
|
||||
fclose(fstore.fp);
|
||||
fstore.fp = NULL;
|
||||
remove_bad_file(conn, path);
|
||||
@@ -783,10 +692,7 @@ mg_handle_form_request(struct mg_connection *conn,
|
||||
/* stored successfully */
|
||||
field_stored(conn, path, file_size, fdh);
|
||||
} else {
|
||||
mg_cry(conn,
|
||||
"%s: Error saving file %s",
|
||||
__func__,
|
||||
path);
|
||||
mg_cry(conn, "%s: Error saving file %s", __func__, path);
|
||||
remove_bad_file(conn, path);
|
||||
}
|
||||
fstore.fp = NULL;
|
||||
|
||||
124
src/httplib_log_access.c
Normal file
124
src/httplib_log_access.c
Normal file
@@ -0,0 +1,124 @@
|
||||
/*
|
||||
* 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 const char *header_val( const struct mg_connection *conn, const char *header );
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* void XX_httplib_log_access( const struct mg_connection *conn );
|
||||
*
|
||||
* The function XX_httplib_log_access() logs an access of a client.
|
||||
*/
|
||||
|
||||
void XX_httplib_log_access( const struct mg_connection *conn ) {
|
||||
|
||||
const struct mg_request_info *ri;
|
||||
struct file fi;
|
||||
char date[64];
|
||||
char src_addr[IP_ADDR_STR_LEN];
|
||||
struct tm *tm;
|
||||
|
||||
const char *referer;
|
||||
const char *user_agent;
|
||||
|
||||
char buf[4096];
|
||||
|
||||
if (!conn || !conn->ctx) return;
|
||||
|
||||
if (conn->ctx->config[ACCESS_LOG_FILE] != NULL) {
|
||||
if (XX_httplib_fopen(conn, conn->ctx->config[ACCESS_LOG_FILE], "a+", &fi) == 0) fi.fp = NULL;
|
||||
} else fi.fp = NULL;
|
||||
|
||||
/* Log is written to a file and/or a callback. If both are not set,
|
||||
* executing the rest of the function is pointless. */
|
||||
if ((fi.fp == NULL) && (conn->ctx->callbacks.log_access == NULL)) return;
|
||||
|
||||
tm = localtime(&conn->conn_birth_time);
|
||||
if (tm != NULL) {
|
||||
strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S %z", tm);
|
||||
} else {
|
||||
XX_httplib_strlcpy(date, "01/Jan/1970:00:00:00 +0000", sizeof(date));
|
||||
date[sizeof(date) - 1] = '\0';
|
||||
}
|
||||
|
||||
ri = &conn->request_info;
|
||||
|
||||
XX_httplib_sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
|
||||
referer = header_val(conn, "Referer");
|
||||
user_agent = header_val(conn, "User-Agent");
|
||||
|
||||
XX_httplib_snprintf(conn,
|
||||
NULL, /* Ignore truncation in access log */
|
||||
buf,
|
||||
sizeof(buf),
|
||||
"%s - %s [%s] \"%s %s%s%s HTTP/%s\" %d %" INT64_FMT " %s %s",
|
||||
src_addr,
|
||||
(ri->remote_user == NULL) ? "-" : ri->remote_user,
|
||||
date,
|
||||
ri->request_method ? ri->request_method : "-",
|
||||
ri->request_uri ? ri->request_uri : "-",
|
||||
ri->query_string ? "?" : "",
|
||||
ri->query_string ? ri->query_string : "",
|
||||
ri->http_version,
|
||||
conn->status_code,
|
||||
conn->num_bytes_sent,
|
||||
referer,
|
||||
user_agent);
|
||||
|
||||
if (conn->ctx->callbacks.log_access) conn->ctx->callbacks.log_access(conn, buf);
|
||||
|
||||
if (fi.fp) {
|
||||
flockfile(fi.fp);
|
||||
fprintf(fi.fp, "%s\n", buf);
|
||||
fflush(fi.fp);
|
||||
funlockfile(fi.fp);
|
||||
XX_httplib_fclose(&fi);
|
||||
}
|
||||
|
||||
} /* XX_httplib_log_access */
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* static const char *header_val( const struct mg_connection *conn, const char *header );
|
||||
*
|
||||
* The function header_val() returns the value of a specific header of a
|
||||
* connection.
|
||||
*/
|
||||
|
||||
static const char *header_val( const struct mg_connection *conn, const char *header ) {
|
||||
|
||||
const char *header_value;
|
||||
|
||||
if ((header_value = mg_get_header(conn, header)) == NULL) return "-";
|
||||
else return header_value;
|
||||
|
||||
} /* header_val */
|
||||
@@ -840,6 +840,8 @@ int XX_httplib_connect_socket( struct mg_context *ctx, const char *host, int p
|
||||
int XX_httplib_consume_socket( struct mg_context *ctx, struct socket *sp, int thread_index );
|
||||
void XX_httplib_set_close_on_exec( SOCKET sock, struct mg_connection *conn );
|
||||
struct mg_connection * XX_httplib_fc( struct mg_context *ctx );
|
||||
void XX_httplib_fclose( struct file *filep );
|
||||
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 );
|
||||
const char * XX_httplib_get_header( const struct mg_request_info *ri, const char *name );
|
||||
int XX_httplib_get_option_index( const char *name );
|
||||
@@ -885,6 +887,7 @@ int XX_httplib_ssl_use_pem_file( struct mg_context *ctx, const char *pem );
|
||||
int XX_httplib_sslize( struct mg_connection *conn, SSL_CTX *s, int (*func)(SSL *) );
|
||||
int XX_httplib_stat( struct mg_connection *conn, const char *path, struct file *filep );
|
||||
char * XX_httplib_strdup( const char *str );
|
||||
void XX_httplib_strlcpy( register char *dst, register const char *src, size_t n );
|
||||
void XX_httplib_tls_dtor( void *key );
|
||||
void XX_httplib_uninitialize_ssl( struct mg_context *ctx );
|
||||
int XX_httplib_vprintf( struct mg_connection *conn, const char *fmt, va_list ap );
|
||||
|
||||
177
src/libhttp.c
177
src/libhttp.c
@@ -871,7 +871,7 @@ static int is_file_in_memory(const struct mg_connection *conn, const char *path,
|
||||
filep->membuf = conn->ctx->callbacks.open_file(conn, path, &size);
|
||||
if (filep->membuf != NULL) {
|
||||
/* NOTE: override filep->size only on success. Otherwise, it might
|
||||
* break constructs like if (!XX_httplib_stat() || !mg_fopen()) ... */
|
||||
* break constructs like if (!XX_httplib_stat() || !XX_httplib_fopen()) ... */
|
||||
filep->size = size;
|
||||
}
|
||||
}
|
||||
@@ -890,18 +890,18 @@ static bool is_file_opened( const struct file *filep ) {
|
||||
} /* is_file_opened */
|
||||
|
||||
|
||||
/* mg_fopen will open a file either in memory or on the disk.
|
||||
/* XX_httplib_fopen will open a file either in memory or on the disk.
|
||||
* The input parameter path is a string in UTF-8 encoding.
|
||||
* The input parameter mode is the same as for fopen.
|
||||
* Either fp or membuf will be set in the output struct filep.
|
||||
* The function returns 1 on success, 0 on error. */
|
||||
static int mg_fopen(const struct mg_connection *conn, const char *path, const char *mode, struct file *filep) {
|
||||
int XX_httplib_fopen( const struct mg_connection *conn, const char *path, const char *mode, struct file *filep ) {
|
||||
|
||||
struct stat st;
|
||||
|
||||
if (!filep) return 0;
|
||||
|
||||
/* TODO (high): mg_fopen should only open a file, while XX_httplib_stat should
|
||||
/* TODO (high): XX_httplib_fopen should only open a file, while XX_httplib_stat should
|
||||
* only get the file status. They should not work on different members of
|
||||
* the same structure (bad cohesion). */
|
||||
memset(filep, 0, sizeof(*filep));
|
||||
@@ -921,20 +921,24 @@ static int mg_fopen(const struct mg_connection *conn, const char *path, const ch
|
||||
}
|
||||
|
||||
return is_file_opened(filep);
|
||||
}
|
||||
|
||||
} /* XX_httplib_fopen */
|
||||
|
||||
|
||||
static void mg_fclose(struct file *filep) {
|
||||
|
||||
if (filep != NULL && filep->fp != NULL) { fclose(filep->fp); }
|
||||
}
|
||||
void XX_httplib_fclose( struct file *filep ) {
|
||||
|
||||
if (filep != NULL && filep->fp != NULL) fclose(filep->fp);
|
||||
|
||||
} /* XX_httplib_fclose */
|
||||
|
||||
|
||||
static void mg_strlcpy(register char *dst, register const char *src, size_t n) {
|
||||
void XX_httplib_strlcpy( register char *dst, register const char *src, size_t n ) {
|
||||
|
||||
for (; *src != '\0' && n > 1; n--) { *dst++ = *src++; }
|
||||
*dst = '\0';
|
||||
}
|
||||
|
||||
} /* XX_httplib_strlcpy */
|
||||
|
||||
|
||||
static int lowercase(const char *s) {
|
||||
@@ -973,7 +977,7 @@ static char * mg_strndup(const char *ptr, size_t len) {
|
||||
|
||||
char *p;
|
||||
|
||||
if ((p = (char *)XX_httplib_malloc(len + 1)) != NULL) mg_strlcpy(p, ptr, len + 1);
|
||||
if ((p = (char *)XX_httplib_malloc(len + 1)) != NULL) XX_httplib_strlcpy(p, ptr, len + 1);
|
||||
|
||||
return p;
|
||||
}
|
||||
@@ -1158,7 +1162,7 @@ static void gmt_time_string(char *buf, size_t buf_len, time_t *t) {
|
||||
if (tm != NULL) {
|
||||
strftime(buf, buf_len, "%a, %d %b %Y %H:%M:%S GMT", tm);
|
||||
} else {
|
||||
mg_strlcpy(buf, "Thu, 01 Jan 1970 00:00:00 GMT", buf_len);
|
||||
XX_httplib_strlcpy(buf, "Thu, 01 Jan 1970 00:00:00 GMT", buf_len);
|
||||
buf[buf_len - 1] = '\0';
|
||||
}
|
||||
}
|
||||
@@ -1198,7 +1202,7 @@ void mg_cry(const struct mg_connection *conn, const char *fmt, ...) {
|
||||
|| (conn->ctx->callbacks.log_message(conn, buf) == 0)) {
|
||||
|
||||
if (conn->ctx->config[ERROR_LOG_FILE] != NULL) {
|
||||
if (mg_fopen(conn, conn->ctx->config[ERROR_LOG_FILE], "a+", &fi)
|
||||
if (XX_httplib_fopen(conn, conn->ctx->config[ERROR_LOG_FILE], "a+", &fi)
|
||||
== 0) {
|
||||
fi.fp = NULL;
|
||||
}
|
||||
@@ -1225,7 +1229,7 @@ void mg_cry(const struct mg_connection *conn, const char *fmt, ...) {
|
||||
fputc('\n', fi.fp);
|
||||
fflush(fi.fp);
|
||||
funlockfile(fi.fp);
|
||||
mg_fclose(&fi);
|
||||
XX_httplib_fclose(&fi);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1915,7 +1919,7 @@ static void path_to_unicode(const struct mg_connection *conn, const char *path,
|
||||
DWORD err;
|
||||
int (*fcompare)(const wchar_t *, const wchar_t *) = mg_wcscasecmp;
|
||||
|
||||
mg_strlcpy(buf, path, sizeof(buf));
|
||||
XX_httplib_strlcpy(buf, path, sizeof(buf));
|
||||
change_slashes_to_backslashes(buf);
|
||||
|
||||
/* Convert to Unicode and back. If doubly-converted string does not
|
||||
@@ -1991,7 +1995,7 @@ int XX_httplib_stat( struct mg_connection *conn, const char *path, struct file *
|
||||
* memset */
|
||||
filep->last_modified = time(NULL);
|
||||
/* last_modified = now ... assumes the file may change during runtime,
|
||||
* so every mg_fopen call may return different data */
|
||||
* so every XX_httplib_fopen call may return different data */
|
||||
/* last_modified = conn->ctx.start_time;
|
||||
* May be used it the data does not change during runtime. This allows
|
||||
* browser caching. Since we do not know, we have to assume the file
|
||||
@@ -2346,10 +2350,10 @@ static pid_t spawn_process(struct mg_connection *conn, const char *prog, char *e
|
||||
goto spawn_cleanup;
|
||||
}
|
||||
|
||||
if (mg_fopen(conn, cmdline, "r", &file)) {
|
||||
if (XX_httplib_fopen(conn, cmdline, "r", &file)) {
|
||||
p = (char *)file.membuf;
|
||||
mg_fgets(buf, sizeof(buf), &file, &p);
|
||||
mg_fclose(&file);
|
||||
XX_httplib_fclose(&file);
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
}
|
||||
|
||||
@@ -3298,7 +3302,7 @@ int mg_get_cookie(const char *cookie_header, const char *var_name, char *dst, si
|
||||
}
|
||||
if ((size_t)(p - s) < dst_size) {
|
||||
len = (int)(p - s);
|
||||
mg_strlcpy(dst, s, (size_t)len + 1);
|
||||
XX_httplib_strlcpy(dst, s, (size_t)len + 1);
|
||||
} else len = -3;
|
||||
break;
|
||||
}
|
||||
@@ -3849,7 +3853,7 @@ static void open_auth_file(struct mg_connection *conn, const char *path, struct
|
||||
|
||||
if (gpass != NULL) {
|
||||
/* Use global passwords file */
|
||||
if (!mg_fopen(conn, gpass, "r", filep)) {
|
||||
if (!XX_httplib_fopen(conn, gpass, "r", filep)) {
|
||||
#ifdef DEBUG
|
||||
mg_cry(conn, "fopen(%s): %s", gpass, strerror(ERRNO));
|
||||
#endif
|
||||
@@ -3860,7 +3864,7 @@ static void open_auth_file(struct mg_connection *conn, const char *path, struct
|
||||
} else if (XX_httplib_stat(conn, path, &file) && file.is_directory) {
|
||||
XX_httplib_snprintf(conn, &truncated, name, sizeof(name), "%s/%s", path, PASSWORDS_FILE_NAME);
|
||||
|
||||
if (truncated || !mg_fopen(conn, name, "r", filep)) {
|
||||
if (truncated || !XX_httplib_fopen(conn, name, "r", filep)) {
|
||||
#ifdef DEBUG
|
||||
mg_cry(conn, "fopen(%s): %s", name, strerror(ERRNO));
|
||||
#endif
|
||||
@@ -3872,7 +3876,7 @@ static void open_auth_file(struct mg_connection *conn, const char *path, struct
|
||||
}
|
||||
XX_httplib_snprintf(conn, &truncated, name, sizeof(name), "%.*s/%s", (int)(e - p), p, PASSWORDS_FILE_NAME);
|
||||
|
||||
if (truncated || !mg_fopen(conn, name, "r", filep)) {
|
||||
if (truncated || !XX_httplib_fopen(conn, name, "r", filep)) {
|
||||
#ifdef DEBUG
|
||||
mg_cry(conn, "fopen(%s): %s", name, strerror(ERRNO));
|
||||
#endif
|
||||
@@ -3908,7 +3912,7 @@ static int parse_auth_header(struct mg_connection *conn, char *buf, size_t buf_s
|
||||
if ((auth_header = mg_get_header(conn, "Authorization")) == NULL || mg_strncasecmp(auth_header, "Digest ", 7) != 0) return 0;
|
||||
|
||||
/* Make modifiable copy of the auth header */
|
||||
mg_strlcpy(buf, auth_header + 7, buf_size);
|
||||
XX_httplib_strlcpy(buf, auth_header + 7, buf_size);
|
||||
s = buf;
|
||||
|
||||
/* Parse authorization header */
|
||||
@@ -4052,9 +4056,9 @@ static int read_auth_file(struct file *filep, struct read_auth_file_struct *work
|
||||
/* :# is a comment */
|
||||
continue;
|
||||
} else if (!strncmp(workdata->f_user + 1, "include=", 8)) {
|
||||
if (mg_fopen(workdata->conn, workdata->f_user + 9, "r", &fp)) {
|
||||
if (XX_httplib_fopen(workdata->conn, workdata->f_user + 9, "r", &fp)) {
|
||||
is_authorized = read_auth_file(&fp, workdata);
|
||||
mg_fclose(&fp);
|
||||
XX_httplib_fclose(&fp);
|
||||
} else {
|
||||
mg_cry(workdata->conn, "%s: cannot open authorization file: %s", __func__, workdata->buf);
|
||||
}
|
||||
@@ -4135,7 +4139,7 @@ static int check_authorization(struct mg_connection *conn, const char *path) {
|
||||
if (!memcmp(conn->request_info.local_uri, uri_vec.ptr, uri_vec.len)) {
|
||||
XX_httplib_snprintf(conn, &truncated, fname, sizeof(fname), "%.*s", (int)filename_vec.len, filename_vec.ptr);
|
||||
|
||||
if (truncated || !mg_fopen(conn, fname, "r", &file)) {
|
||||
if (truncated || !XX_httplib_fopen(conn, fname, "r", &file)) {
|
||||
mg_cry(conn, "%s: cannot open %s: %s", __func__, fname, strerror(errno));
|
||||
}
|
||||
break;
|
||||
@@ -4146,7 +4150,7 @@ static int check_authorization(struct mg_connection *conn, const char *path) {
|
||||
|
||||
if (is_file_opened(&file)) {
|
||||
authorized = authorize(conn, &file);
|
||||
mg_fclose(&file);
|
||||
XX_httplib_fclose(&file);
|
||||
}
|
||||
|
||||
return authorized;
|
||||
@@ -4199,9 +4203,9 @@ static int is_authorized_for_put(struct mg_connection *conn) {
|
||||
const char *passfile = conn->ctx->config[PUT_DELETE_PASSWORDS_FILE];
|
||||
int ret = 0;
|
||||
|
||||
if (passfile != NULL && mg_fopen(conn, passfile, "r", &file)) {
|
||||
if (passfile != NULL && XX_httplib_fopen(conn, passfile, "r", &file)) {
|
||||
ret = authorize(conn, &file);
|
||||
mg_fclose(&file);
|
||||
XX_httplib_fclose(&file);
|
||||
}
|
||||
|
||||
return ret;
|
||||
@@ -4492,7 +4496,7 @@ static void print_dir_entry(struct de *de) {
|
||||
if (tm != NULL) {
|
||||
strftime(mod, sizeof(mod), "%d-%b-%Y %H:%M", tm);
|
||||
} else {
|
||||
mg_strlcpy(mod, "01-Jan-1970 00:00", sizeof(mod));
|
||||
XX_httplib_strlcpy(mod, "01-Jan-1970 00:00", sizeof(mod));
|
||||
mod[sizeof(mod) - 1] = '\0';
|
||||
}
|
||||
mg_url_encode(de->file_name, href, sizeof(href));
|
||||
@@ -4932,7 +4936,7 @@ static void handle_static_file_request(struct mg_connection *conn, const char *p
|
||||
encoding = "Content-Encoding: gzip\r\n";
|
||||
}
|
||||
|
||||
if (!mg_fopen(conn, path, "rb", filep)) {
|
||||
if (!XX_httplib_fopen(conn, path, "rb", filep)) {
|
||||
XX_httplib_send_http_error(conn, 500, "Error: Cannot open file\nfopen(%s): %s", path, strerror(ERRNO));
|
||||
return;
|
||||
}
|
||||
@@ -4947,7 +4951,7 @@ static void handle_static_file_request(struct mg_connection *conn, const char *p
|
||||
/* actually, range requests don't play well with a pre-gzipped
|
||||
* file (since the range is specified in the uncompressed space) */
|
||||
if (filep->gzipped) {
|
||||
XX_httplib_send_http_error( conn, 501, "%s", "Error: Range requests in gzipped files are not supported"); mg_fclose(filep);
|
||||
XX_httplib_send_http_error( conn, 501, "%s", "Error: Range requests in gzipped files are not supported"); XX_httplib_fclose(filep);
|
||||
return;
|
||||
}
|
||||
conn->status_code = 206;
|
||||
@@ -5010,7 +5014,7 @@ static void handle_static_file_request(struct mg_connection *conn, const char *p
|
||||
} else mg_printf(conn, "\r\n");
|
||||
|
||||
if (strcmp(conn->request_info.request_method, "HEAD") != 0) send_file_data(conn, filep, r1, cl);
|
||||
mg_fclose(filep);
|
||||
XX_httplib_fclose(filep);
|
||||
}
|
||||
|
||||
|
||||
@@ -5141,20 +5145,20 @@ long long mg_store_body( struct mg_connection *conn, const char *path ) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mg_fopen(conn, path, "w", &fi) == 0) return -12;
|
||||
if (XX_httplib_fopen(conn, path, "w", &fi) == 0) return -12;
|
||||
|
||||
ret = mg_read(conn, buf, sizeof(buf));
|
||||
while (ret > 0) {
|
||||
n = (int)fwrite(buf, 1, (size_t)ret, fi.fp);
|
||||
if (n != ret) {
|
||||
mg_fclose(&fi);
|
||||
XX_httplib_fclose(&fi);
|
||||
remove_bad_file(conn, path);
|
||||
return -13;
|
||||
}
|
||||
ret = mg_read(conn, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
/* TODO: mg_fclose should return an error,
|
||||
/* TODO: XX_httplib_fclose should return an error,
|
||||
* and every caller should check and handle it. */
|
||||
if (fclose(fi.fp) != 0) {
|
||||
remove_bad_file(conn, path);
|
||||
@@ -5381,7 +5385,7 @@ static int substitute_index_file(struct mg_connection *conn, char *path, size_t
|
||||
if (filename_vec.len > path_len - (n + 2)) continue;
|
||||
|
||||
/* Prepare full path to the index file */
|
||||
mg_strlcpy(path + n + 1, filename_vec.ptr, filename_vec.len + 1);
|
||||
XX_httplib_strlcpy(path + n + 1, filename_vec.ptr, filename_vec.len + 1);
|
||||
|
||||
/* Does it exist? */
|
||||
if (XX_httplib_stat(conn, path, &file)) {
|
||||
@@ -6060,8 +6064,8 @@ static void put_file(struct mg_connection *conn, const char *path) {
|
||||
}
|
||||
|
||||
/* A file should be created or overwritten. */
|
||||
if (!mg_fopen(conn, path, "wb+", &file) || file.fp == NULL) {
|
||||
mg_fclose(&file);
|
||||
if (!XX_httplib_fopen(conn, path, "wb+", &file) || file.fp == NULL) {
|
||||
XX_httplib_fclose(&file);
|
||||
XX_httplib_send_http_error(conn, 500, "Error: Can not create file\nfopen(%s): %s", path, strerror(ERRNO));
|
||||
return;
|
||||
}
|
||||
@@ -6078,7 +6082,7 @@ static void put_file(struct mg_connection *conn, const char *path) {
|
||||
/* forward_body_data failed.
|
||||
* The error code has already been sent to the client,
|
||||
* and conn->status_code is already set. */
|
||||
mg_fclose(&file);
|
||||
XX_httplib_fclose(&file);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -6087,7 +6091,7 @@ static void put_file(struct mg_connection *conn, const char *path) {
|
||||
send_no_cache_header(conn);
|
||||
mg_printf(conn, "Date: %s\r\n" "Content-Length: 0\r\n" "Connection: %s\r\n\r\n", date, suggest_connection_header(conn));
|
||||
|
||||
mg_fclose(&file);
|
||||
XX_httplib_fclose(&file);
|
||||
}
|
||||
|
||||
|
||||
@@ -6189,7 +6193,7 @@ static void do_ssi_include(struct mg_connection *conn, const char *ssi, char *ta
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mg_fopen(conn, path, "rb", &file)) {
|
||||
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);
|
||||
@@ -6200,7 +6204,7 @@ static void do_ssi_include(struct mg_connection *conn, const char *ssi, char *ta
|
||||
} else {
|
||||
send_file_data(conn, &file, 0, INT64_MAX);
|
||||
}
|
||||
mg_fclose(&file);
|
||||
XX_httplib_fclose(&file);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6327,7 +6331,7 @@ static void handle_ssi_file_request(struct mg_connection *conn, const char *path
|
||||
cors3 = "";
|
||||
}
|
||||
|
||||
if (!mg_fopen(conn, path, "rb", filep)) {
|
||||
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));
|
||||
@@ -6348,7 +6352,7 @@ static void handle_ssi_file_request(struct mg_connection *conn, const char *path
|
||||
date,
|
||||
suggest_connection_header(conn));
|
||||
send_ssi_file(conn, path, filep, 0);
|
||||
mg_fclose(filep);
|
||||
XX_httplib_fclose(filep);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7254,7 +7258,7 @@ static void redirect_to_https_port(struct mg_connection *conn, int ssl_index) {
|
||||
if (host_header != NULL) {
|
||||
char *pos;
|
||||
|
||||
mg_strlcpy(host, host_header, hostlen);
|
||||
XX_httplib_strlcpy(host, host_header, hostlen);
|
||||
host[hostlen - 1] = '\0';
|
||||
pos = strchr(host, ':');
|
||||
if (pos != NULL) *pos = '\0';
|
||||
@@ -8048,9 +8052,7 @@ int XX_httplib_set_ports_option( struct mg_context *ctx ) {
|
||||
int portsTotal = 0;
|
||||
int portsOk = 0;
|
||||
|
||||
if (!ctx) {
|
||||
return 0;
|
||||
}
|
||||
if ( ctx == NULL ) return 0;
|
||||
|
||||
memset(&so, 0, sizeof(so));
|
||||
memset(&usa, 0, sizeof(usa));
|
||||
@@ -8221,80 +8223,3 @@ int XX_httplib_set_ports_option( struct mg_context *ctx ) {
|
||||
return portsOk;
|
||||
|
||||
} /* XX_httplib_set_ports_option */
|
||||
|
||||
|
||||
static const char *header_val(const struct mg_connection *conn, const char *header) {
|
||||
|
||||
const char *header_value;
|
||||
|
||||
if ((header_value = mg_get_header(conn, header)) == NULL) return "-";
|
||||
else return header_value;
|
||||
}
|
||||
|
||||
|
||||
void XX_httplib_log_access( const struct mg_connection *conn ) {
|
||||
|
||||
const struct mg_request_info *ri;
|
||||
struct file fi;
|
||||
char date[64];
|
||||
char src_addr[IP_ADDR_STR_LEN];
|
||||
struct tm *tm;
|
||||
|
||||
const char *referer;
|
||||
const char *user_agent;
|
||||
|
||||
char buf[4096];
|
||||
|
||||
if (!conn || !conn->ctx) return;
|
||||
|
||||
if (conn->ctx->config[ACCESS_LOG_FILE] != NULL) {
|
||||
if (mg_fopen(conn, conn->ctx->config[ACCESS_LOG_FILE], "a+", &fi) == 0) fi.fp = NULL;
|
||||
} else fi.fp = NULL;
|
||||
|
||||
/* Log is written to a file and/or a callback. If both are not set,
|
||||
* executing the rest of the function is pointless. */
|
||||
if ((fi.fp == NULL) && (conn->ctx->callbacks.log_access == NULL)) return;
|
||||
|
||||
tm = localtime(&conn->conn_birth_time);
|
||||
if (tm != NULL) {
|
||||
strftime(date, sizeof(date), "%d/%b/%Y:%H:%M:%S %z", tm);
|
||||
} else {
|
||||
mg_strlcpy(date, "01/Jan/1970:00:00:00 +0000", sizeof(date));
|
||||
date[sizeof(date) - 1] = '\0';
|
||||
}
|
||||
|
||||
ri = &conn->request_info;
|
||||
|
||||
XX_httplib_sockaddr_to_string(src_addr, sizeof(src_addr), &conn->client.rsa);
|
||||
referer = header_val(conn, "Referer");
|
||||
user_agent = header_val(conn, "User-Agent");
|
||||
|
||||
XX_httplib_snprintf(conn,
|
||||
NULL, /* Ignore truncation in access log */
|
||||
buf,
|
||||
sizeof(buf),
|
||||
"%s - %s [%s] \"%s %s%s%s HTTP/%s\" %d %" INT64_FMT " %s %s",
|
||||
src_addr,
|
||||
(ri->remote_user == NULL) ? "-" : ri->remote_user,
|
||||
date,
|
||||
ri->request_method ? ri->request_method : "-",
|
||||
ri->request_uri ? ri->request_uri : "-",
|
||||
ri->query_string ? "?" : "",
|
||||
ri->query_string ? ri->query_string : "",
|
||||
ri->http_version,
|
||||
conn->status_code,
|
||||
conn->num_bytes_sent,
|
||||
referer,
|
||||
user_agent);
|
||||
|
||||
if (conn->ctx->callbacks.log_access) conn->ctx->callbacks.log_access(conn, buf);
|
||||
|
||||
if (fi.fp) {
|
||||
flockfile(fi.fp);
|
||||
fprintf(fi.fp, "%s\n", buf);
|
||||
fflush(fi.fp);
|
||||
funlockfile(fi.fp);
|
||||
mg_fclose(&fi);
|
||||
}
|
||||
|
||||
} /* XX_httplib_log_access */
|
||||
|
||||
Reference in New Issue
Block a user