init commit
This commit is contained in:
commit
9904bd2212
16 changed files with 846 additions and 0 deletions
25
http/Makefile
Normal file
25
http/Makefile
Normal 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
137
http/http.c
Normal 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
31
http/http.h
Normal 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
62
http/listen.c
Normal 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
6
http/listen.h
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
#ifndef _LISTEN_H_
|
||||
#define _LISTEN_H_
|
||||
|
||||
int init_server_socket(char *port);
|
||||
|
||||
#endif
|
||||
48
http/main.c
Normal file
48
http/main.c
Normal 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);
|
||||
}
|
||||
Loading…
Reference in a new issue