output.c (goaccess-1.7.1) | : | output.c (goaccess-1.7.2) | ||
---|---|---|---|---|
skipping to change at line 40 | skipping to change at line 40 | |||
#define _LARGEFILE_SOURCE | #define _LARGEFILE_SOURCE | |||
#define _LARGEFILE64_SOURCE | #define _LARGEFILE64_SOURCE | |||
#define _FILE_OFFSET_BITS 64 | #define _FILE_OFFSET_BITS 64 | |||
#include <errno.h> | #include <errno.h> | |||
#include <ctype.h> | #include <ctype.h> | |||
#include <stdio.h> | #include <stdio.h> | |||
#include <stdlib.h> | #include <stdlib.h> | |||
#include <string.h> | #include <string.h> | |||
#include <libgen.h> | ||||
#include "output.h" | #include "output.h" | |||
#include "error.h" | #include "error.h" | |||
#include "gkhash.h" | #include "gkhash.h" | |||
#include "gwsocket.h" | #include "gwsocket.h" | |||
#include "json.h" | #include "json.h" | |||
#include "settings.h" | #include "settings.h" | |||
#include "ui.h" | #include "ui.h" | |||
#include "util.h" | #include "util.h" | |||
skipping to change at line 155 | skipping to change at line 156 | |||
{TLS_TYPE, 1, print_metrics, { | {TLS_TYPE, 1, print_metrics, { | |||
{CHART_VBAR, hits_visitors_plot, 0, 1, NULL, NULL}, | {CHART_VBAR, hits_visitors_plot, 0, 1, NULL, NULL}, | |||
{CHART_VBAR, hits_bw_plot, 0, 1, NULL, NULL}, | {CHART_VBAR, hits_bw_plot, 0, 1, NULL, NULL}, | |||
}}, | }}, | |||
}; | }; | |||
/* *INDENT-ON* */ | /* *INDENT-ON* */ | |||
/* number of new lines (applicable fields) */ | /* number of new lines (applicable fields) */ | |||
static int nlines = 0; | static int nlines = 0; | |||
static int external_assets = 0; | ||||
/* Get the chart type for the JSON definition. | /* Get the chart type for the JSON definition. | |||
* | * | |||
* On success, the chart type string is returned. */ | * On success, the chart type string is returned. */ | |||
static const char * | static const char * | |||
chart2str (GChartType type) { | chart2str (GChartType type) { | |||
static const char *strings[] = { "null", "bar", "area-spline" }; | static const char *strings[] = { "null", "bar", "area-spline" }; | |||
return strings[type]; | return strings[type]; | |||
} | } | |||
skipping to change at line 226 | skipping to change at line 228 | |||
/* Set the HTML document title and the generated date/time */ | /* Set the HTML document title and the generated date/time */ | |||
static void | static void | |||
print_html_title (FILE * fp) { | print_html_title (FILE * fp) { | |||
const char *title = conf.html_report_title ? conf.html_report_title : HTML_REP ORT_TITLE; | const char *title = conf.html_report_title ? conf.html_report_title : HTML_REP ORT_TITLE; | |||
fprintf (fp, "<title>"); | fprintf (fp, "<title>"); | |||
clean_output (fp, title); | clean_output (fp, title); | |||
fprintf (fp, "</title>"); | fprintf (fp, "</title>"); | |||
} | } | |||
static void | ||||
print_html_header_styles (FILE * fp, FILE * fcs) { | ||||
if (fcs) { | ||||
fprintf (fp, "<link rel='stylesheet' href='%s'>", FILENAME_CSS); | ||||
fprintf (fcs, "%.*s\n", fa_css_length, fa_css); | ||||
fprintf (fcs, "%.*s\n", bootstrap_css_length, bootstrap_css); | ||||
fprintf (fcs, "%.*s\n", app_css_length, app_css); | ||||
} else { | ||||
fprintf (fp, "<style>%.*s</style>", fa_css_length, fa_css); | ||||
fprintf (fp, "<style>%.*s</style>", bootstrap_css_length, bootstrap_css); | ||||
fprintf (fp, "<style>%.*s</style>", app_css_length, app_css); | ||||
} | ||||
} | ||||
/* *INDENT-OFF* */ | /* *INDENT-OFF* */ | |||
/* Output all the document head elements. */ | /* Output all the document head elements. */ | |||
static void | static void | |||
print_html_header (FILE * fp) | print_html_header (FILE * fp, FILE *fcs) | |||
{ | { | |||
fprintf (fp, | fprintf (fp, | |||
"<!DOCTYPE html>" | "<!DOCTYPE html>" | |||
"<html lang='%s'>" | "<html lang='%s'>" | |||
"<head>" | "<head>" | |||
"<meta charset='UTF-8'>" | "<meta charset='UTF-8'>" | |||
"<meta name='referrer' content='no-referrer'>" | "<meta name='referrer' content='no-referrer'>" | |||
"<meta http-equiv='X-UA-Compatible' content='IE=edge'>" | "<meta http-equiv='X-UA-Compatible' content='IE=edge'>" | |||
"<meta name='google' content='notranslate'>" | "<meta name='google' content='notranslate'>" | |||
"<meta name='viewport' content='width=device-width, initial-scale=1'>" | "<meta name='viewport' content='width=device-width, initial-scale=1'>" | |||
skipping to change at line 254 | skipping to change at line 270 | |||
"EBAQAAEABAAoAQAAFgAAACgAAAAQAAAAIAAAAAEABAAAAAAAgAAAAAAAAAAAAAAAEAAAA" | "EBAQAAEABAAoAQAAFgAAACgAAAAQAAAAIAAAAAEABAAAAAAAgAAAAAAAAAAAAAAAEAAAA" | |||
"AAAAADGxsYAWFhYABwcHABfAP8A/9dfAADXrwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" | "AAAAADGxsYAWFhYABwcHABfAP8A/9dfAADXrwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" | |||
"AAAAAAAAAAAAAAAAAAAAAAIiIiIiIiIiIjMlUkQgAiIiIiIiIiIiIiIzJVJEIAAAIiIiI" | "AAAAAAAAAAAAAAAAAAAAAAIiIiIiIiIiIjMlUkQgAiIiIiIiIiIiIiIzJVJEIAAAIiIiI" | |||
"iIiIiIiMyVSRCAAIiIiIiIiIiIiIRERERERERERERERERERERIiIiIiIiIiIgACVVUiIi" | "iIiIiIiMyVSRCAAIiIiIiIiIiIiIRERERERERERERERERERERIiIiIiIiIiIgACVVUiIi" | |||
"IiIiIiIiIiIiIAAlVVIiIiIiIiIiIiIiIhEREREREREREREREREREREAAAAAAAAAAAAAA" | "IiIiIiIiIiIiIAAlVVIiIiIiIiIiIiIiIhEREREREREREREREREREREAAAAAAAAAAAAAA" | |||
"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" | "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" | |||
"AA' type='image/x-icon' />"); | "AA' type='image/x-icon' />"); | |||
print_html_title (fp); | print_html_title (fp); | |||
fprintf (fp, "<style>%.*s</style>", fa_css_length, fa_css); | print_html_header_styles(fp, fcs); | |||
fprintf (fp, "<style>%.*s</style>", bootstrap_css_length, bootstrap_css); | ||||
fprintf (fp, "<style>%.*s</style>", app_css_length, app_css); | ||||
/* load custom CSS file, if any */ | /* load custom CSS file, if any */ | |||
if (conf.html_custom_css) | if (conf.html_custom_css) | |||
fprintf (fp, "<link rel='stylesheet' href='%s'>", conf.html_custom_css); | fprintf (fp, "<link rel='stylesheet' href='%s'>", conf.html_custom_css); | |||
fprintf (fp, | fprintf (fp, | |||
"</head>" | "</head>" | |||
"<body>"); | "<body>"); | |||
} | } | |||
/* Output all structural elements of the HTML document. */ | /* Output all structural elements of the HTML document. */ | |||
skipping to change at line 314 | skipping to change at line 329 | |||
"</div>" | "</div>" | |||
"<div class='wrap-panels'></div>" | "<div class='wrap-panels'></div>" | |||
"</div>", conf.html_report_title ? conf.html_report_title : ""); | "</div>", conf.html_report_title ? conf.html_report_title : ""); | |||
fprintf (fp, "%.*s", tpls_length, tpls); | fprintf (fp, "%.*s", tpls_length, tpls); | |||
} | } | |||
/* Output all the document footer elements such as script and closing | /* Output all the document footer elements such as script and closing | |||
* tags. */ | * tags. */ | |||
static void | static void | |||
print_html_footer (FILE * fp) | print_html_footer (FILE * fp, FILE *fjs) | |||
{ | { | |||
fprintf (fp, "<script>%.*s</script>", d3_js_length, d3_js); | if (fjs) { | |||
fprintf (fp, "<script>%.*s</script>", hogan_js_length, hogan_js); | fprintf (fp, "<script src='%s'></script>", FILENAME_JS); | |||
fprintf (fp, "<script>%.*s</script>", app_js_length, app_js); | fprintf (fjs, "%.*s", d3_js_length, d3_js); | |||
fprintf (fp, "<script>%.*s</script>", charts_js_length, charts_js); | fprintf (fjs, "%.*s", hogan_js_length, hogan_js); | |||
fprintf (fjs, "%.*s", app_js_length, app_js); | ||||
fprintf (fjs, "%.*s", charts_js_length, charts_js); | ||||
} else { | ||||
fprintf (fp, "<script>%.*s</script>", d3_js_length, d3_js); | ||||
fprintf (fp, "<script>%.*s</script>", hogan_js_length, hogan_js); | ||||
fprintf (fp, "<script>%.*s</script>", app_js_length, app_js); | ||||
fprintf (fp, "<script>%.*s</script>", charts_js_length, charts_js); | ||||
} | ||||
/* load custom JS file, if any */ | /* load custom JS file, if any */ | |||
if (conf.html_custom_js) | if (conf.html_custom_js) | |||
fprintf (fp, "<script src='%s'></script>", conf.html_custom_js); | fprintf (fp, "<script src='%s'></script>", conf.html_custom_js); | |||
fprintf (fp, "</body>"); | fprintf (fp, "</body>"); | |||
fprintf (fp, "</html>"); | fprintf (fp, "</html>"); | |||
} | } | |||
/* *INDENT-ON* */ | /* *INDENT-ON* */ | |||
skipping to change at line 490 | skipping to change at line 513 | |||
} | } | |||
/* Output JSON data definitions. */ | /* Output JSON data definitions. */ | |||
static void | static void | |||
print_json_data (FILE * fp, GHolder * holder) { | print_json_data (FILE * fp, GHolder * holder) { | |||
char *json = NULL; | char *json = NULL; | |||
if ((json = get_json (holder, 1)) == NULL) | if ((json = get_json (holder, 1)) == NULL) | |||
return; | return; | |||
fprintf (fp, "<script type='text/javascript'>"); | fprintf (fp, external_assets ? "" : "<script type='text/javascript'>"); | |||
fprintf (fp, "var json_data=%s", json); | fprintf (fp, "var json_data=%s", json); | |||
fprintf (fp, "</script>"); | fprintf (fp, external_assets ? "\n" : "</script>"); | |||
free (json); | free (json); | |||
} | } | |||
/* Output WebSocket connection definition. */ | /* Output WebSocket connection definition. */ | |||
static void | static void | |||
print_conn_def (FILE * fp) { | print_conn_def (FILE * fp) { | |||
int sp = 0; | int sp = 0; | |||
/* use tabs to prettify output */ | /* use tabs to prettify output */ | |||
if (conf.json_pretty_print) | if (conf.json_pretty_print) | |||
sp += 1; | sp += 1; | |||
if (!conf.real_time_html) | if (!conf.real_time_html) | |||
return; | return; | |||
fprintf (fp, "<script type='text/javascript'>"); | fprintf (fp, external_assets ? "" : "<script type='text/javascript'>"); | |||
fprintf (fp, "var connection = "); | ||||
fprintf (fp, "var connection = "); | ||||
fpopen_obj (fp, sp); | fpopen_obj (fp, sp); | |||
fpskeysval (fp, "url", (conf.ws_url ? conf.ws_url : ""), sp, 0); | fpskeysval (fp, "url", (conf.ws_url ? conf.ws_url : ""), sp, 0); | |||
fpskeyival (fp, "port", (conf.port ? atoi (conf.port) : 7890), sp, 0); | fpskeyival (fp, "port", (conf.port ? atoi (conf.port) : 7890), sp, 0); | |||
fpskeyival (fp, "ping_interval", (conf.ping_interval ? atoi (conf.ping_interva l) : 0), sp, | fpskeyival (fp, "ping_interval", (conf.ping_interval ? atoi (conf.ping_interva l) : 0), sp, | |||
1); | 1); | |||
fpclose_obj (fp, sp, 1); | fpclose_obj (fp, sp, 1); | |||
fprintf (fp, "</script>"); | fprintf (fp, external_assets ? "\n" : "</script>"); | |||
} | } | |||
/* Output JSON per panel metric definitions. */ | /* Output JSON per panel metric definitions. */ | |||
static void | static void | |||
print_def_metric (FILE * fp, const GDefMetric def, int sp) { | print_def_metric (FILE * fp, const GDefMetric def, int sp) { | |||
int isp = 0; | int isp = 0; | |||
/* use tabs to prettify output */ | /* use tabs to prettify output */ | |||
if (conf.json_pretty_print) | if (conf.json_pretty_print) | |||
isp = sp + 1; | isp = sp + 1; | |||
skipping to change at line 919 | skipping to change at line 942 | |||
print_def_data (FILE * fp, GModule module, int sp) { | print_def_data (FILE * fp, GModule module, int sp) { | |||
GDefMetric def = { | GDefMetric def = { | |||
.cname = "trunc", | .cname = "trunc", | |||
.cwidth = "100%", | .cwidth = "100%", | |||
.datakey = "data", | .datakey = "data", | |||
.datatype = module == VISITORS ? "date" : "string", | .datatype = module == VISITORS ? "date" : "string", | |||
.lbl = MTRC_DATA_LBL, | .lbl = MTRC_DATA_LBL, | |||
.metakey = "unique", | .metakey = "unique", | |||
.metalbl = "Total", | .metalbl = "Total", | |||
.metatype = "numeric", | .metatype = "numeric", | |||
.hlregex = "{" "\\\"^(\\\\\\\\d+|\\\\\\\\d+xx)(\\\\\\\\s.*)$\\\": \\\"<b>$1< | .hlregex = "{" "\\\"^(1\\\\\\\\d{2}|1xx)(\\\\\\\\s.*)$\\\": \\\"<b class='sp | |||
/b>$2\\\"," /* 2xx Success */ | an-hl lblu'>$1</b>$2\\\"," /* 2xx Success */ | |||
"\\\"^(2\\\\\\\\d{2}|2xx)(\\\\\\\\s.*)$\\\": \\\"<b class='span-hl lgrn'>$ | ||||
1</b>$2\\\"," /* 2xx Success */ | ||||
"\\\"^(3\\\\\\\\d{2}|3xx)(\\\\\\\\s.*)$\\\": \\\"<b class='span-hl lprp'>$ | ||||
1</b>$2\\\"," /* 3xx Success */ | ||||
"\\\"^(4\\\\\\\\d{2}|4xx)(\\\\\\\\s.*)$\\\": \\\"<b class='span-hl lyel'>$ | ||||
1</b>$2\\\"," /* 4xx Success */ | ||||
"\\\"^(5\\\\\\\\d{2}|5xx)(\\\\\\\\s.*)$\\\": \\\"<b class='span-hl lred'>$ | ||||
1</b>$2\\\"," /* 5xx Success */ | ||||
"\\\"^(AS\\\\\\\\d+)\\\": \\\"<b>$1</b>\\\"," /* AS9823 Google */ | "\\\"^(AS\\\\\\\\d+)\\\": \\\"<b>$1</b>\\\"," /* AS9823 Google */ | |||
"\\\"^(\\\\\\\\d+:)\\\": \\\"<b>$1</b>\\\"," /* 01234: Data */ | "\\\"^(\\\\\\\\d+:)\\\": \\\"<b>$1</b>\\\"," /* 01234: Data */ | |||
"\\\"(\\\\\\\\d+)|(:\\\\\\\\d+)|(:\\\\\\\\d+:\\\\\\\\d+)\\\": \\\"$1<b>$2< /b>\\\"," /* 12/May/2022:12:34 */ | "\\\"(\\\\\\\\d+)|(:\\\\\\\\d+)|(:\\\\\\\\d+:\\\\\\\\d+)\\\": \\\"$1<b>$2< /b>\\\"," /* 12/May/2022:12:34 */ | |||
"\\\"^([A-Z]{2})(\\\\\\\\s.*$)\\\": \\\"<b class='span-hl g5'>$1</b>$2\\\" " /* US United States */ | "\\\"^([A-Z]{2})(\\\\\\\\s.*$)\\\": \\\"<b class='span-hl g5'>$1</b>$2\\\" " /* US United States */ | |||
"}", | "}", | |||
}; | }; | |||
print_def_block (fp, def, sp, 1); | print_def_block (fp, def, sp, 1); | |||
} | } | |||
skipping to change at line 1194 | skipping to change at line 1221 | |||
/* output close panel attribute */ | /* output close panel attribute */ | |||
fpclose_obj (fp, sp, 0); | fpclose_obj (fp, sp, 0); | |||
} | } | |||
/* Entry point to output definitions for all panels. */ | /* Entry point to output definitions for all panels. */ | |||
static void | static void | |||
print_json_defs (FILE * fp) { | print_json_defs (FILE * fp) { | |||
const GHTML *def; | const GHTML *def; | |||
size_t idx = 0; | size_t idx = 0; | |||
fprintf (fp, "<script type='text/javascript'>"); | fprintf (fp, external_assets ? "" : "<script type='text/javascript'>"); | |||
fprintf (fp, "var json_i18n="); | fprintf (fp, "var json_i18n="); | |||
print_json_i18n_def (fp); | print_json_i18n_def (fp); | |||
fprintf (fp, ";"); | fprintf (fp, ";"); | |||
fprintf (fp, "var html_prefs=%s;", conf.html_prefs ? conf.html_prefs : "{}"); | fprintf (fp, "var html_prefs=%s;", conf.html_prefs ? conf.html_prefs : "{}"); | |||
fprintf (fp, "var user_interface="); | fprintf (fp, "var user_interface="); | |||
fpopen_obj (fp, 0); | fpopen_obj (fp, 0); | |||
print_json_def_summary (fp); | print_json_def_summary (fp); | |||
FOREACH_MODULE (idx, module_list) { | FOREACH_MODULE (idx, module_list) { | |||
if ((def = panel_lookup (module_list[idx]))) { | if ((def = panel_lookup (module_list[idx]))) { | |||
print_json_def (fp, def); | print_json_def (fp, def); | |||
} | } | |||
} | } | |||
fpclose_obj (fp, 0, 1); | fpclose_obj (fp, 0, 1); | |||
fprintf (fp, "</script>"); | fprintf (fp, external_assets ? "\n" : "</script>"); | |||
} | ||||
static char * | ||||
get_asset_filepath (const char *filename, const char *asset_fname) { | ||||
char *fname = NULL, *path = NULL, *s = NULL; | ||||
path = xstrdup (filename); | ||||
fname = xstrdup (basename (path)); | ||||
path[strlen (filename) - strlen (fname)] = '\0'; | ||||
s = xmalloc (snprintf (NULL, 0, "%s%s", path, asset_fname) + 1); | ||||
sprintf (s, "%s%s", path, asset_fname); | ||||
free (path); | ||||
free (fname); | ||||
return s; | ||||
} | ||||
static FILE * | ||||
get_asset (const char *filename, const char *asset_fname) { | ||||
FILE *fp = NULL; | ||||
char *fn = NULL; | ||||
if (!(fn = get_asset_filepath (filename, asset_fname))) | ||||
FATAL ("Invalid JS file."); | ||||
if (!(fp = fopen (fn, "w"))) | ||||
FATAL ("Unable to open file %s.", strerror (errno)); | ||||
free (fn); | ||||
return fp; | ||||
} | } | |||
/* entry point to generate a report writing it to the fp */ | /* entry point to generate a report writing it to the fp */ | |||
void | void | |||
output_html (GHolder * holder, const char *filename) { | output_html (GHolder * holder, const char *filename) { | |||
FILE *fp; | FILE *fp, *fjs = NULL, *fcs = NULL; | |||
char now[DATE_TIME]; | char now[DATE_TIME] = { 0 }; | |||
if (filename != NULL) | if (filename != NULL) | |||
fp = fopen (filename, "w"); | fp = fopen (filename, "w"); | |||
else | else | |||
fp = stdout; | fp = stdout; | |||
if (!fp) | if (!fp) | |||
FATAL ("Unable to open HTML file: %s.", strerror (errno)); | FATAL ("Unable to open HTML file: %s.", strerror (errno)); | |||
if (filename && conf.external_assets) { | ||||
fjs = get_asset (filename, FILENAME_JS); | ||||
fcs = get_asset (filename, FILENAME_CSS); | ||||
external_assets = 1; | ||||
} | ||||
/* use new lines to prettify output */ | /* use new lines to prettify output */ | |||
if (conf.json_pretty_print) | if (conf.json_pretty_print) | |||
nlines = 1; | nlines = 1; | |||
set_json_nlines (nlines); | set_json_nlines (nlines); | |||
generate_time (); | generate_time (); | |||
strftime (now, DATE_TIME, "%Y-%m-%d %H:%M:%S %z", &now_tm); | strftime (now, DATE_TIME, "%Y-%m-%d %H:%M:%S %z", &now_tm); | |||
print_html_header (fp); | print_html_header (fp, fcs); | |||
print_html_body (fp, now); | print_html_body (fp, now); | |||
print_json_defs (fp); | print_json_defs ((fjs ? fjs : fp)); | |||
print_json_data (fp, holder); | print_json_data ((fjs ? fjs : fp), holder); | |||
print_conn_def (fp); | print_conn_def ((fjs ? fjs : fp)); | |||
print_html_footer (fp); | print_html_footer (fp, fjs); | |||
if (fjs) | ||||
fclose (fjs); | ||||
if (fcs) | ||||
fclose (fcs); | ||||
fclose (fp); | fclose (fp); | |||
} | } | |||
End of changes. 19 change blocks. | ||||
27 lines changed or deleted | 98 lines changed or added |