http-server.c

Basic HTTP server and router in C
git clone git://git.finwo.net/lib/http-server.c
Log | Files | Refs | README

example.c (3633B)


      1 #include <stdbool.h>
      2 #include <stdio.h>
      3 #include <stdlib.h>
      4 #include <string.h>
      5 
      6 #include "finwo/fnet.h"
      7 #include "finwo/http-parser.h"
      8 #include "pierreguillot/thread.h"
      9 #include "tidwall/buf.h"
     10 
     11 
     12 #include "http-server.h"
     13 
     14 uint16_t targetPort = 8080;
     15 
     16 void onServing(char *addr, uint16_t port, void *udata) {
     17   printf("Serving at %s:%d\n", addr, port);
     18 }
     19 
     20 const int countDownOrg = 20;
     21 int       countDown    = countDownOrg;
     22 void onTick(void *udata) {
     23   struct http_server_opts *opts = udata;
     24 
     25   // Handle auto-shutdown
     26   printf("Shutdown in %d second(s)\n", --countDown);
     27   if (countDown <= 0) {
     28     opts->shutdown = true;
     29     fnet_shutdown();
     30     return;
     31   }
     32 
     33   // Handle port re-assign
     34   if (opts->port != targetPort) {
     35     opts->port = targetPort;
     36     fnet_close(opts->listen_connection);
     37   }
     38 
     39 }
     40 
     41 void route_get_hello(struct http_server_reqdata *reqdata) {
     42   http_parser_header_set(reqdata->reqres->response, "Content-Type", "text/plain");
     43   reqdata->reqres->response->body       = calloc(1, sizeof(struct buf));
     44   reqdata->reqres->response->body->data = strdup("Hello World\n");
     45   reqdata->reqres->response->body->len  = strlen(reqdata->reqres->response->body->data);
     46   http_server_response_send(reqdata, true);
     47   countDown = countDownOrg;
     48   return;
     49 }
     50 
     51 void route_get_hello_named(struct http_server_reqdata *reqdata) {
     52   http_parser_header_set(reqdata->reqres->response, "Content-Type", "text/plain");
     53 
     54   const char *name = http_parser_meta_get(reqdata->reqres->request, "param:name");
     55   if (!name) name = "there";
     56 
     57   reqdata->reqres->response->body       = calloc(1, sizeof(struct buf));
     58   reqdata->reqres->response->body->data = calloc(7 + strlen(name), sizeof(char));
     59   strcat(reqdata->reqres->response->body->data, "Hello ");
     60   strcat(reqdata->reqres->response->body->data, name);
     61   reqdata->reqres->response->body->len  = strlen(reqdata->reqres->response->body->data);
     62   http_server_response_send(reqdata, true);
     63   countDown = countDownOrg;
     64   return;
     65 }
     66 
     67 void route_post_port(struct http_server_reqdata *reqdata) {
     68   http_parser_header_set(reqdata->reqres->response, "Content-Type", "text/plain");
     69   targetPort = atoi(reqdata->reqres->request->body->data);
     70   reqdata->reqres->response->body       = calloc(1, sizeof(struct buf));
     71   reqdata->reqres->response->body->data = strdup("OK\n");
     72   reqdata->reqres->response->body->len  = strlen(reqdata->reqres->response->body->data);
     73   http_server_response_send(reqdata, true);
     74   return;
     75 }
     76 
     77 void route_404(struct http_server_reqdata *reqdata) {
     78   http_parser_header_set(reqdata->reqres->response, "Content-Type", "text/plain");
     79   reqdata->reqres->response->status     = 404;
     80   reqdata->reqres->response->body       = calloc(1, sizeof(struct buf));
     81   reqdata->reqres->response->body->data = strdup("not found\n");
     82   reqdata->reqres->response->body->len  = strlen(reqdata->reqres->response->body->data);
     83   http_server_response_send(reqdata, true);
     84   return;
     85 }
     86 
     87 int main() {
     88   struct http_server_events evs = {
     89     .serving  = onServing,
     90     .close    = NULL,
     91     .notFound = route_404,
     92     .tick     = onTick,
     93   };
     94   struct http_server_opts opts = {
     95     .evs   = &evs,
     96     .addr  = "0.0.0.0",
     97     .port  = targetPort,
     98     .udata = &opts,
     99   };
    100 
    101   http_server_route("GET" , "/hello"      , route_get_hello);
    102   http_server_route("POST", "/port"       , route_post_port);
    103   http_server_route("GET" , "/hello/:name", route_get_hello_named);
    104 
    105   /* // Launch network management thread */
    106   /* thd_thread thread; */
    107   /* thd_thread_detach(&thread, fnet_thread, NULL); */
    108 
    109   http_server_main(&opts);
    110   fnet_shutdown();
    111 
    112   /* thd_thread_join(&thread); */
    113 
    114   printf("Server has shut down\n");
    115 }