summaryrefslogblamecommitdiffstats
path: root/api/c/api.c
blob: e452617a575eb2d107fbde05e8684e1379195dbd (plain) (tree)



















































































































































































































































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