📄 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;
}
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;
}
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];
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(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;
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;
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 = items(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;
}
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 = ((src[0] >= 'A' ? src[0] - 'A'+ 10 : src[0] - '0') << 4) |
(src[1] >= 'A' ? src[1] - 'A'+ 10 : src[1] - '0');
src += 2;
}
*dst++ = ch;
}
*dst = '\0';
char* value = dst = src;
while (src < end && (ch = *src++) != '&') {
if (ch == '+') {
ch = ' ';
} else if (ch == '%') {
ch = ((src[0] >= 'A' ? src[0] - 'A'+ 10 : src[0] - '0') << 4) |
(src[1] >= 'A' ? src[1] - 'A'+ 10 : src[1] - '0');
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;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -