Merge branch 'master' of https://github.com/szmoore/MCTX3420.git
[matches/MCTX3420.git] / testing / fastcgi-approach / fastcgi.c
1 /**
2  * @file fastcgi.c
3  * @purpose Runs the FCGI request loop to handle web interface requests.
4  * 
5  * <stdio.h> should not be included, because these functions are handled by
6  * fcgi_stdio.h. If included, it must be included after fcgi_stdio.h.
7  */
8  
9 #include <fcgi_stdio.h>
10 #include <string.h>
11 #include <stdlib.h>
12
13 /*
14         But the suggestion was: FunctionName, variable_name (local or member),
15     Structure, ENUMVALUE, Extern_FunctionName, g_global
16 */
17
18 enum {STATUS_OK = 200, STATUS_BADREQUEST = 400,
19           STATUS_UNAUTHORIZED = 401};
20
21 typedef void (*ModuleHandler) (void *data, char *params);
22
23 /**
24  * Extracts a key/value pair from a request string.
25  * Note that the input is modified by this function.
26  * @param in The string from which to extract the pair
27  * @param key A pointer to a variable to hold the key string
28  * @param value A pointer to a variable to hold the value string
29  * @return A pointer to the start of the next search location, or NULL if
30  *         the EOL is reached.
31  */
32 char *FCGI_KeyPair(char *in, const char **key, const char **value)
33 {
34         char *ptr;
35         if (!in || !*in) { //Invalid input or string is EOL
36                 return NULL;
37         }
38
39         *key = in;
40         //Find either = or &, whichever comes first
41         if ((ptr = strpbrk(in, "=&"))) {
42                 if (*ptr == '&') { //No value specified
43                         *value = ptr;
44                         *ptr++ = 0;
45                 } else {
46                         //Stopped at an '=' sign
47                         *ptr++ = 0;
48                         *value = ptr;
49                         if ((ptr = strchr(ptr,'&'))) {
50                                 *ptr++ = 0;
51                         } else {
52                                 ptr = "";
53                         }
54                 }
55         } else { //No value specified and no other pair
56                 ptr = "";
57                 *value = ptr;
58         }
59         return ptr;
60 }
61
62 void FCGI_BeginJSON(int status_code, const char *module)
63 {
64         switch (status_code) {
65                 case STATUS_OK:
66                         break;
67                 case STATUS_UNAUTHORIZED:
68                         printf("Status: 401 Unauthorized\r\n");
69                         break;
70                 default:
71                         printf("Status: 400 Bad Request\r\n");
72         }
73         printf("Content-type: application/json; charset=utf-8\r\n\r\n");
74         printf("{\r\n");
75         printf("\t\"module\" : \"%s\"", module);
76 }
77
78 void FCGI_BuildJSON(const char *key, const char *value)
79 {
80         printf(",\r\n\t\"%s\" : \"%s\"", key, value);
81 }
82
83 void FCGI_EndJSON() 
84 {
85         printf("\r\n}\r\n");
86 }
87
88 static void SensorsHandler(void *data, char *params) 
89 {
90         const char *key, *value;
91         
92         //Begin a request only when you know the final result
93         //E.g whether OK or not.
94         FCGI_BeginJSON(STATUS_OK, "sensors");
95         while ((params = FCGI_KeyPair(params, &key, &value))) {
96                 FCGI_BuildJSON(key, value);
97         }
98         FCGI_EndJSON();
99 }
100
101 void FCGI_RequestLoop (void *data)
102 {
103         int count = 0;
104         while (FCGI_Accept() >= 0)   {
105                 ModuleHandler module_handler = NULL;
106                 char module[BUFSIZ], params[BUFSIZ];
107
108                 //strncpy doesn't zero-truncate properly
109                 snprintf(module, BUFSIZ, "%s", getenv("DOCUMENT_URI_LOCAL"));
110                 snprintf(params, BUFSIZ, "%s", getenv("QUERY_STRING"));
111                 
112                 //Remove trailing slashes (if present) from module query
113                 size_t lastchar = strlen(module) - 1;
114                 if (lastchar > 0 && module[lastchar] == '/')
115                         module[lastchar] = 0;
116                 
117
118                 if (!strcmp("sensors", module)) {
119                         module_handler = SensorsHandler;
120                 } else if (!strcmp("admin", module)) {
121                         //module_handler = AdminHandlerReplace with pointer to admin handler
122                 }
123
124                 if (module_handler) {
125                         module_handler(data, params);
126                 } else {
127                         char buf[BUFSIZ];
128                         
129                         FCGI_BeginJSON(400, module);
130                         FCGI_BuildJSON("description", "400 Invalid response");
131                         snprintf(buf, BUFSIZ, "%d", count);
132                         FCGI_BuildJSON("request-number", buf);
133                         FCGI_BuildJSON("params", params);
134                         FCGI_BuildJSON("host", getenv("SERVER_HOSTNAME"));
135                         FCGI_EndJSON();
136                 }
137
138                 count++;
139         }
140 }
141
142 int main(int argc, char *argv[]) {
143         FCGI_RequestLoop(NULL);
144 }

UCC git Repository :: git.ucc.asn.au