211 lines
5.4 KiB
C
211 lines
5.4 KiB
C
#include "util.h"
|
|
|
|
#include <stdio.h>
|
|
#include <ctype.h> /**< isalnum isdigit */
|
|
#include <string.h> /**< strncmp */
|
|
#include <time.h> /**< strftime */
|
|
#include <sys/time.h> /**< struct timeval */
|
|
#include <sys/resource.h> /**< struct rusage, getrusage */
|
|
|
|
// timeval -> microseconds
|
|
static int64_t Tv2Ms(struct timeval *p)
|
|
{
|
|
return ((int64_t)p->tv_sec) * 1000000 + (int64_t)p->tv_usec;
|
|
}
|
|
|
|
/// Render seconds since 1970 as an RFC822 date string.
|
|
/// Return a pointer to that string in a static buffer.
|
|
static char *Rfc822Date(time_t t)
|
|
{
|
|
struct tm *tm;
|
|
static char date[100];
|
|
|
|
tm = gmtime(&t);
|
|
strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S GMT", tm);
|
|
|
|
return date;
|
|
}
|
|
|
|
char *Rfc822DateNow()
|
|
{
|
|
time_t now;
|
|
time(&now);
|
|
return Rfc822Date(now);
|
|
}
|
|
|
|
/// Parse an RFC822-formatted timestamp as we'd expect from HTTP and return
|
|
/// a Unix epoch time. <= zero is returned on failure.
|
|
time_t ParseRfc822Date(const char *zDate)
|
|
{
|
|
int mday, mon, year, yday, hour, min, sec;
|
|
char zIgnore[4];
|
|
char zMonth[4];
|
|
|
|
static const char *const azMonths[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
|
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
|
|
|
|
if (7 == sscanf(zDate, "%3[A-Za-z], %d %3[A-Za-z] %d %d:%d:%d", zIgnore,
|
|
&mday, zMonth, &year, &hour, &min, &sec))
|
|
{
|
|
if (year > 1900) year -= 1900;
|
|
|
|
for (mon = 0; mon < 12; mon++)
|
|
{
|
|
if(!strncmp(azMonths[mon], zMonth, 3))
|
|
{
|
|
int nDay;
|
|
int isLeapYr;
|
|
static int priorDays[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
|
|
isLeapYr = year % 4 == 0 && (year % 100 != 0 || (year + 300) % 400==0);
|
|
yday = priorDays[mon] + mday - 1;
|
|
|
|
if(isLeapYr && mon > 1) yday++;
|
|
|
|
nDay = (year - 70) * 365 + (year - 69) / 4 - year / 100 + (year + 300) / 400 + yday;
|
|
return ((time_t)(nDay * 24 + hour) * 60 + min) * 60 + sec;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void LogPrint(int lineNum)
|
|
{
|
|
struct timeval now;
|
|
struct tm *ptm;
|
|
struct rusage self;
|
|
size_t sz;
|
|
char date[200];
|
|
|
|
gettimeofday(&now, 0);
|
|
ptm = localtime(&now.tv_sec);
|
|
strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", ptm);
|
|
getrusage(RUSAGE_SELF, &self);
|
|
/* Log record:
|
|
** (1) Date and time
|
|
** (2) IP address
|
|
** (3) URL being accessed
|
|
** (4) Referer
|
|
** (5) Reply status
|
|
** (6) Bytes received
|
|
** (7) Bytes sent
|
|
** (8) Self user time
|
|
** (9) Self system time
|
|
** (10) Total wall-clock time
|
|
** (11) Request number for same TCP/IP connection
|
|
** (12) User agent
|
|
** (13) Remote user
|
|
** (14) Bytes of URL that correspond to the SCRIPT_NAME
|
|
** (15) Line number in source file
|
|
*/
|
|
// fprintf(stdout, "%s,%s,\"%s://%s%s\",\"%s\","
|
|
// "%s,%d,%d,%lld,%lld,%lld,%lld,%lld,%d,\"%s\",\"%s\",%d,%d\n",
|
|
// zDate, zRemoteAddr, zHttpScheme, Escape(zHttpHost), Escape(zScript),
|
|
// Escape(zReferer), zReplyStatus, nIn, nOut,
|
|
// Tv2Ms(&self.ru_utime) - Tv2Ms(&priorSelf.ru_utime),
|
|
// Tv2Ms(&self.ru_stime) - Tv2Ms(&priorSelf.ru_stime),
|
|
// Tv2Ms(&now) - Tv2Ms(&beginTime),
|
|
// nRequest, Escape(zAgent), Escape(zRM),
|
|
// (int)(strlen(zHttpScheme)+strlen(zHttpHost)+strlen(zRealScript)+3),
|
|
// lineNum);
|
|
// priorSelf = self;
|
|
}
|
|
|
|
int HttpUrlEncodeWithLength(const char *src, size_t srcsize, char *dst, size_t dstsize)
|
|
{
|
|
static const char *kDontEscape = "._-$,;~()";
|
|
static const char *kHex = "0123456789abcdef";
|
|
|
|
size_t i = 0;
|
|
int ch;
|
|
char *pos;
|
|
const char *end;
|
|
|
|
if (dst == NULL || dstsize < 1)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (src == NULL || srcsize == 0)
|
|
{
|
|
dst[0] = 0;
|
|
return 0;
|
|
}
|
|
|
|
pos = dst;
|
|
end = dst + dstsize - 1;
|
|
|
|
while (i < srcsize && pos < end)
|
|
{
|
|
ch = src[i];
|
|
if (isalnum(ch) || strchr(kDontEscape, ch) != NULL)
|
|
{
|
|
*pos = (char)ch;
|
|
}
|
|
else if (pos + 2 < end)
|
|
{
|
|
pos[0] = '%';
|
|
pos[1] = kHex[ch >> 4];
|
|
pos[2] = kHex[ch & 0xf];
|
|
pos += 2;
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
|
|
pos++;
|
|
i++;
|
|
}
|
|
|
|
*pos = 0;
|
|
return (i == srcsize) ? (int)(pos - dst) : -1;
|
|
}
|
|
|
|
int HttpUrlDecodeWithFormat(const char *src, char *dst, size_t dstsize, int is_form_url_encoded)
|
|
{
|
|
#define HEXTOI(x) (isdigit(x) ? ((x) - '0') : ((x) - 'W'))
|
|
int i = 0, j = 0, a, b;
|
|
int srcsize, dstlen;
|
|
|
|
if (dst == NULL || dstsize < 1)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if (src == NULL)
|
|
{
|
|
dst[0] = 0;
|
|
return 0;
|
|
}
|
|
|
|
srcsize = (int)strlen(src);
|
|
dstlen = (int)dstsize;
|
|
|
|
while (i < srcsize && j < dstlen - 1)
|
|
{
|
|
if (i < srcsize - 2 && src[i] == '%' && isdigit(*(const uint8_t *)(src + i + 1)) && isxdigit(*(const uint8_t *)(src + i + 2)))
|
|
{
|
|
a = tolower(*(const uint8_t *)(src + i + 1));
|
|
b = tolower(*(const uint8_t *)(src + i + 2));
|
|
dst[j] = (char)((HEXTOI(a) << 4) | HEXTOI(b));
|
|
i += 2;
|
|
}
|
|
else if (is_form_url_encoded && src[i] == '+')
|
|
{
|
|
dst[j] = ' ';
|
|
}
|
|
else
|
|
{
|
|
dst[j] = src[i];
|
|
}
|
|
i++;
|
|
j++;
|
|
}
|
|
|
|
dst[j] = 0;
|
|
return (i >= srcsize) ? j : -1;
|
|
}
|
|
|