pico-http/http/http.c
Andrew Gundersen 9904bd2212 init commit
2022-05-02 08:00:44 -05:00

137 lines
2.4 KiB
C

/**
* 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;
}