diff options
Diffstat (limited to 'api/c/api.c')
-rw-r--r-- | api/c/api.c | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/api/c/api.c b/api/c/api.c new file mode 100644 index 0000000..e452617 --- /dev/null +++ b/api/c/api.c @@ -0,0 +1,244 @@ +/* + * threaded.c -- A simple multi-threaded FastCGI application. + */ + +#ifndef lint +// static const char rcsid[] = "$Id: threaded.c,v 1.9 2001/11/20 03:23:21 robs Exp $"; // just popps up warnings +#endif /* not lint */ + +#include "fcgi_config.h" + +#include <pthread.h> +#include <sys/types.h> + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include "fcgiapp.h" + +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include "urlcode.c" +#include <limits.h> +#include <stdio.h> +#define MALLOC_RETURNED_NULL fprintf(stderr, "%s()@" __FILE__ ":%d: malloc() returned NULL\n", __func__, __LINE__); + + +#define THREAD_COUNT 20 + +static int counts[THREAD_COUNT]; + +struct assoc_s { + char * key; + char * value; +}; // value je lahko NULL + +void free_assoc_s(struct assoc_s * s) { + if (s->key != NULL) { + free(s->key); + s->key = NULL; + } + if (s->value != NULL) { + free(s->value); + s->value = NULL; + } + free(s); + s = NULL; + return; +} + +struct request_uri_s { + char * path; + struct assoc_s ** params; // to je "array". zadnji naj bo NULL. +}; + +void free_request_uri_s(struct request_uri_s * s) { + int unsigned i = 0; + while (s->params[i] != NULL) { + free_assoc_s(s->params[i]); + s->params[i++] = NULL; + } + free(s->path); + s->path = NULL; + free(s->params); + s->params = NULL; + free(s); + s = NULL; + return; +} + +struct assoc_s ** parse_html_keyvalue(const char * t) { + struct assoc_s ** params = malloc(sizeof(void *)); + if (params == NULL) { + MALLOC_RETURNED_NULL + return NULL; + } + unsigned int o = 0; // številka parametra od 0 vključno z 0 + unsigned int n = 0; // 0 če smo v key, 1 če smo v value, 3 če je konec urija + unsigned int a = 0; // nakazuje pozicijo naslednjega znaka, ki ga bomo napisa. + params[0] = malloc(sizeof(struct assoc_s)); + if (params[0] == NULL) { + MALLOC_RETURNED_NULL + return NULL; + } + for (unsigned int e = 0; n != 3 && e <= UINT_MAX; e++) { + switch (t[e]) { + case '\0': + params = realloc(params, sizeof(struct assoc_s)*(o+1)); + if (params == NULL) { + MALLOC_RETURNED_NULL + return NULL; + } // zadnji mora biti null + params[o+1] = NULL; + n = 3; + break; + case '=': + if (n == 0) { // ni treba mallocat, realloca se pred vsakim writom bajta + n = 1; + a = 0; + } else { // this is some undocumented behaviour, adding = to param value + params[o]->value = realloc(params[o]->value, a+1); + if (params[o]->value == NULL) { + MALLOC_RETURNED_NULL + return NULL; + } + params[o]->value[a++] = '='; + } + break; + case '&': // tu je treba mallocat, ker assoc_s še ne obstaja za naslednji + n = 0; + a = 0; + o++; + params = realloc(params, sizeof(struct assoc_s)*(o+1)); + if (params == NULL) { + MALLOC_RETURNED_NULL + return NULL; + } + params[o] = malloc(sizeof(struct assoc_s)); // value kasneje + if (params[o] == NULL) { + MALLOC_RETURNED_NULL + return NULL; + } + break; + default: + if (n == 0) { + params[o]->key = realloc(params[o]->key, a+1); + if (params[o]->key == NULL) { + MALLOC_RETURNED_NULL + return NULL; + } + params[o]->key[a++] = t[e]; + } else { + params[o]->value = realloc(params[o]->value, a+1); + if (params[o]->value == NULL) { + MALLOC_RETURNED_NULL + return NULL; + } + params[o]->value[a++] = t[e]; + } + break; + } + } + return params; +} + +struct request_uri_s * parse_request_uri(char * uri) { // returns NULL on fail! + struct request_uri_s * parsed = malloc(sizeof(struct request_uri_s)); + if (parsed == NULL) { // and returns pointer to ONE request_uri_s on success^ + MALLOC_RETURNED_NULL + return NULL; + } + char * t = strchr(uri, '?'); // remember to free /\ ! + if (t != NULL) + t[0] = '\0'; // uri vedno vseeno pride ven nespremenjen/popravljen + parsed->path = malloc(sizeof(char)*strlen(uri)+1); //znak po path je itak NULL + if (parsed->path == NULL) { // malloc returna NULL, fucking panic! + if (t != NULL) // popravimo še \0 nazaj na ? + t[0] = '?'; + MALLOC_RETURNED_NULL + return NULL; + } + strncpy(parsed->path, uri, strlen(uri)+1); // torej zadnji znak patha bo NULL + parsed->params = NULL; // če slučajno ni query_stringa in kmalu returnamo + if (t == NULL) // ni query stringa zato je path parse dovoljšen + return parsed; // parsed.params je NULL, to pred uporabo PREVERIMO! + t[0] = '?'; // ker smo prej zaradi strlen in strncpy dali na NULL, sedaj spre. + t++; // da ne začnemo z vprašajem ampak z prvim znakom + parsed->params = parse_html_keyvalue(t); + return parsed; +} + +static void *doit(void *a) { + intptr_t rc, i, thread_id = (intptr_t)a; + pid_t pid = getpid(); + FCGX_Request request; + char *server_name; + char * uri_to_parse; + struct request_uri_s * parseduri; + + FCGX_InitRequest(&request, 0, 0); + + for (;;) { + static pthread_mutex_t accept_mutex = PTHREAD_MUTEX_INITIALIZER; + static pthread_mutex_t counts_mutex = PTHREAD_MUTEX_INITIALIZER; + + /* Some platforms require accept() serialization, some don't.. */ + pthread_mutex_lock(&accept_mutex); + rc = FCGX_Accept_r(&request); + pthread_mutex_unlock(&accept_mutex); + + if (rc < 0) + break; + + server_name = FCGX_GetParam("SERVER_NAME", request.envp); + uri_to_parse = FCGX_GetParam("REQUEST_URI", request.envp); + parseduri = parse_request_uri(uri_to_parse); + if (strchr(parseduri->path, 'S') != NULL) { + exit(0); + } + if (parseduri == NULL) { + FCGX_FPrintF(request.out, "Status: 500 Zaledna napaka\r\n" + "Content-Type: text/plain; charset=utf-8\r\n\r\n" + "zgodila se je napaka na strežniku med procesiranjem URIja.\r\n"); + free_request_uri_s(parseduri); + goto doit_finish; + } + FCGX_FPrintF(request.out, + "Status: 200 V redu\r\n" + "Content-type: text/html; charset=utf-8\r\n" + "\r\n" + "<title>FastCGI Pozdravljen svet! (večnitenje v C, knjižnica fcgiapp)</title>" + "<h1>FastCGI Pozdravljen svet! (večnitenje v C, knjižnica fcgiapp)</h1>" + "Nit %d, Proces %ld<p>" + "Števci zahtev za %d niti na strežniku <i>%s</i><p><code>", + thread_id, pid, + THREAD_COUNT, server_name ? server_name : "?"); + free_request_uri_s(parseduri); + pthread_mutex_lock(&counts_mutex); + ++counts[thread_id]; + for (i = 0; i < THREAD_COUNT; i++) + FCGX_FPrintF(request.out, "%5d " , counts[i]); + pthread_mutex_unlock(&counts_mutex); + +doit_finish: + FCGX_Finish_r(&request); + } + + return NULL; +} + +int main(void) { + intptr_t i; + pthread_t id[THREAD_COUNT]; + + FCGX_Init(); + + for (i = 1; i < THREAD_COUNT; i++) + pthread_create(&id[i], NULL, doit, (void*)i); + + doit(0); // trenutno nit uporabimo tudi kot handler, zakaj pa ne (: + + return 0; +} |