summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJason Linehan <patientulysses@gmail.com>2012-06-18 11:59:36 -0400
committerJason Linehan <patientulysses@gmail.com>2012-06-18 11:59:36 -0400
commit313aa4bbcbcb1101ef16a3588b37bf625498eb71 (patch)
tree79e84cd3eb1cc26b32015c64f00a706a906faaab
parent7693ca87376803a69367c50e04d5ef0fbf278050 (diff)
downloadcloth-313aa4bbcbcb1101ef16a3588b37bf625498eb71.tar.gz
cloth-313aa4bbcbcb1101ef16a3588b37bf625498eb71.tar.bz2
cloth-313aa4bbcbcb1101ef16a3588b37bf625498eb71.zip
Factors log functions into new module
-rw-r--r--cloth.c232
-rw-r--r--http_status.h15
-rw-r--r--log.c245
-rw-r--r--log.h7
4 files changed, 253 insertions, 246 deletions
diff --git a/cloth.c b/cloth.c
index cc027dc..759bdbb 100644
--- a/cloth.c
+++ b/cloth.c
@@ -26,13 +26,7 @@
/* For static buffers */
#define BUFSIZE 8096
-#define LOGBUF 256
-/* Default path of the log file (relative to -d) */
-#define LOG_PATH "cloth.log"
-/* Default path of procinfo file (relative to -d) */
-#define INFO_PATH "cloth.info"
-/* The strftime() format string for common log time. */
-#define COMMON_LOG_TIME "%d/%b/%Y:%H:%M:%S %z"
+
/* Message printed on illegal argument usage. */
#define HELP_MESSAGE "usage: cloth <PORT> <WWW-DIRECTORY>\n"
@@ -76,233 +70,9 @@ char www_path[BUFSIZE];
-/******************************************************************************
- * LOGS
- * Implements the common log format and standard log time format.
- ******************************************************************************/
-/**
- * A log entry consists of the 7-tuple
- *
- * { code, file, local-addr, action, remote-addr, time, message }
- *
- * code: the type of log entry, one of
- * START - the server is starting up
- * STOP - the server is shutting down
- * INFO - standard entry which indicates an action
- * WARN - an action has failed
- * OUCH - an unrecoverable error has occured
- *
- * file: the filename of the source being requested
- *
- * local-addr: the address or domain name specified by the remote host, viz.
- * myserver.mydomain.org or 42.112.5.25.some.isp.net. Because different
- * names may resolve to the same address, this field will specifically
- * reflect the label that the *remote host* is using to contact your
- * server.
- *
- * action: the nature of the interaction between the local and remote hosts,
- * being one of the 9 HTTP methods ("verbs"), or else a response verb
- * emitted by the server. The action may be printed by name or in
- * symbolic fashion.
- *
- * HEAD - Ask for response (metadata) without response body
- * GET - Request a representation of the specified source
- * POST - Submits data to be processed
- * PUT - Uploads a representation of the specified resource
- * DELETE - Deletes the specified resource
- * TRACE - Echoes back the received request
- * OPTIONS - Check if the server supports a specific request
- * CONNECT - Converts the connection to a transparent TCP/IP tunnel
- * PATCH - Apply partial modifications to a resource
- *
- * Cloth only supports the GET routine, for simplicity, and a successful
- * response is marked SEND.
- *
- * Alternate representations
- *
- * GET <---
- * SEND --->
- * WARN !---
- * ---!
- * OUCH x--x
- *
- * remote-addr: similar to the local address, except for the remote host
- *
- * time: The time at which the request was processed by the server
- * Time is formatted in ISO format: yyyy-mm-dd HH:mm:ss
- *
- * message: An optional plaintext message, e.g. explaining an error context or
- * specifying the user agent of the remote host
- *
- * An example log snippet:
- *
- * INFO index.html cloth.homeunix.org:80 <--- 22.85.117.2:34205 (2012-06-17 06:49:58) "Mozilla/5.0 (Windows; U; Windows..."
- * INFO index.html cloth.homeunix.org:80 ---> 22.85.117.2:34206 (2012-06-17 06:49:59)
- * INFO jindex.baz cloth.homeunix.org:80 <--- 22.85.117.2:31102 (2012-06-17 06:50:01) "Mozilla/5.0 (Windows; U; Windows..."
- * WARN jindex.baz cloth.homeunix.org:80 ---! 22.85.117.2:31102 (2012-06-17 06:50:02) "Extension type not supported"
- */
-
-
-struct session_t {
- int socket; /* File descriptor of the socket */
- char *host; /* Hostname the remote end wants to connect to */
- char *agent; /* Remote user-agent id */
- char *resource; /* Resource (file) being requested */
- char *remote_addr; /* Address of the remote host */
- short remote_port; /* Port of the remote host */
-};
-
-
-/**
- * http_info -- Parse an HTTP request and identify relevant information
- * @request: the HTTP request buffer
- * @entry : the log_entry struct to be (partially) filled out
- *
- * Determines the following:
- * 0. The resource being requested
- * 1. The hostname targeted by the remote agent
- * 2. The remote User-Agent ID
- *
- */
-void http_info(struct session_t *session, char *request)
-{
- static char req_copy[BUFSIZE];
- char *token;
- char *buf;
-
- bwipe(req_copy);
- strcpy(req_copy, request);
-
- /*
- * Search tokens are truncated before being placed in the struct.
- * See field() in textutils.h for details.
- */
- for (token = strtok(req_copy, "**");
- token != NULL;
- token = strtok(NULL, "**"))
- {
- if (buf = field(token, "GET "), buf != NULL)
- /* e.g. 'GET /index.html' */
- pumpf(&session->resource, "%s", buf);
-
- if (buf = field(token, "Host: "), buf != NULL)
- /* e.g. 'Host: www.something.com' */
- pumpf(&session->host, "%s", buf);
-
- if (buf = field(token, "User-Agent: "), buf != NULL)
- /* e.g. 'User-Agent: Mozilla/3.0 ...' */
- pumpf(&session->agent, "%s", buf);
- }
-}
-
-
-/**
- * addr_info -- fill out the remote host information in the session struct
- * @session: pointer to a session struct
- * @remote : pointer to a copy of the remote sockaddr_in
- */
-void addr_info(struct session_t *session, struct sockaddr_in *remote)
-{
- if (!remote)
- return;
-
- session->remote_addr = inet_ntoa(remote->sin_addr);
- session->remote_port = ntohs(remote->sin_port);
-}
-
-
-/**
- * session_info -- fill out the session structure
- * @session: pointer to a session struct
- * @socket : file descriptor of active socket
- * @remote : sockaddr of remote client
- * @request: HTTP request
- */
-void session_info(struct session_t *session, int socket, struct sockaddr_in *remote, char *request)
-{
- http_info(session, request);
- addr_info(session, remote);
- session->socket = socket;
-}
-
-
-
-void time_info(char *buffer, time_t time)
-{
- #define TIME_FORMAT "%Y-%m-%d %H:%M:%S"
- strftime(buffer, LOGBUF, TIME_FORMAT, gmtime(&time));
-}
-char *new_entry(struct http_status *status, struct session_t *session)
-{
- char *timebuf;
- char *buffer;
-
- timebuf = malloc(LOGBUF * sizeof(char));
- time_info(timebuf, time(NULL));
-
- pumpf(&buffer, "%s %s %s %s:%hd (%s)",
- session->resource,
- session->host,
- status->figure,
- session->remote_addr,
- session->remote_port,
- timebuf);
-
- free(timebuf);
-
- return buffer;
-}
-
-
-void log(int code, struct session_t *session, char *msg)
-{
- struct http_status *status;
- char *entry;
- char *buf;
- int fd;
-
- status = &STATUS[code];
-
- if (status->code != OUCH)
- entry = new_entry(status, session);
-
- switch (status->code)
- {
- case OUCH:
- pumpf(&buf, "OUCH: \"%s\" (%d)", msg, errno);
- break;
- case WARN:
- /* Write over socket */
- pumpf(&buf, "cloth says: %hd %s\r", status->code, msg);
- write(session->socket, buf, strlen(buf));
- /* Write to log */
- pumpf(&buf, "WARN: %s \"%hd\"", entry, status->http);
- break;
- case INFO:
- pumpf(&buf, "INFO: %s \"%s\"", entry, msg);
- break;
- }
-
- /* Write the log buffer to the log file */
- if ((fd = open(LOG_PATH, O_CREAT| O_WRONLY | O_APPEND, 0644)) >= 0) {
- write(fd, buf, strlen(buf));
- write(fd, "\n", 1);
- close(fd);
- }
-
- if (status->code != OUCH)
- free(entry);
-
- free(buf);
-
- if (status->code == OUCH || status->code == WARN)
- exit(3);
-}
-
-
/******************************************************************************
* HTTP
* The main functions called by the child process when a request is made
diff --git a/http_status.h b/http_status.h
index 71dd90b..571a0f7 100644
--- a/http_status.h
+++ b/http_status.h
@@ -50,19 +50,4 @@ static struct http_status STATUS[]={
{ OUCH, HTTP_FATAL_ERROR, "xxxx" }, /* FATAL */
};
-//[> Info <]
-//static struct http_status RESPONSE { HTTP_OK, "--->" };
-//static struct http_status ACCEPT { HTTP_ACCEPTED, "<---" };
-
-//[> Warn <]
-//static struct http_status BAD_REQUEST { HTTP_BAD_REQUEST, "x---" };
-//static struct http_status NOT_FOUND { HTTP_NOT_FOUND, "?---" };
-//static struct http_status BAD_METHOD { HTTP_METHOD_FORBIDDEN, "x---" };
-//static struct http_status OVERFLOW { HTTP_HEADER_OVERFLOW, "+---" };
-//static struct http_status ERROR { HTTP_SERVER_ERROR, "---x" };
-//static struct http_status NO_METHOD { HTTP_NO_METHOD, "---?" };
-
-//[> Ouch <]
-//static struct http_status FATAL { HTTP_FATAL_ERROR, "xxxx" };
-
#endif
diff --git a/log.c b/log.c
new file mode 100644
index 0000000..a35dc57
--- /dev/null
+++ b/log.c
@@ -0,0 +1,245 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include "textutils.h"
+#include "http_status.h"
+
+/* Default path of the log file (relative to -d) */
+#define LOG_PATH "cloth.log"
+
+/* strf format strings */
+#define COMMON_LOG_TIME "%d/%b/%Y:%H:%M:%S %z"
+#define ISO_TIME "%Y-%m-%d %H:%M:%S"
+#define ISO_LEN 24
+
+/******************************************************************************
+ * LOGS
+ *
+ * { code, file, hostname, verb, remote_addr, remote_port, time, message }
+ *
+ * code
+ * ````
+ * START - the server is starting up
+ * STOP - the server is shutting down
+ * INFO - standard entry which indicates an action
+ * WARN - an action has failed
+ * OUCH - an unrecoverable error has occured
+ *
+ * file
+ * ````
+ * The filename of the source being requested
+ *
+ * hostname
+ * ````````
+ * myserver.mydomain.org
+ * 42.112.5.25.some.isp.net.
+ *
+ * The address or domain name specified by the remote host. Because
+ * different names may resolve to the same address, this field will
+ * specifically reflect the label that the *remote host* is using to
+ * contact your server.
+ *
+ * verb
+ * ````
+ * The nature of the interaction between the local and remote hosts,
+ * being one of the 9 HTTP methods ("verbs"). The 9 methods are HEAD,
+ * GET, POST, PUT, DELETE, TRACE, OPTIONS, CONNECT, and PATCH.
+ *
+ * cloth only supports the GET routine, for simplicity.
+ *
+ * remote_addr
+ * ```````````
+ * IPv4 address of the remote client.
+ *
+ * remote_port
+ * ```````````
+ * Port number of the remote client.
+ * time
+ * ````
+ * The time at which the request was processed by the server.
+ * Time is formatted in ISO format: yyyy-mm-dd HH:mm:ss
+ *
+ * message
+ * ```````
+ * An optional plaintext message, e.g. explaining an error context or
+ * specifying the user agent of the remote host.
+ *
+ ******************************************************************************/
+
+
+/******************************************************************************
+ * SESSION INFORMATION
+ *
+ * A session is identified in the log by a set of 6 values:
+ *
+ * 0. socket - the outbound socket being communicated over
+ * 1. host - hostname given by remote client (resolves to local ip)
+ * 2. agent - the user-agent id of the remote client
+ * 3. resource - the file requested by the remote client
+ * 4. remote_addr - the address of the remote client
+ * 5. remote_port - the port of the remote client
+ *
+ ******************************************************************************/
+/*
+ * Session structure
+ */
+struct ses_t {
+ int socket; // File descriptor of the socket
+ char *host; // Hostname submitted by remote end
+ char *agent; // Remote user-agent id
+ char *resource; // Resource (file) being requested
+ char *remote_addr; // Address of the remote host
+ char time[ISO_LEN]; // Formatted time of processing
+ unsigned short remote_port; // Port of the remote host
+};
+
+
+/**
+ * sesinfo_http -- Insert parsed HTTP request into the session struct
+ * @session: the uninitialized session struct
+ * @request: the raw text of the HTTP request
+ *
+ * PROVIDES: resource, host, agent
+ */
+void sesinfo_http(struct ses_t *session, char *request)
+{
+ char *copy; // copy of HTTP request
+ char *token; // tokenized substring of copy
+ char *clean; // cleaned-up version of token
+
+ copy = bdup(request);
+
+ /*
+ * Search tokens are truncated before being placed in the struct.
+ * See field() in textutils.h for details.
+ */
+ for (token = strtok(copy, "**");
+ token != NULL;
+ token = strtok(NULL, "**"))
+ {
+ if (clean = field(token, "GET "), clean != NULL)
+ pumpf(&session->resource, "%s", clean);
+
+ if (clean = field(token, "Host: "), clean != NULL)
+ pumpf(&session->host, "%s", clean);
+
+ if (clean = field(token, "User-Agent: "), clean != NULL)
+ pumpf(&session->agent, "%s", clean);
+ }
+}
+
+
+/**
+ * sesinfo_addr -- Insert remote host address and port into the session struct
+ * @session: the uninitialized session struct
+ * @remote : a copy of the remote sockaddr_in
+ *
+ * PROVIDES: remote_addr, remote_port
+ */
+inline void sesinfo_addr(struct ses_t *session, struct sockaddr_in *remote)
+{
+ session->remote_addr = inet_ntoa(remote->sin_addr);
+ session->remote_port = ntohs(remote->sin_port);
+}
+
+
+/**
+ * sesinfo_time -- Insert the formatted time into the session struct
+ * @session: the uninitialized session struct
+ * @time : current time
+ */
+inline void sesinfo_time(struct ses_t *session, time_t time)
+{
+ strftime(session->time, LOGBUF, ISO_TIME, gmtime(&time));
+}
+
+
+/**
+ * sesinfo -- fill out a session structure
+ * @session: the uninitialized session struct
+ * @socket : file descriptor of active socket
+ * @remote : sockaddr of remote client
+ * @request: HTTP request
+ */
+void sesinfo(struct ses_t *session, int socket, struct sockaddr_in *remote, char *request)
+{
+ sesinfo_http(session, request); // get resource, host, agent
+ sesinfo_addr(session, remote); // get remote_addr, remote_port
+ session->socket = socket; // get socket descriptor
+}
+
+
+
+
+
+
+char *new_entry(struct http_status *status, struct session_t *session)
+{
+ char *timebuf;
+ char *buffer;
+
+ timebuf = malloc(LOGBUF * sizeof(char));
+ time_info(timebuf, time(NULL));
+
+ pumpf(&buffer, "%s %s %s %s:%hu (%s)",
+ session->resource,
+ session->host,
+ status->figure,
+ session->remote_addr,
+ session->remote_port,
+ timebuf);
+
+ free(timebuf);
+
+ return buffer;
+}
+
+
+void log(int code, struct session_t *session, char *msg)
+{
+ char *entry;
+ char *buf;
+ int fd;
+
+ if (session != NULL)
+ entry = new_entry(&STATUS[code], session);
+
+ switch (STATUS[code].code)
+ {
+ case INFO:
+ pumpf(&buf, "INFO: %s %s", entry, msg);
+ break;
+ case OUCH:
+ pumpf(&buf, "OUCH: %s (%d)", msg, errno);
+ break;
+ case WARN:
+ pumpf(&buf, "cloth says: %hd %s\r", STATUS[code].code, msg);
+ write(session->socket, buf, strlen(buf));
+ pumpf(&buf, "WARN: %s (%hd)", entry, STATUS[code].http);
+ break;
+ }
+
+ /* Write the log buffer to the log file */
+ if ((fd = open(LOG_PATH, O_CREAT| O_WRONLY | O_APPEND, 0644)) >= 0) {
+ write(fd, buf, strlen(buf));
+ write(fd, "\n", 1);
+ close(fd);
+ }
+
+ if (session != NULL)
+ free(entry);
+
+ free(buf);
+
+ if (STATUS[code].code == OUCH || STATUS[code].code == WARN)
+ exit(3);
+}
+
diff --git a/log.h b/log.h
new file mode 100644
index 0000000..cdf8953
--- /dev/null
+++ b/log.h
@@ -0,0 +1,7 @@
+#ifndef __HTTP_LOG_H
+#define __HTTP_LOG_H
+
+struct ses_t _session_fref;
+
+
+void log(int code, struct ses_t *session, char *msg);