?? wwwapi.cpp
字號:
//-< WWWAPI.CPP >----------------------------------------------------*--------*
// FastDB Version 1.0 (c) 1999 GARRET * ? *
// (Main Memory Database Management System) * /\| *
// * / \ *
// Created: 27-Mar-99 K.A. Knizhnik * / [] \ *
// Last update: 1-Jul-99 K.A. Knizhnik * GARRET *
//-------------------------------------------------------------------*--------*
// Implementation of WWWapi class
//-------------------------------------------------------------------*--------*
#define INSIDE_FASTDB
#include "wwwapi.h"
#include <ctype.h>
const size_t init_reply_buffer_size = 4*1024;
inline unsigned string_hash_function(const char* name)
{
unsigned h = 0, g;
while(*name)
{
h = (h << 4) + *name++;
if ((g = h & 0xF0000000) != 0)
{
h ^= g >> 24;
}
h &= ~g;
}
return h;
}
#define ERROR_TEXT(x) \
"HTTP/1.1 " x "\r\n\
Connection: close\r\n\r\n\
<HTML><HEAD><TITLE>Invalid request to the database</TITLE>\r\n\
</HEAD><BODY>\n\r\
<H1>" x "</H1>\n\r\
</BODY></HTML>\r\n\r\n"
WWWconnection::WWWconnection()
{
memset(hash_table, 0, sizeof hash_table);
sock = NULL;
reply_buf = new char[init_reply_buffer_size];
reply_buf_size = init_reply_buffer_size;
free_pairs = NULL;
peer = NULL;
userData = NULL;
userDataDestructor = NULL;
}
WWWconnection::~WWWconnection()
{
reset();
name_value_pair *nvp, *next;
for (nvp = free_pairs; nvp != NULL; nvp = next)
{
next = nvp->next;
delete nvp;
}
delete[] reply_buf;
delete[] peer;
if (userDataDestructor != NULL && userData != NULL)
{
userDataDestructor(userData);
}
}
inline char* WWWconnection::extendBuffer(size_t inc)
{
if (reply_buf_used + inc >= reply_buf_size)
{
reply_buf_size = reply_buf_size*2 > reply_buf_used + inc
? reply_buf_size*2 : reply_buf_used + inc;
char* new_buf = new char[reply_buf_size+1];
memcpy(new_buf, reply_buf, reply_buf_used);
delete[] reply_buf;
reply_buf = new_buf;
}
reply_buf_used += inc;
return reply_buf;
}
bool WWWconnection::terminatedBy(char const* str) const
{
size_t len = strlen(str);
if (len > reply_buf_used - 4)
{
return false;
}
return memcmp(reply_buf + reply_buf_used - len, str, len) == 0;
}
WWWconnection& WWWconnection::append(const void *buf, int len)
{
int pos = reply_buf_used;
char *dst = extendBuffer(len);
memcpy(dst + pos, buf, len);
return *this;
}
WWWconnection& WWWconnection::append(char const* str)
{
int pos = reply_buf_used;
char* dst = extendBuffer(strlen(str));
unsigned char ch;
switch (encoding)
{
case TAG:
strcpy(dst + pos, str);
encoding = HTML;
break;
case HTML:
encoding = TAG;
#if 1 // MS-Explorer handle " " in HTML string literals in very strange way
if (str[0] == ' ' && str[1] == '\0')
{
strcpy(extendBuffer(5) + pos, " ");
return *this;
}
#endif
while (true)
{
switch(ch = *str++)
{
case '<':
dst = extendBuffer(3);
dst[pos++] = '&';
dst[pos++] = 'l';
dst[pos++] = 't';
dst[pos++] = ';';
break;
case '>':
dst = extendBuffer(3);
dst[pos++] = '&';
dst[pos++] = 'g';
dst[pos++] = 't';
dst[pos++] = ';';
break;
case '&':
dst = extendBuffer(4);
dst[pos++] = '&';
dst[pos++] = 'a';
dst[pos++] = 'm';
dst[pos++] = 'p';
dst[pos++] = ';';
break;
case '"':
dst = extendBuffer(5);
dst[pos++] = '&';
dst[pos++] = 'q';
dst[pos++] = 'u';
dst[pos++] = 'o';
dst[pos++] = 't';
dst[pos++] = ';';
break;
case '\0':
dst[pos] = '\0';
return *this;
#if 0 // MS-Explorer handle " " in HTML string literals in very strange way
case ' ':
dst = extendBuffer(5);
dst[pos++] = '&';
dst[pos++] = 'n';
dst[pos++] = 'b';
dst[pos++] = 's';
dst[pos++] = 'p';
dst[pos++] = ';';
break;
#endif
default:
dst[pos++] = ch;
}
}
case URL:
encoding = TAG;
while (true)
{
ch = *str++;
if (ch == '\0')
{
dst[pos] = '\0';
return *this;
}
else if (ch == ' ')
{
dst[pos++] = '+';
}
else if (!isalnum(ch))
{
dst = extendBuffer(2);
dst[pos++] = '%';
dst[pos++] = (ch >> 4) >= 10
? (ch >> 4) + 'A' - 10 : (ch >> 4) + '0';
dst[pos++] = (ch & 0xF) >= 10
? (ch & 0xF) + 'A' - 10 : (ch & 0xF) + '0';
}
else
{
dst[pos++] = ch;
}
}
}
return *this;
}
void WWWconnection::reset()
{
reply_buf_used = 0;
encoding = TAG;
for (int i = itemsof(hash_table); --i >= 0;)
{
name_value_pair *nvp, *next;
for (nvp = hash_table[i]; nvp != NULL; nvp = next)
{
next = nvp->next;
nvp->next = free_pairs;
free_pairs = nvp;
}
hash_table[i] = NULL;
}
}
void WWWconnection::addPair(char const* name, char const* value)
{
name_value_pair* nvp;
if (free_pairs != NULL)
{
nvp = free_pairs;
free_pairs = nvp->next;
}
else
{
nvp = new name_value_pair;
}
unsigned hash_code = string_hash_function(name);
nvp->hash_code = hash_code;
hash_code %= hash_table_size;
nvp->next = hash_table[hash_code];
hash_table[hash_code] = nvp;
nvp->value = value;
nvp->name = name;
}
#define HEX_DIGIT(ch) ((ch) >= 'a' ? ((ch) - 'a' + 10) : (ch) >= 'A' ? ((ch) - 'A' + 10) : ((ch) - '0'))
char* WWWconnection::unpack(char* body, size_t length)
{
char *src = body, *end = body + length;
while (src < end)
{
char* name = src;
char ch;
char* dst = src;
while (src < end && (ch = *src++) != '=')
{
if (ch == '+')
{
ch = ' ';
}
else if (ch == '%')
{
ch = (HEX_DIGIT(src[0]) << 4) | HEX_DIGIT(src[1]);
src += 2;
}
*dst++ = ch;
}
*dst = '\0';
char* value = dst = src;
while (src < end && (ch = *src++) != '&')
{
if (ch == '+')
{
ch = ' ';
}
else if (ch == '%')
{
ch = (HEX_DIGIT(src[0]) << 4) | HEX_DIGIT(src[1]);
src += 2;
}
*dst++ = ch;
}
*dst = '\0';
addPair(name, value);
}
stub = get
("stub");
return get
("page");
}
char* WWWconnection::get
(char const* name, int n)
{
unsigned hash_code = string_hash_function(name);
name_value_pair* nvp;
for (nvp = hash_table[hash_code % hash_table_size];
nvp != NULL;
nvp = nvp->next)
{
if (nvp->hash_code == hash_code && strcmp(nvp->name, name) == 0)
{
if (n == 0)
{
return (char*)nvp->value;
}
n -= 1;
}
}
return NULL;
}
//--------------------------------------------------
WWWapi::WWWapi(dbDatabase& dbase, int n_handlers, dispatcher* dispatch_table)
: db(dbase)
{
memset(hash_table, 0, sizeof hash_table);
sock = NULL;
address = NULL;
dispatcher* disp = dispatch_table;
while (--n_handlers >= 0)
{
unsigned hash_code = string_hash_function(disp->page);
disp->hash_code = hash_code;
hash_code %= hash_table_size;
disp->collision_chain = hash_table[hash_code];
hash_table[hash_code] = disp;
disp += 1;
}
}
bool WWWapi::open(char const* socket_address,
socket_t::socket_domain domain,
int listen_queue)
{
if (sock != NULL)
{
close();
}
address = new char[strlen(socket_address) + 1];
strcpy(address, socket_address);
sock = domain != socket_t::sock_global_domain
? socket_t::create_local(socket_address, listen_queue)
: socket_t::create_global(socket_address, listen_queue);
canceled = false;
if (!sock->is_ok())
{
char buf[64];
sock->get_error_text(buf, sizeof buf);
fprintf(stderr, "WWWapi::open: create socket failed: %s\n", buf);
return false;
}
return true;
}
bool WWWapi::connect(WWWconnection& con)
{
assert(sock != NULL);
con.reset();
delete con.sock;
con.sock = sock->accept();
con.address = address;
if (con.sock == NULL)
{
if (!canceled)
{
char buf[64];
sock->get_error_text(buf, sizeof buf);
fprintf(stderr, "WWWapi::connect: accept failed: %s\n", buf);
}
return false;
}
return true;
}
void WWWapi::cancel()
{
canceled = true;
sock->cancel_accept();
}
void WWWapi::close()
{
delete sock;
delete[] address;
sock = NULL;
}
bool WWWapi::dispatch(WWWconnection& con, char* page)
{
unsigned hash_code = string_hash_function(page);
for (dispatcher* disp = hash_table[hash_code % hash_table_size];
disp != NULL;
disp = disp->collision_chain)
{
if (disp->hash_code == hash_code && strcmp(disp->page, page) == 0)
{
bool result = disp->func(con);
db.commit();
return result;
}
}
return true;
}
void URL2ASCII(char* src)
{
char* dst = src;
char ch;
while ((ch = *src++) != '\0')
{
if (ch == '%')
{
*dst++ = ((src[0] - '0') << 8) | (src[1] - '0');
}
else if (ch == '+')
{
*dst++ = ' ';
}
else if (ch == '.' && *src == '.')
{
// for security reasons do not allow access to parent directory
break;
}
else
{
*dst++ = ch;
}
}
*dst = '\0';
}
bool CGIapi::serve(WWWconnection& con)
{
nat4 length;
con.reset();
if ((size_t)con.sock->read(&length, sizeof length, sizeof length)
!= sizeof(length))
{
return true;
}
int size = length - sizeof length;
char* buf = new char[size];
if (con.sock->read(buf, size, size) != size)
{
return true;
}
char* page = con.unpack(buf + buf[0], length - sizeof length - buf[0]);
char* peer = con.get("peer");
con.peer = new char[strlen(peer)+1];
strcpy(con.peer, peer);
bool result = true;
if (page != NULL)
{
con.extendBuffer(4);
result = dispatch(con, page);
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -