bench_app.c 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. /*
  2. This is an incomplete example meant to be used as a benchmark application for
  3. the TechEmpower Framework Benchmarks. See:
  4. http://frameworkbenchmarks.readthedocs.io/en/latest/
  5. At the moment it's incomplete and might be broken.
  6. */
  7. #include "http.h"
  8. #include "fio_cli.h"
  9. #include "fio_hashmap.h"
  10. /* *****************************************************************************
  11. Internal Helpers
  12. ***************************************************************************** */
  13. /* initialize CLI helper and manage it's default options */
  14. static void cli_init(int argc, char const *argv[]);
  15. /* cleanup any leftovers */
  16. static void cleanup(void);
  17. /* reusable objects */
  18. static FIOBJ HTTP_HEADER_SERVER;
  19. static FIOBJ HTTP_VALUE_SERVER;
  20. static FIOBJ JSON_KEY;
  21. static FIOBJ JSON_VALUE;
  22. /* *****************************************************************************
  23. Routing
  24. ***************************************************************************** */
  25. /* adds a route to our simple router */
  26. static void route_add(char *path, void (*handler)(http_s *));
  27. /* routes a request to the correct handler */
  28. static void route_perform(http_s *);
  29. /* cleanup for our router */
  30. static void route_clear(void);
  31. /* *****************************************************************************
  32. Request handlers
  33. ***************************************************************************** */
  34. /* handles JSON requests */
  35. static void on_request_json(http_s *h);
  36. /* handles plain text requests (Hello World) */
  37. static void on_request_plain_text(http_s *h);
  38. /* *****************************************************************************
  39. The main function
  40. ***************************************************************************** */
  41. int main(int argc, char const *argv[]) {
  42. /* initialize the CLI helper and options */
  43. cli_init(argc, argv);
  44. /* sertup routes */
  45. route_add("/json", on_request_json);
  46. route_add("/plaintext", on_request_plain_text);
  47. /* Server name and header */
  48. HTTP_HEADER_SERVER = fiobj_str_new("server", 6);
  49. HTTP_VALUE_SERVER = fiobj_strprintf("facil.io %u.%u.%u", FACIL_VERSION_MAJOR,
  50. FACIL_VERSION_MINOR, FACIL_VERSION_PATCH);
  51. /* JSON values to be serialized */
  52. JSON_KEY = fiobj_str_new("message", 7);
  53. JSON_VALUE = fiobj_str_new("Hello, World!", 13);
  54. /* Test for static file service */
  55. const char *public_folder = fio_cli_get_str("www");
  56. if (public_folder) {
  57. fprintf(stderr, "* serving static files from:%s\n", public_folder);
  58. }
  59. /* listen to HTTP connections */
  60. http_listen(fio_cli_get_str("port"), fio_cli_get_str("address"),
  61. .on_request = route_perform, .public_folder = public_folder,
  62. .log = fio_cli_get_int("log"));
  63. /* Start the facil.io reactor */
  64. facil_run(.threads = fio_cli_get_int("t"), .processes = fio_cli_get_int("w"));
  65. /* perform cleanup */
  66. cleanup();
  67. return 0;
  68. }
  69. /* *****************************************************************************
  70. Request handlers
  71. ***************************************************************************** */
  72. /* handles JSON requests */
  73. static void on_request_json(http_s *h) {
  74. http_set_header(h, HTTP_HEADER_CONTENT_TYPE, http_mimetype_find("json", 4));
  75. FIOBJ json;
  76. /* create a new Hash to be serialized for every request */
  77. FIOBJ hash = fiobj_hash_new();
  78. fiobj_hash_set(hash, JSON_KEY, fiobj_dup(JSON_VALUE));
  79. json = fiobj_obj2json(hash, 0);
  80. fiobj_free(hash);
  81. fio_cstr_s tmp = fiobj_obj2cstr(json);
  82. http_send_body(h, tmp.data, tmp.len);
  83. fiobj_free(json);
  84. }
  85. /* handles plain text requests (Hello World) */
  86. static void on_request_plain_text(http_s *h) {
  87. http_set_header(h, HTTP_HEADER_CONTENT_TYPE, http_mimetype_find("txt", 3));
  88. http_send_body(h, "Hello, World!", 13);
  89. }
  90. /* *****************************************************************************
  91. CLI
  92. ***************************************************************************** */
  93. /* initialize CLI helper and manage it's default options */
  94. static void cli_init(int argc, char const *argv[]) {
  95. fio_cli_start(argc, argv,
  96. "This is a facil.io framework benchmark application.\n"
  97. "\nFor details about the benchmarks visit:\n"
  98. "http://frameworkbenchmarks.readthedocs.io/en/latest/\n"
  99. "\nThe following arguments are supported:");
  100. fio_cli_accept_num("threads t",
  101. "The number of threads to use. System dependent default.");
  102. fio_cli_accept_num(
  103. "workers w", "The number of processes to use. System dependent default.");
  104. fio_cli_accept_num(
  105. "port p", "The port number to listen to (set to 0 for Unix Sockets.");
  106. fio_cli_accept_str("address b", "The address to bind to.");
  107. fio_cli_accept_str("public www",
  108. "A public folder for serve an HTTP static file service.");
  109. fio_cli_accept_bool("log v", "Turns logging on (logs to terminal).");
  110. fio_cli_accept_str("database db", "The database adrress.");
  111. fio_cli_accept_num("database-port dbp", "The database port.");
  112. /* setup default port */
  113. if (!fio_cli_get_str("p"))
  114. fio_cli_set_str("p", "8080");
  115. /* setup database address */
  116. if (!fio_cli_get_str("db")) {
  117. char *database = getenv("DBHOST");
  118. if (!database)
  119. database = "localhost";
  120. fio_cli_set_str("db", database);
  121. }
  122. /* setup database port - default for Redis */
  123. if (!fio_cli_get_str("dbp"))
  124. fio_cli_set_str("dbp", "6379");
  125. }
  126. /* *****************************************************************************
  127. Routing
  128. ***************************************************************************** */
  129. /* the router is a simple hash map */
  130. static fio_hash_s routes;
  131. /* adds a route to our simple router */
  132. static void route_add(char *path, void (*handler)(http_s *)) {
  133. /* add handler to the hash map */
  134. size_t len = strlen(path);
  135. uint64_t hash = fio_siphash(path, len);
  136. fio_hash_insert(&routes, hash, (void *)(uintptr_t)handler);
  137. }
  138. /* routes a request to the correct handler */
  139. static void route_perform(http_s *h) {
  140. /* add required Serevr header */
  141. http_set_header(h, HTTP_HEADER_SERVER, fiobj_dup(HTTP_VALUE_SERVER));
  142. /* collect path from hash map */
  143. fio_cstr_s tmp = fiobj_obj2cstr(h->path);
  144. uint64_t hash = fio_siphash(tmp.data, tmp.len);
  145. void (*handler)(http_s *) =
  146. (void (*)(http_s *))(uintptr_t)fio_hash_find(&routes, hash);
  147. /* forward request or send error */
  148. if (handler) {
  149. handler(h);
  150. return;
  151. }
  152. http_send_error(h, 404);
  153. }
  154. /* cleanup for our router */
  155. static void route_clear(void) { fio_hash_free(&routes); }
  156. /* *****************************************************************************
  157. Cleanup
  158. ***************************************************************************** */
  159. /* cleanup any leftovers */
  160. static void cleanup(void) {
  161. fio_cli_end();
  162. fiobj_free(HTTP_HEADER_SERVER);
  163. fiobj_free(HTTP_VALUE_SERVER);
  164. fiobj_free(JSON_KEY);
  165. fiobj_free(JSON_VALUE);
  166. route_clear();
  167. }