Add POST handling and URLDecode POST/GET request data. Switch Login to use POST inste...
authorJeremy Tan <[email protected]>
Thu, 24 Oct 2013 11:17:27 +0000 (19:17 +0800)
committerJeremy Tan <[email protected]>
Thu, 24 Oct 2013 11:17:27 +0000 (19:17 +0800)
Hopefully this doesn't introduce any new bugs.

server/fastcgi.c
server/fastcgi.h
server/login.c
server/sensor.c
testing/fastcgi-approach/post/post.c [new file with mode: 0644]

index 76ce61f..19d2869 100644 (file)
@@ -11,6 +11,7 @@
 #include <stdarg.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <ctype.h>
 
 #include "common.h"
 #include "sensor.h"
@@ -537,6 +538,40 @@ char *FCGI_EscapeText(char *buf)
        return buf;
 }
 
+/**
+ * Unescapes a URL encoded string in-place. The string
+ * must be NULL terminated.
+ * (e.g this%2d+string --> this- string)
+ * @param buf The buffer to decode. Will be modified in-place.
+ * @return The same buffer.
+ */
+char *FCGI_URLDecode(char *buf)
+{
+       char *head = buf, *tail = buf;
+       char hex[3] = {0};
+
+       while (*tail) {
+               if (*tail == '%') { //%hh hex to char
+                       tail++;
+                       if (isxdigit(*tail) && isxdigit(*(tail+1))) {
+                               hex[0] = *tail++;
+                               hex[1] = *tail++;
+                               *head++ = (char)strtol(hex, NULL, 16);
+                       } else { //Not valid format; keep original
+                               head++;
+                       }
+               } else if (*tail == '+') { //Plus to space
+                       tail++;
+                       *head++ = ' ';
+               } else { //Anything else
+                       *head++ = *tail++;
+               }
+       }
+       *head = 0; //NULL-terminate at new end point
+
+       return buf;
+}
+
 /**
  * Main FCGI request loop that receives/responds to client requests.
  * @param data Reserved.
@@ -555,7 +590,13 @@ void * FCGI_RequestLoop (void *data)
                
                //strncpy doesn't zero-truncate properly
                snprintf(module, BUFSIZ, "%s", getenv("DOCUMENT_URI_LOCAL"));
-               snprintf(params, BUFSIZ, "%s", getenv("QUERY_STRING"));
+               
+               //Read from post body. If not empty, try GET instead.
+               if (fgets(params, BUFSIZ, stdin) == NULL || *params == '\0') {
+                       snprintf(params, BUFSIZ, "%s", getenv("QUERY_STRING"));
+               }
+               //URL decode the parameters
+               FCGI_URLDecode(params);
 
                FCGI_GetControlCookie(context.received_key);
                Log(LOGDEBUG, "Got request #%d - Module %s, params %s", context.response_number, module, params);
@@ -592,26 +633,23 @@ void * FCGI_RequestLoop (void *data)
                context.current_module = module;
                context.response_number++;
                
-               if (module_handler) 
-               {
-                       if (module_handler != Login_Handler && module_handler != IdentifyHandler && module_handler)
-                       //if (false) // Testing
-                       {
+               if (module_handler) {
+                       if (module_handler == IdentifyHandler) {
+                               FCGI_EscapeText(params);
+                       } else if (module_handler != Login_Handler) {
                                if (!FCGI_HasControl(&context))
                                {
-                                       if (g_options.auth_method == AUTH_NONE)
-                                       {       //:(
+                                       if (g_options.auth_method == AUTH_NONE) {       //:(
                                                Log(LOGWARN, "Locking control (no auth!)");
                                                FCGI_LockControl(&context, NOAUTH_USERNAME, USER_ADMIN);
                                                FCGI_SendControlCookie(&context, true);
                                        }
-                                       else
-                                       {
+                                       else {
                                                FCGI_RejectJSON(&context, "Please login. Invalid control key.");
                                                continue;
                                        }
                                }
-
+                               
                                //Escape all special characters.
                                //Don't escape for login (password may have special chars?)
                                FCGI_EscapeText(params);
@@ -619,8 +657,7 @@ void * FCGI_RequestLoop (void *data)
 
                        module_handler(&context, params);
                } 
-               else 
-               {
+               else {
                        FCGI_RejectJSON(&context, "Unhandled module");
                }
        }
index 5826ece..a417a43 100644 (file)
@@ -85,6 +85,7 @@ extern void FCGI_JSONKey(const char *key);
 extern void FCGI_PrintRaw(const char *format, ...);
 extern void FCGI_EndJSON();
 extern void FCGI_RejectJSONEx(FCGIContext *context, StatusCodes status, const char *description);
+extern char *FCGI_URLDecode(char *buf);
 extern char *FCGI_EscapeText(char *buf);
 extern void *FCGI_RequestLoop (void *data);
 
index 4d3d7fd..d6d7748 100644 (file)
@@ -178,7 +178,10 @@ void Logout_Handler(FCGIContext * context, char * params)
 /**
  * Handle a Login Request
  * @param context - The context
- * @param params - Parameter string, should contain username and password
+ * @param params - Parameter string, should contain username and password.
+ *                                NOTE: Care should be taken when using params, as it is
+ *                                completely unescaped. Do not log or use it without
+ *                 suitable escaping.
  */
 void Login_Handler(FCGIContext * context, char * params)
 {
@@ -220,7 +223,7 @@ void Login_Handler(FCGIContext * context, char * params)
 
                case AUTH_LDAP:
                {
-                       if (strlen(pass) <= 0)
+                       if (*pass == '\0')
                        {
                                FCGI_RejectJSON(context, "No password supplied.");
                                return;
index d146905..53b3f03 100644 (file)
@@ -47,7 +47,7 @@ int Sensor_Add(const char * name, int user_id, ReadFn read, InitFn init, CleanFn
        s->init = init; // Set init function
 
        // Start by averaging values taken over a second
-       DOUBLE_TO_TIMEVAL(1e-3, &(s->sample_time));
+       DOUBLE_TO_TIMEVAL(1, &(s->sample_time));
        s->averages = 1;
        s->num_read = 0;
 
diff --git a/testing/fastcgi-approach/post/post.c b/testing/fastcgi-approach/post/post.c
new file mode 100644 (file)
index 0000000..7cd803d
--- /dev/null
@@ -0,0 +1,53 @@
+#include <fcgi_stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+char *FCGI_URLDecode(char *buf);
+
+int main() {
+       while (FCGI_Accept() >= 0) {
+               char buf[BUFSIZ];
+               printf("Content-type: text/plain\r\n\r\n");
+
+
+               while(fgets(buf, BUFSIZ, stdin)) {
+                       printf("POST (raw):\r\n");
+                       printf("%s", buf);
+                       printf("\r\nPOST (decoded):\r\n");
+                       printf("%s", FCGI_URLDecode(buf));
+               }
+
+               snprintf(buf, BUFSIZ, "%s", getenv("QUERY_STRING"));
+               printf("\r\nGET (raw):\r\n");
+               printf("%s", getenv("QUERY_STRING"));
+
+               printf("\r\nGET (decoded):\r\n");
+               printf("%s", FCGI_URLDecode(buf));
+       }
+       return 0;
+
+}
+
+char *FCGI_URLDecode(char *buf) {
+       char *head = buf, *tail = buf;
+       char hex[3] = {0};
+       while (*tail) {
+               if (*tail == '%') {
+                       tail++;
+                       if (isxdigit(*tail) && isxdigit(*(tail+1))) {
+                               hex[0] = *tail++;
+                               hex[1] = *tail++;
+                               *head++ = (char)strtol(hex, NULL, 16);
+                       } else {
+                               head++;
+                       }
+               } else if (*tail == '+') {
+                       tail++;
+                       *head++ = ' ';
+               } else {
+                       *head++ = *tail++;
+               }
+       }
+       *head = 0;
+       return buf;
+}

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