init commit

This commit is contained in:
Andrew Gundersen 2022-05-02 08:00:44 -05:00
commit 9904bd2212
16 changed files with 846 additions and 0 deletions

25
http/Makefile Normal file
View file

@ -0,0 +1,25 @@
CC=gcc
CFLAGS=-Wall -Wextra
OBJS=test.o http.o net.o hashtable.o llist.o
all: test
test: $(OBJS)
gcc -o $@ $^
test.o: test.c http.h
http.o: http.c http.h
net.o: net.c net.h
hashtable.o: hashtable.c hashtable.h
llist.o: llist.c llist.h
clean:
rm -f $(OBJS)
rm -f test
.PHONY: all, clean

137
http/http.c Normal file
View file

@ -0,0 +1,137 @@
/**
* http.c - Basic HTTP framework implentation
*
* hashtable.c for routing
* listen.c for socket creation
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include "hashtable.h"
#include "listen.h"
#include "http.h"
#define BUF_SIZE 65536
#define HTTP_RES "HTTP/1.1 %d MESSAGE\n"\
"Connection: close\n"\
"Content-Length: %d\n"\
"Content-Type: %s\n"\
"\n"\
"%s"
HT* routes;
void use(char* path, Handler handler)
{
if (routes == NULL)
{
routes = ht_create();
}
// TODO: handle for key exist
ht_put(routes, path, (void*) handler);
}
void send_response(int client, Res* res)
{
char res_raw[BUF_SIZE];
sprintf( res_raw,
HTTP_RES,
res->status,
res->content_length,
res->content_type,
res->body) ;
int num_sent = send(client, res_raw, strlen(res_raw), 0);
if (num_sent < 0)
{
perror("send");
}
}
void fallback_handler(Res* res)
{
char* content = "Bad request\n";
res->status = 400;
res->content_length = strlen(content);
res->content_type = "text/html";
res->body = content;
}
void parse_req_raw(char* raw, Req* req)
{
printf("%s\n", raw);
sscanf(raw, "%s %s", req->type, req->path);
}
void handle_request(int client)
{
char req_raw[BUF_SIZE];
Req req;
Res res;
int num_recvd = recv(client, req_raw, BUF_SIZE - 1, 0);
if (num_recvd < 0)
{
perror("recv");
return;
}
parse_req_raw(req_raw, &req); // TODO: handle for parse.
printf("Request: %s, %s\n", req.type, req.path);
Handler handler = ht_get(routes, req.path);
if (handler == NULL)
{
fallback_handler(&res);
}
else
{
handler(&req, &res);
}
send_response(client, &res);
}
int http_start(char* port)
{
int client, server;
if ((server = init_server_socket(port)) < 0)
{
puts("Error when establishing the server.");
exit(1);
}
printf("Waiting for connections on port %s...\n", port);
while(1)
{
client = accept(server, (struct sockaddr*) NULL, NULL);
if (client == -1)
{
perror("accept");
continue;
}
printf("Client connected.\n");
handle_request(client);
close(client);
}
return 0;
}

31
http/http.h Normal file
View file

@ -0,0 +1,31 @@
#ifndef _HTTP_H_
#define _HTTP_H_
#define PORT "3000"
typedef struct
{
char type[100];
char path[200];
}
Req;
typedef struct
{
int status;
char* content_type;
int content_length;
char* body;
}
Res;
/* User defined handlers must be this shape */
typedef void (*Handler)(Req* req, Res* res);
/* Add an api endpoint */
void use(char* path, Handler handler);
/* Start the server */
int http_start(char* port);
#endif

62
http/listen.c Normal file
View file

@ -0,0 +1,62 @@
/**
* listen.c - Create and bind a server socket to a port
*
*/
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <sys/socket.h>
#include "listen.h"
#define QUEUE 8
int init_server_socket(char* port)
{
int fd, yes = 1;
struct addrinfo hints, *servinfo, *p;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE;
getaddrinfo(NULL, port, &hints, &servinfo);
for (p = servinfo; p != NULL; p = p->ai_next)
{
if ((fd = socket(p->ai_family, p->ai_socktype, p->ai_protocol)) == -1)
{
continue;
}
if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) == -1)
{
close(fd);
freeaddrinfo(servinfo);
return -1;
}
if (bind(fd, p->ai_addr, p->ai_addrlen) == -1)
{
close(fd);
continue;
}
break;
}
freeaddrinfo(servinfo);
if (p == NULL) { return -1; }
if (listen(fd, QUEUE) == -1)
{
close(fd);
return -1;
}
return fd;
}

6
http/listen.h Normal file
View file

@ -0,0 +1,6 @@
#ifndef _LISTEN_H_
#define _LISTEN_H_
int init_server_socket(char *port);
#endif

48
http/main.c Normal file
View file

@ -0,0 +1,48 @@
/**
* main.c - HTTP server that uses http.c framework
*
* curl http://localhost:3000/api/login
*
*/
#include <stdio.h>
#include <string.h>
#include "http.h"
void login(Req* req, Res* res)
{
(void) req;
char* content = "Login works!\n";
res->status = 200;
res->content_length = strlen(content);
res->content_type = "text/html";
res->body = content;
}
void signup(Req* req, Res* res)
{
(void) req;
char* content = "Sign Up works!\n";
res->status = 200;
res->content_length = strlen(content);
res->content_type = "text/html";
res->body = content;
}
/**
* Register the endpoints and start the server.
*/
int main(void)
{
puts("Registering endpoints");
use("/signup", &signup);
use("/login", &login);
http_start(PORT);
}