📄 wwwapi.cpp
字号:
{ 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); *(int4*)con.reply_buf = con.reply_buf_used; con.sock->write(con.reply_buf, con.reply_buf_used); } delete[] con.peer; con.peer = NULL; delete con.sock; con.sock = NULL; // close connection return result;}inline char* stristr(char* s, char* p) { while (*s != '\0') { int i; for (i = 0; (s[i] & ~('a'-'A')) == (p[i] & ~('a' - 'A')) && p[i] != '\0'; i++); if (p[i] == '\0') { return s; } s += 1; } return NULL;}bool HTTPapi::serve(WWWconnection& con){ const size_t inputBufferSize = 16*1024; char buf[inputBufferSize]; bool result = false; size_t size = 0; con.peer = con.sock->get_peer_name(); while (true) { con.reset(); char* p = buf; char prev_ch = 0; do { if (p == buf + size) { int rc = con.sock->read(buf + size, 5, sizeof(buf) - size - 1, connectionHoldTimeout); if (rc < 0) { delete con.sock; con.sock = NULL; return true; } if (rc < 5) { con.append(ERROR_TEXT("200 OK")); // connection closed due to timeout expiration break; } size += rc; } buf[size] = '\0'; while (*p != '\0' && (prev_ch != '\n' || *p != '\r')) { prev_ch = *p++; } } while (*p == '\0' && p == buf + size); // p now points to the message body if (*p != '\r' || *(p+1) != '\n') { con.append(ERROR_TEXT("400 Bad Request")); break; } p += 2; int length = INT_MAX; char* lenptr = stristr(buf, "content-length: "); bool persistentConnection = stristr(buf, "Connection: keep-alive") != NULL; char* host = stristr(buf, "host: "); if (host != NULL) { char* q = host += 6; while (*q != '\n' && *q != '\r' && *q != '\0') q += 1; *q = '\0'; } if (lenptr != NULL) { sscanf(lenptr+15, "%d", &length); } if (strncmp(buf, "GET ", 4) == 0) { char* file, *uri = buf; file = strchr(uri, '/'); if (file == NULL) { con.append(ERROR_TEXT("400 Bad Request")); break; } if (*++file == '/') { if (host == NULL) { host = file+1; } file = strchr(uri, '/'); if (file == NULL) { con.append(ERROR_TEXT("400 Bad Request")); break; } *file++ = '\0'; } char* file_end = strchr(file, ' '); char index_html[] = "index.html"; if (file_end == NULL) { con.append(ERROR_TEXT("400 Bad Request")); break; } if (file_end == file) { file = index_html; } else { *file_end = '\0'; } if (host == NULL) { host = "localhost"; } char* params = strchr(file, '?'); if (params != NULL) { if (!handleRequest(con, params+1, file_end, host, result)) { delete con.sock; con.sock = NULL; return result; } } else { URL2ASCII(file); FILE* f = fopen(file, "rb"); if (f == NULL) { if (strcmp(file, index_html) == 0) { static char defaultPage[] = "page=defaultPage"; if (!handleRequest(con, defaultPage, defaultPage + strlen(defaultPage), host, result)) { delete con.sock; con.sock = NULL; return result; } } else { con.append(ERROR_TEXT("404 File Not Found")); break; } } else { fseek(f, 0, SEEK_END); size_t file_size = ftell(f); fseek(f, 0, SEEK_SET); char reply[1024]; sprintf(reply, "HTTP/1.1 200 OK\r\nContent-Length: %u\r\n" "Content-Type: text/html\r\nConnection: %s\r\n\r\n", file_size, keepConnectionAlive ? "Keep-Alive" : "close"); con.append(reply); size_t pos = con.reply_buf_used; char* dst = con.extendBuffer(file_size); if (dst == NULL) { con.reset(); con.append(ERROR_TEXT("413 Request Entity Too Large")); break; } if (fread(dst + pos, 1, file_size, f) != file_size) { con.reset(); con.append(ERROR_TEXT("500 Internal server error")); break; } fclose(f); if (!con.sock->write(dst, con.reply_buf_used) || !keepConnectionAlive) { delete con.sock; con.sock = NULL; return true; } } } } else if (strncmp(buf, "POST ", 5) == 0) { char* body = p; ScanNextPart: int n = length < buf + size - p ? length : buf + size - p; while (--n >= 0 && *p != '\r' && *p != '\n') { p += 1; } if (n < 0 && p - body != length) { if (size >= sizeof(buf) - 1) { con.append(ERROR_TEXT("413 Request Entity Too Large")); break; } int rc = con.sock->read(p, 1, sizeof(buf) - size - 1, connectionHoldTimeout); if (rc < 0) { delete con.sock; con.sock = NULL; return true; } size += rc; goto ScanNextPart; } else { if (host == NULL) { host = "localhost"; } if (!handleRequest(con, body, p, host, result)) { delete con.sock; con.sock = NULL; return result; } while (n >= 0 && (*p == '\n' || *p == '\r')) { p += 1; n -= 1; } } } else { con.append(ERROR_TEXT("405 Method not allowed")); break; } if (!persistentConnection) { delete con.sock; con.sock = NULL; return true; } if (p - buf < (long)size) { size -= p - buf; memcpy(buf, p, size); } else { size = 0; } } if (con.sock != NULL) { con.sock->write(con.reply_buf, con.reply_buf_used); con.sock->shutdown(); delete con.sock; con.sock = NULL; } return true;}bool HTTPapi::handleRequest(WWWconnection& con, char* begin, char* end, char* host, bool& result){ char buf[64]; char ch = *end; char* page = con.unpack(begin, end - begin); if (page != NULL) { con.append("HTTP/1.1 200 OK\r\nContent-Length: \r\n"); int length_pos = con.reply_buf_used - 8; con.append(keepConnectionAlive ? "Connection: Keep-Alive\r\n" : "Connection: close\r\n"); sprintf(buf, "http://%s/", host); con.stub = buf; result = dispatch(con, page); char* body = con.reply_buf + length_pos; char prev_ch = 0; con.reply_buf[con.reply_buf_used] = '\0'; while ((*body != '\n' || prev_ch != '\n') && (*body != '\r' || prev_ch != '\n') && *body != '\0') { prev_ch = *body++; } if (*body == '\0') { con.reset(); con.append(ERROR_TEXT("404 Not found")); con.sock->write(con.reply_buf, con.reply_buf_used); return false; } body += *body == '\n' ? 1 : 2; sprintf(buf, "%u", con.reply_buf_used - (body - con.reply_buf)); memcpy(con.reply_buf + length_pos, buf, strlen(buf)); if (!con.sock->write(con.reply_buf, con.reply_buf_used)) { return false; } *end = ch; return result && keepConnectionAlive; } else { con.append(ERROR_TEXT("Not acceptable")); con.sock->write(con.reply_buf, con.reply_buf_used); result = true; *end = ch; return false; }}//----------------------------------------------------void thread_proc QueueManager::handleThread(void* arg){ ((QueueManager*)arg)->handle();}QueueManager::QueueManager(WWWapi& api, dbDatabase& dbase, int nThreads, int connectionQueueLen): db(dbase){ assert(nThreads >= 1 && connectionQueueLen >= 1); this->nThreads = nThreads; go.open(); done.open(); threads = new dbThread[nThreads]; while (--nThreads >= 0) { threads[nThreads].create(handleThread, this); threads[nThreads].detach(); } connectionPool = new WWWconnection[connectionQueueLen]; connectionPool[--connectionQueueLen].next = NULL; while (--connectionQueueLen >= 0) { connectionPool[connectionQueueLen].next = &connectionPool[connectionQueueLen+1]; } freeList = connectionPool; waitList = NULL; server = &api;}void QueueManager::start(){ mutex.lock(); while (server != NULL) { if (freeList == NULL) { done.reset(); done.wait(mutex); if (server == NULL) { break; } assert(freeList != NULL); } WWWconnection* con = freeList; freeList = con->next; WWWapi* srv = server; mutex.unlock(); if (!srv->connect(*con) || server == NULL) { return; } mutex.lock(); con->next = waitList; waitList = con; go.signal(); } mutex.unlock();}void QueueManager::handle(){ db.attach(); mutex.lock(); while (true) { go.wait(mutex); WWWapi* api = server; if (api == NULL) { break; } WWWconnection* con = waitList; assert(con != NULL); waitList = con->next; mutex.unlock(); if (!api->serve(*con)) { stop(); } mutex.lock(); if (freeList == NULL) { done.signal(); } con->next = freeList; freeList = con; } mutex.unlock(); db.detach();}void QueueManager::stop() { mutex.lock(); WWWapi* server = this->server; this->server = NULL; server->cancel(); while (--nThreads >= 0) { go.signal(); } done.signal(); mutex.unlock();}QueueManager::~QueueManager(){ go.close(); done.close(); delete[] threads; delete[] connectionPool;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -