Full rewrite
This commit is contained in:
@@ -1,51 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include <stdlib.h>
|
||||
#include "../tinyhttp.h"
|
||||
|
||||
sig_atomic_t should_exit = 0;
|
||||
|
||||
static void
|
||||
signal_handler(int sig)
|
||||
{
|
||||
if (sig == SIGINT)
|
||||
should_exit = 1;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
signal(SIGINT, signal_handler);
|
||||
|
||||
TinyHTTPServerConfig config = {
|
||||
.reuse = 1,
|
||||
.plain_addr = "127.0.0.1",
|
||||
.plain_port = 8080,
|
||||
.plain_backlog = 32,
|
||||
};
|
||||
|
||||
TinyHTTPServer *server = tinyhttp_server_init(config);
|
||||
if (server == NULL)
|
||||
return -1;
|
||||
|
||||
while (!should_exit) {
|
||||
|
||||
int ret;
|
||||
TinyHTTPRequest *req;
|
||||
TinyHTTPResponse res;
|
||||
|
||||
ret = tinyhttp_server_wait(server, &req, &res, 1000);
|
||||
if (ret < 0) return -1; // Error
|
||||
if (ret > 0) continue; // Timeout
|
||||
|
||||
tinyhttp_response_status(res, 200);
|
||||
tinyhttp_response_body(res, "Hello, world!", -1);
|
||||
|
||||
//tinyhttp_response_undo(res);
|
||||
//tinyhttp_response_status(res, 500);
|
||||
|
||||
tinyhttp_response_send(res);
|
||||
}
|
||||
|
||||
tinyhttp_server_free(server);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,271 +0,0 @@
|
||||
#include <stdio.h>
|
||||
#include <signal.h>
|
||||
#include "../tinyhttp.h"
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// CONFIGURATION
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
// Network stuff
|
||||
#define ADDR "127.0.0.1"
|
||||
#define PORT 8080
|
||||
#define REUSE 1
|
||||
#define BACKLOG 32
|
||||
|
||||
// Social stuff
|
||||
#define MAX_USERS 32
|
||||
#define MAX_POSTS 32
|
||||
#define MAX_USERNAME 128
|
||||
#define MAX_PASSWORD 256
|
||||
#define MAX_BIO 512
|
||||
#define MAX_CONTENT 512
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// UTILITIES
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef struct {
|
||||
char *ptr;
|
||||
ptrdiff_t len;
|
||||
} string;
|
||||
|
||||
#define S(X) ((string) {(X), sizeof(X)-1})
|
||||
|
||||
static string trim(string s)
|
||||
{
|
||||
int i = 0;
|
||||
while (i < s.len && (s.ptr[i] == ' ' || s.ptr[i] == '\t'))
|
||||
i++;
|
||||
|
||||
if (i == s.len) {
|
||||
s.ptr = NULL;
|
||||
s.len = 0;
|
||||
} else {
|
||||
s.ptr += i;
|
||||
s.len -= i;
|
||||
while (s.ptr[s.len-1] == ' ' || s.ptr[s.len-1] == '\n')
|
||||
s.len--;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static int copy(string src, string *dst, char *mem, int cap)
|
||||
{
|
||||
if (src.len > cap)
|
||||
return -1;
|
||||
memcpy(mem, src.ptr, src.len);
|
||||
dst->ptr = mem;
|
||||
dst->len = src.len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// BUSINESS LOGIC
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
typedef struct {
|
||||
string name;
|
||||
string pass;
|
||||
string bio;
|
||||
char name_mem[MAX_USERNAME];
|
||||
char pass_mem[MAX_PASSWORD];
|
||||
char bio_mem[MAX_BIO];
|
||||
} User;
|
||||
|
||||
typedef struct {
|
||||
int id;
|
||||
string author;
|
||||
string content;
|
||||
char author_mem[MAX_USERNAME];
|
||||
char content_mem[MAX_CONTENT];
|
||||
} Post;
|
||||
|
||||
static User users[MAX_USERS];
|
||||
static int user_count = 0;
|
||||
|
||||
static Post posts[MAX_POSTS];
|
||||
static int posts_head = 0;
|
||||
static int posts_count = 0;
|
||||
|
||||
static void init_users_and_posts(void)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
static int find_user(string name)
|
||||
{
|
||||
for (int i = 0; i < user_count; i++)
|
||||
if (streq(name, users[i].name))
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int create_user(string name, string pass)
|
||||
{
|
||||
name = trim(name);
|
||||
pass = trim(pass);
|
||||
|
||||
if (name.len == 0 || pass.len == 0)
|
||||
return -1;
|
||||
|
||||
if (find_user(name) != -1)
|
||||
return -1;
|
||||
|
||||
if (user_count == MAX_USERS)
|
||||
return -1;
|
||||
|
||||
User *user = &users[user_count];
|
||||
|
||||
if (copy(name, &user->name, user->name_mem, sizeof(user->name_mem)) < 0 &&
|
||||
copy(pass, &user->pass, user->pass_mem, sizeof(user->pass_mem)) < 0)
|
||||
return -1;
|
||||
|
||||
user_count++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int delete_user(string name)
|
||||
{
|
||||
int i = find_user(name);
|
||||
if (i == -1)
|
||||
return -1;
|
||||
|
||||
// TODO
|
||||
}
|
||||
|
||||
static int create_post(string author, string content)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
static int delete_post(int id)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
static int modify_post(int id, string new_content)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// ENDPOINTS
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
#define MAX_SESSIONS 32
|
||||
|
||||
typedef struct {
|
||||
int id;
|
||||
string name;
|
||||
char name_mem[MAX_USERNAME];
|
||||
} Session;
|
||||
|
||||
static Session sessions[MAX_SESSIONS];
|
||||
static int session_count = 0;
|
||||
|
||||
static void init_sessions(void)
|
||||
{
|
||||
for (int i = 0; i < MAX_SESSIONS; i++)
|
||||
sessions[i].id = -1;
|
||||
}
|
||||
|
||||
static int find_session(int id)
|
||||
{
|
||||
for (int i = 0; i < MAX_SESSIONS; i++)
|
||||
if (sessions[i].id == id)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int create_session(string name)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
static int delete_session(string name)
|
||||
{
|
||||
// TODO
|
||||
}
|
||||
|
||||
// TODO
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
// ENTRY POINT
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
static sig_atomic_t should_exit = 0;
|
||||
|
||||
static void
|
||||
signal_handler(int sig)
|
||||
{
|
||||
if (sig == SIGINT)
|
||||
should_exit = 1;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
signal(SIGINT, signal_handler);
|
||||
|
||||
init_users_and_posts();
|
||||
init_sessions();
|
||||
|
||||
TinyHTTPServerConfig config = {
|
||||
.reuse = REUSE,
|
||||
.plain_addr = ADDR,
|
||||
.plain_port = PORT,
|
||||
.plain_backlog = BACKLOG,
|
||||
};
|
||||
|
||||
TinyHTTPServer *server = tinyhttp_server_init(config);
|
||||
if (server == NULL)
|
||||
return -1;
|
||||
|
||||
while (!should_exit) {
|
||||
|
||||
int ret;
|
||||
TinyHTTPRequest *req;
|
||||
TinyHTTPResponse res;
|
||||
|
||||
ret = tinyhttp_server_wait(server, &req, &res, 1000);
|
||||
if (ret < 0) return -1; // Error
|
||||
if (ret > 0) continue; // Timeout
|
||||
|
||||
char path_mem[1<<10];
|
||||
TinyHTTPString path;
|
||||
if (tinyhttp_normalizepath(req->path, &path, path_mem, sizeof(path_mem)) < 0) {
|
||||
tinyhttp_response_status(res, 200);
|
||||
tinyhttp_response_send(res);
|
||||
continue;
|
||||
}
|
||||
|
||||
TinyHTTPString sessid = tinyhttp_getcookie(req, TINYHTTP_STRING("sessid"));
|
||||
|
||||
if (tinyhttp_streq(path, TINYHTTP_STRING("/users"))) {
|
||||
tinyhttp_response_status(res, 200);
|
||||
tinyhttp_response_body(res, "<html><head><title>Users</title></head><body><ul>", -1);
|
||||
for (int i = 0; i < user_count; i++)
|
||||
tinyhttp_response_body(res, "<li><a href=\"/users/???\">???</a></li>", -1);
|
||||
tinyhttp_response_body(res, "</ul></body></html>", -1);
|
||||
tinyhttp_response_send(res);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (tinyhttp_streq(path, TINYHTTP_STRING("/posts"))) {
|
||||
tinyhttp_response_status(res, 200);
|
||||
tinyhttp_response_body(res, "<html><head><title>Posts</title></head><body><ul>", -1);
|
||||
for (int i = 0; i < user_count; i++)
|
||||
tinyhttp_response_body(res, "<li><a href=\"/posts/???\">???</a></li>", -1);
|
||||
tinyhttp_response_body(res, "</ul></body></html>", -1);
|
||||
tinyhttp_response_send(res);
|
||||
continue;
|
||||
}
|
||||
|
||||
tinyhttp_response_status(res, 404);
|
||||
tinyhttp_response_body(res, "<html><head><title>Not Found</title></head><body>Nothing here!</body></html>", -1);
|
||||
tinyhttp_response_send(res);
|
||||
}
|
||||
|
||||
tinyhttp_server_free(server);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
#include "../tinyhttp.h"
|
||||
|
||||
// TODO: Complete this example
|
||||
|
||||
int main(void)
|
||||
{
|
||||
SOCKET listen_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (listen_fd == INVALID_SOCKET)
|
||||
return -1;
|
||||
|
||||
for (;;) {
|
||||
|
||||
SOCKET client_fd = accept(listen_fd, NULL, NULL);
|
||||
if (client_fd == INVALID_SOCKET)
|
||||
continue;
|
||||
|
||||
TinyHTTPStream stream;
|
||||
tinyhttp_stream_init(&stream, memfunc, NULL);
|
||||
|
||||
int state = tinyhttp_stream_state(&stream);
|
||||
while (!(state & TINYHTTP_STREAM_READY)) {
|
||||
|
||||
ASSERT(state & TINYHTTP_STREAM_RECV);
|
||||
|
||||
char *dst;
|
||||
ptrdiff_t cap;
|
||||
|
||||
dst = tinyhttp_stream_recv_buf(&stream, &cap);
|
||||
|
||||
int ret = recv(client_fd, dst, cap, 0);
|
||||
if (ret < 0) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
tinyhttp_stream_recv_ack(&stream, ret);
|
||||
state = tinyhttp_stream_state(&stream);
|
||||
}
|
||||
|
||||
TinyHTTPRequest *request = tinyhttp_stream_request(&stream);
|
||||
|
||||
tinyhttp_stream_response_status(&stream, 200);
|
||||
tinyhttp_stream_response_body(&stream, "Hello, world!", -1);
|
||||
tinyhttp_stream_response_send(&stream);
|
||||
|
||||
while (state & TINYHTTP_STREAM_SEND) {
|
||||
|
||||
char *src;
|
||||
ptrdiff_t len;
|
||||
|
||||
src = tinyhttp_stream_send_buf(&stream, &len);
|
||||
|
||||
int ret = send(client_fd, src, len, 0);
|
||||
if (ret < 0) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
tinyhttp_stream_send_ack(&stream, ret);
|
||||
state = tinyhttp_stream_state(&stream);
|
||||
}
|
||||
|
||||
tinyhttp_stream_free(&stream);
|
||||
CLOSESOCKET(client_fd);
|
||||
}
|
||||
|
||||
CLOSESOCKET(listen_fd);
|
||||
return 0;
|
||||
}
|
||||
@@ -1,107 +0,0 @@
|
||||
#include <assert.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#include <winsock2.h>
|
||||
#define CLOSESOCKET closesocket
|
||||
#elif defined(__linux__)
|
||||
#include <unistd.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#include <arpa/inet.h>
|
||||
#define CLOSESOCKET close
|
||||
#else
|
||||
#error "Only Windows and Linux are supported"
|
||||
#endif
|
||||
|
||||
#include "../tinyhttp.h"
|
||||
|
||||
#define PORT 8080
|
||||
#define ADDR "127.0.0.1"
|
||||
|
||||
// TODO: Complete this
|
||||
|
||||
void respond(TinyHTTPStream *stream)
|
||||
{
|
||||
TinyHTTPRequest *req = tinyhttp_stream_request(stream);
|
||||
if (req->method != TINYHTTP_METHOD_GET)
|
||||
tinyhttp_stream_response_status(stream, 405);
|
||||
else
|
||||
tinyhttp_stream_response_status(stream, 200);
|
||||
tinyhttp_stream_response_send(stream);
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int listen_fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
|
||||
struct sockaddr_in buf;
|
||||
buf.sin_family = AF_INET;
|
||||
buf.sin_port = htons(PORT);
|
||||
buf.sin_addr.s_addr = inet_addr(ADDR);
|
||||
bind(listen_fd, (struct sockaddr*) &buf, sizeof(buf));
|
||||
|
||||
listen(listen_fd, 32);
|
||||
|
||||
int num_conns = 0;
|
||||
int fds[1000];
|
||||
TinyHTTPStream streams[1000];
|
||||
|
||||
for (int i = 0; i < 1000; i++)
|
||||
fds[i] = -1;
|
||||
|
||||
for (;;) {
|
||||
// TODO: timeouts
|
||||
|
||||
fd_set readset;
|
||||
fd_set writeset;
|
||||
FD_ZERO(&readset);
|
||||
FD_ZERO(&writeset);
|
||||
|
||||
FD_SET(listen_fd, &readset);
|
||||
int max_fd = listen_fd;
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
if (fds[i] == -1) continue;
|
||||
int state = tinyhttp_stream_state(&streams[i]);
|
||||
if (state & TINYHTTP_STREAM_RECV)
|
||||
FD_SET(fds[i], &readset);
|
||||
if (state & TINYHTTP_STREAM_SEND)
|
||||
FD_SET(fds[i], &writeset);
|
||||
if (state & (TINYHTTP_STREAM_RECV | TINYHTTP_STREAM_SEND))
|
||||
if (max_fd < fds[i]) max_fd = fds[i];
|
||||
}
|
||||
|
||||
int num = select(max_fd+1, &readset, &writeset, NULL, NULL);
|
||||
|
||||
if (FD_ISSET(listen_fd, &readset)) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
int ready_queue[1000];
|
||||
int ready_head = 0;
|
||||
int ready_count = 0;
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
// TODO
|
||||
}
|
||||
|
||||
while (ready_count > 0) {
|
||||
|
||||
int idx = ready_queue[ready_head];
|
||||
TinyHTTPStream *stream = &streams[idx];
|
||||
|
||||
TinyHTTPRequest *req = tinyhttp_stream_request(stream);
|
||||
assert(req);
|
||||
|
||||
respond(stream);
|
||||
|
||||
ready_head = (ready_head + 1) % 1000;
|
||||
ready_count--;
|
||||
if (tinyhttp_stream_request(stream)) {
|
||||
ready_queue[(ready_head + ready_count) % 1000] = idx;
|
||||
ready_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CLOSESOCKET(listen_fd);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user