When logging, escape strings.

While I'm here, rename urlencode[_filename]() and improve it.
This commit is contained in:
Emil Mikulic 2011-04-17 16:47:09 +10:00
parent 77e050b4f4
commit 36f22757f3

View File

@ -1077,9 +1077,34 @@ static void accept_connection(void) {
poll_recv_request(conn); poll_recv_request(conn);
} }
/* Should this character be logencoded?
*/
static int needs_logencoding(const unsigned char c) {
return ((c <= 0x1F) || (c >= 0x7F) || (c == '"'));
}
/* Encode string for logging.
*/
static void logencode(const char *src, char *dest) {
static const char hex[] = "0123456789ABCDEF";
int i, j;
for (i = j = 0; src[i] != '\0'; i++) {
if (needs_logencoding((unsigned char)src[i])) {
dest[j++] = '%';
dest[j++] = hex[(src[i] >> 4) & 0xF];
dest[j++] = hex[ src[i] & 0xF];
}
else
dest[j++] = src[i];
}
dest[j] = '\0';
}
/* Add a connection's details to the logfile. */ /* Add a connection's details to the logfile. */
static void log_connection(const struct connection *conn) { static void log_connection(const struct connection *conn) {
struct in_addr inaddr; struct in_addr inaddr;
char *safe_method, *safe_url, *safe_referer, *safe_user_agent;
if (logfile == NULL) if (logfile == NULL)
return; return;
@ -1088,20 +1113,45 @@ static void log_connection(const struct connection *conn) {
if (conn->method == NULL) if (conn->method == NULL)
return; /* invalid - didn't parse - maybe too long */ return; /* invalid - didn't parse - maybe too long */
/* Separated by tabs:
* time client_ip method url http_code bytes_sent "referer" "user-agent"
*/
inaddr.s_addr = conn->client; inaddr.s_addr = conn->client;
fprintf(logfile, "%lu\t%s\t%s\t%s\t%d\t%llu\t\"%s\"\t\"%s\"\n", #define make_safe(x) \
(unsigned long int)now, inet_ntoa(inaddr), if (conn->x) { \
conn->method, conn->url, safe_##x = xmalloc(strlen(conn->x)*3 + 1); \
conn->http_code, llu(conn->total_sent), logencode(conn->x, safe_##x); \
(conn->referer == NULL)?"":conn->referer, } else { \
(conn->user_agent == NULL)?"":conn->user_agent safe_##x = NULL; \
}
make_safe(method);
make_safe(url);
make_safe(referer);
make_safe(user_agent);
#define use_safe(x) safe_##x ? safe_##x : ""
fprintf(logfile, "%lu %s \"%s %s\" %d %llu \"%s\" \"%s\"\n",
(unsigned long int)now,
inet_ntoa(inaddr),
use_safe(method),
use_safe(url),
conn->http_code,
llu(conn->total_sent),
use_safe(referer),
use_safe(user_agent)
); );
fflush(logfile); fflush(logfile);
#define free_safe(x) if (safe_##x) free(safe_##x);
free_safe(method);
free_safe(url);
free_safe(referer);
free_safe(user_agent);
#undef make_safe
#undef use_safe
#undef free_safe
} }
/* Log a connection, then cleanly deallocate its internals. */ /* Log a connection, then cleanly deallocate its internals. */
@ -1535,41 +1585,41 @@ static void cleanup_sorted_dirlist(struct dlent **list, const ssize_t size) {
} }
} }
/* Should this character be urlencoded (according to RFC1738). /* Should this character be urlencoded? (according to RFC1738)
* Contributed by nf. * Contributed by nf.
*/ */
static int needs_urlencoding(unsigned char c) { static int needs_urlencoding(const unsigned char c) {
unsigned int i; unsigned int i;
static const char bad[] = "<>\"%{}|^~[]`\\;:/?@#=&"; static const char bad[] = "<>\"%{}|^~[]`\\;:/?@#=&";
/* Non-US-ASCII characters */
if ((c <= 0x1F) || (c >= 0x7F))
return 1;
for (i = 0; i < sizeof(bad) - 1; i++) for (i = 0; i < sizeof(bad) - 1; i++)
if (c == bad[i]) if (c == bad[i])
return 1; return 1;
/* Non-US-ASCII characters */
if ((c <= 0x1F) || (c >= 0x80) || (c == 0x7F))
return 1;
return 0; return 0;
} }
/* Encode filename to be an RFC1738-compliant URL part. /* Encode string to be an RFC1738-compliant URL part.
* Contributed by nf. * Contributed by nf.
*/ */
static void urlencode_filename(char *name, char *safe_url) { static void urlencode(const char *src, char *dest) {
static const char hex[] = "0123456789ABCDEF"; static const char hex[] = "0123456789ABCDEF";
int i, j; int i, j;
for (i = j = 0; name[i] != '\0'; i++) { for (i = j = 0; src[i] != '\0'; i++) {
if (needs_urlencoding((unsigned char)name[i])) { if (needs_urlencoding((unsigned char)src[i])) {
safe_url[j++] = '%'; dest[j++] = '%';
safe_url[j++] = hex[(name[i] >> 4) & 0xF]; dest[j++] = hex[(src[i] >> 4) & 0xF];
safe_url[j++] = hex[ name[i] & 0xF]; dest[j++] = hex[ src[i] & 0xF];
} }
else else
safe_url[j++] = name[i]; dest[j++] = src[i];
} }
safe_url[j] = '\0'; dest[j] = '\0';
} }
static void generate_dir_listing(struct connection *conn, const char *path) { static void generate_dir_listing(struct connection *conn, const char *path) {
@ -1608,7 +1658,7 @@ static void generate_dir_listing(struct connection *conn, const char *path) {
*/ */
char safe_url[MAXNAMLEN*3 + 1]; char safe_url[MAXNAMLEN*3 + 1];
urlencode_filename(list[i]->name, safe_url); urlencode(list[i]->name, safe_url);
append(listing, "<a href=\""); append(listing, "<a href=\"");
append(listing, safe_url); append(listing, safe_url);