[xiph-cvs] cvs commit: httpp httpp.c httpp.h

Michael Smith msmith at xiph.org
Mon Dec 30 22:28:41 PST 2002



msmith      02/12/31 01:28:40

  Modified:    src      client.c client.h connection.c util.c util.h
               .        httpp.c httpp.h
  Log:
  mp3 metadata complete. Still untested.

Revision  Changes    Path
1.5       +10 -0     icecast/src/client.c

Index: client.c
===================================================================
RCS file: /usr/local/cvsroot/icecast/src/client.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- client.c	16 Aug 2002 15:28:46 -0000	1.4
+++ client.c	31 Dec 2002 06:28:38 -0000	1.5
@@ -45,6 +45,16 @@
         free(client);
 }
 
+void client_send_400(client_t *client, char *message) {
+    int bytes;
+    bytes = sock_write(client->con->sock, "HTTP/1.0 404 File Not Found\r\n"
+            "Content-Type: text/html\r\n\r\n"
+            "<b>%s</b>\r\n", message);
+    if(bytes > 0) client->con->sent_bytes = bytes;
+    client->respcode = 404;
+    client_destroy(client);
+}
+
 void client_send_404(client_t *client, char *message) {
 
     int bytes;

<p><p>1.6       +1 -0      icecast/src/client.h

Index: client.h
===================================================================
RCS file: /usr/local/cvsroot/icecast/src/client.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -r1.5 -r1.6
--- client.h	30 Dec 2002 07:55:56 -0000	1.5
+++ client.h	31 Dec 2002 06:28:38 -0000	1.6
@@ -31,5 +31,6 @@
 void client_destroy(client_t *client);
 void client_send_404(client_t *client, char *message);
 void client_send_401(client_t *client);
+void client_send_400(client_t *client, char *message);
 
 #endif  /* __CLIENT_H__ */

<p><p>1.37      +67 -1     icecast/src/connection.c

Index: connection.c
===================================================================
RCS file: /usr/local/cvsroot/icecast/src/connection.c,v
retrieving revision 1.36
retrieving revision 1.37
diff -u -r1.36 -r1.37
--- connection.c	30 Dec 2002 15:42:38 -0000	1.36
+++ connection.c	31 Dec 2002 06:28:38 -0000	1.37
@@ -36,6 +36,7 @@
 #include "fserve.h"
 #include "source.h"
 #include "format.h"
+#include "format_mp3.h"
 
 #define CATMODULE "connection"
 
@@ -418,6 +419,65 @@
     return ret;
 }
 
+static void handle_metadata_request(client_t *client)
+{
+    source_t *source;
+    char *action;
+    char *mount;
+    char *value;
+    mp3_state *state;
+    int bytes;
+
+    if(!_check_source_pass(client->parser)) {
+		INFO0("Metadata request with wrong or missing password");
+        client_send_401(client);
+        return;
+    }
+
+    action = httpp_get_query_param(client->parser, "mode");
+    mount = httpp_get_query_param(client->parser, "mount");
+    value = httpp_get_query_param(client->parser, "song");
+
+    if(value == NULL || action == NULL || mount == NULL) {
+        client_send_400(client, "Missing parameter");
+        return;
+    }
+
+    avl_tree_rlock(global.source_tree);
+    source = source_find_mount(mount);
+    avl_tree_unlock(global.source_tree);
+
+    if(source == NULL) {
+        client_send_400(client, "No such mountpoint");
+        return;
+    }
+
+    if(source->format->type != FORMAT_TYPE_MP3) {
+        client_send_400(client, "Not mp3, cannot update metadata");
+        return;
+    }
+
+    if(strcmp(action, "updinfo") != 0) {
+        client_send_400(client, "No such action");
+        return;
+    }
+
+    state = source->format->_state;
+    thread_mutex_lock(&(state->lock));
+    free(state->metadata);
+    state->metadata = strdup(value);
+    state->metadata_age++;
+    thread_mutex_unlock(&(state->lock));
+
+    DEBUG2("Metadata on mountpoint %s changed to \"%s\"", mount, value);
+    client->respcode = 200;
+	bytes = sock_write(client->con->sock, 
+            "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"
+            "Update successful");
+    if(bytes > 0) client->con->sent_bytes = bytes;
+    client_destroy(client);
+}
+
 static void _handle_source_request(connection_t *con, 
         http_parser_t *parser, char *uri)
 {
@@ -500,7 +560,7 @@
         ** aren't subject to the limits.
         */
         /* TODO: add GUID-xxxxxx */
-	if (strcmp(uri, "/stats.xml") == 0) {
+	if (strcmp(uri, "/admin/stats.xml") == 0) {
             if (!_check_source_pass(parser)) {
                     INFO0("Request for stats.xml with incorrect or no password");
             client_send_401(client);
@@ -509,6 +569,12 @@
         DEBUG0("Stats request, sending xml stats");
                 stats_sendxml(client);
         client_destroy(client);
+        return;
+    }
+
+    if(strcmp(uri, "/admin/metadata") == 0) {
+        DEBUG0("Got metadata update request");
+        handle_metadata_request(client);
         return;
     }
 

<p><p>1.15      +39 -25    icecast/src/util.c

Index: util.c
===================================================================
RCS file: /usr/local/cvsroot/icecast/src/util.c,v
retrieving revision 1.14
retrieving revision 1.15
diff -u -r1.14 -r1.15
--- util.c	22 Nov 2002 13:00:44 -0000	1.14
+++ util.c	31 Dec 2002 06:28:38 -0000	1.15
@@ -208,50 +208,43 @@
     return fullpath;
 }
 
-/* Get an absolute path (from the webroot dir) from a URI. Return NULL if the
- * path contains 'disallowed' sequences like foo/../ (which could be used to
- * escape from the webroot) or if it cannot be URI-decoded.
- * Caller should free the path.
- */
-char *util_normalise_uri(char *uri) {
-    int urilen = strlen(uri);
-    unsigned char *path;
-    char *dst;
+char *util_url_escape(char *src)
+{
+    int len = strlen(src);
+    unsigned char *decoded;
     int i;
+    char *dst;
     int done = 0;
 
-    if(uri[0] != '/')
-        return NULL;
-
-    path = calloc(1, urilen + 1);
+    decoded = calloc(1, len + 1);
 
-    dst = path;
+    dst = decoded;
 
-    for(i=0; i < urilen; i++) {
-        switch(uri[i]) {
+    for(i=0; i < len; i++) {
+        switch(src[i]) {
             case '%':
-                if(i+2 >= urilen) {
-                    free(path);
+                if(i+2 >= len) {
+                    free(decoded);
                     return NULL;
                 }
-                if(hex(uri[i+1]) == -1 || hex(uri[i+2]) == -1 ) {
-                    free(path);
+                if(hex(src[i+1]) == -1 || hex(src[i+2]) == -1 ) {
+                    free(decoded);
                     return NULL;
                 }
 
-                *dst++ = hex(uri[i+1]) * 16  + hex(uri[i+2]);
+                *dst++ = hex(src[i+1]) * 16  + hex(src[i+2]);
                 i+= 2;
                 break;
             case '#':
                 done = 1;
                 break;
             case 0:
-                ERROR0("Fatal internal logic error in util_get_path_from_uri()");
-                free(path);
+                ERROR0("Fatal internal logic error in util_url_escape()");
+                free(decoded);
                 return NULL;
                 break;
             default:
-                *dst++ = uri[i];
+                *dst++ = src[i];
                 break;
         }
         if(done)
@@ -260,9 +253,30 @@
 
     *dst = 0; /* null terminator */
 
+    return decoded;
+}
+
+/* Get an absolute path (from the webroot dir) from a URI. Return NULL if the
+ * path contains 'disallowed' sequences like foo/../ (which could be used to
+ * escape from the webroot) or if it cannot be URI-decoded.
+ * Caller should free the path.
+ */
+char *util_normalise_uri(char *uri) {
+    char *path;
+
+    if(uri[0] != '/')
+        return NULL;
+
+    path = util_url_escape(uri);
+
+    if(path == NULL) {
+        WARN1("Error decoding URI: %s\n", uri);
+        return NULL;
+    }
+
     /* We now have a full URI-decoded path. Check it for allowability */
     if(verify_path(path))
-        return (char *)path;
+        return path;
     else {
         WARN1("Rejecting invalid path \"%s\"", path);
         free(path);

<p><p>1.9       +2 -0      icecast/src/util.h

Index: util.h
===================================================================
RCS file: /usr/local/cvsroot/icecast/src/util.h,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- util.h	18 Aug 2002 08:49:25 -0000	1.8
+++ util.h	31 Dec 2002 06:28:38 -0000	1.9
@@ -14,4 +14,6 @@
 char *util_base64_encode(char *data);
 char *util_base64_decode(unsigned char *input);
 
+char *util_url_escape(char *src);
+
 #endif  /* __UTIL_H__ */

<p><p>1.9       +142 -2    httpp/httpp.c

Index: httpp.c
===================================================================
RCS file: /usr/local/cvsroot/httpp/httpp.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -r1.8 -r1.9
--- httpp.c	16 Aug 2002 14:22:44 -0000	1.8
+++ httpp.c	31 Dec 2002 06:28:39 -0000	1.9
@@ -40,6 +40,7 @@
         parser->req_type = httpp_req_none;
         parser->uri = NULL;
         parser->vars = avl_tree_new(_compare_vars, NULL);
+    parser->queryvars = avl_tree_new(_compare_vars, NULL);
 
         /* now insert the default variables */
         list = defaults;
@@ -178,6 +179,100 @@
         return 1;
 }
 
+static int hex(char c)
+{
+    if(c >= '0' && c <= '9')
+        return c - '0';
+    else if(c >= 'A' && c <= 'F')
+        return c - 'A' + 10;
+    else if(c >= 'a' && c <= 'f')
+        return c - 'a' + 10;
+    else
+        return -1;
+}
+
+static char *url_escape(char *src)
+{
+    int len = strlen(src);
+    unsigned char *decoded;
+    int i;
+    char *dst;
+    int done = 0;
+
+    decoded = calloc(1, len + 1);
+
+    dst = decoded;
+
+    for(i=0; i < len; i++) {
+        switch(src[i]) {
+            case '%':
+                if(i+2 >= len) {
+                    free(decoded);
+                    return NULL;
+                }
+                if(hex(src[i+1]) == -1 || hex(src[i+2]) == -1 ) {
+                    free(decoded);
+                    return NULL;
+                }
+
+                *dst++ = hex(src[i+1]) * 16  + hex(src[i+2]);
+                i+= 2;
+                break;
+            case '#':
+                done = 1;
+                break;
+            case 0:
+                free(decoded);
+                return NULL;
+                break;
+            default:
+                *dst++ = src[i];
+                break;
+        }
+        if(done)
+            break;
+    }
+
+    *dst = 0; /* null terminator */
+
+    return decoded;
+}
+
+/** TODO: This is almost certainly buggy in some cases */
+static void parse_query(http_parser_t *parser, char *query)
+{
+    int len;
+    int i=0;
+    char *key = query;
+    char *val=NULL;
+
+    if(!query || !*query)
+        return;
+
+    len = strlen(query);
+
+    while(i<len) {
+        switch(query[i]) {
+            case '&':
+                query[i] = 0;
+                if(val && key) {
+                    httpp_set_query_param(parser, key, val);
+                }
+                key = query+i+1;
+                break;
+            case '=':
+                query[i] = 0;
+                val = query+i+1;
+                break;
+        }
+        i++;
+    }
+
+    if(val && key) {
+        httpp_set_query_param(parser, key, val);
+    }
+}
+
 int httpp_parse(http_parser_t *parser, char *http_data, unsigned long len)
 {
         char *data, *tmp;
@@ -247,8 +342,17 @@
                 parser->req_type = httpp_req_unknown;
         }
 
-	if (uri != NULL && strlen(uri) > 0)
+	if (uri != NULL && strlen(uri) > 0) 
+    {
+        char *query;
+        if((query = strchr(uri, '?')) != NULL) {
+            *query = 0;
+            query++;
+            parse_query(parser, query);
+        }
+
                 parser->uri = strdup(uri);
+    }
         else
                 parser->uri = NULL;
 
@@ -335,7 +439,7 @@
         http_var_t *found;
 
         var.name = name;
-        var.value = NULL;
+    var.value = NULL;
 
         if (avl_get_by_key(parser->vars, (void *)&var, (void **)&found) == 0)
                 return found->value;
@@ -343,6 +447,41 @@
                 return NULL;
 }
 
+void httpp_set_query_param(http_parser_t *parser, char *name, char *value)
+{
+	http_var_t *var;
+
+	if (name == NULL || value == NULL)
+		return;
+
+	var = (http_var_t *)malloc(sizeof(http_var_t));
+	if (var == NULL) return;
+
+	var->name = strdup(name);
+	var->value = url_escape(value);
+
+	if (httpp_get_query_param(parser, name) == NULL) {
+		avl_insert(parser->queryvars, (void *)var);
+	} else {
+		avl_delete(parser->queryvars, (void *)var, _free_vars);
+		avl_insert(parser->queryvars, (void *)var);
+	}
+}
+
+char *httpp_get_query_param(http_parser_t *parser, char *name)
+{
+	http_var_t var;
+	http_var_t *found;
+
+	var.name = name;
+    var.value = NULL;
+
+	if (avl_get_by_key(parser->queryvars, (void *)&var, (void **)&found) == 0)
+		return found->value;
+	else
+		return NULL;
+}
+
 void httpp_clear(http_parser_t *parser)
 {
         parser->req_type = httpp_req_none;
@@ -350,6 +489,7 @@
                 free(parser->uri);
         parser->uri = NULL;
         avl_tree_free(parser->vars, _free_vars);
+	avl_tree_free(parser->queryvars, _free_vars);
         parser->vars = NULL;
 }
 

<p><p>1.5       +3 -0      httpp/httpp.h

Index: httpp.h
===================================================================
RCS file: /usr/local/cvsroot/httpp/httpp.h,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -r1.4 -r1.5
--- httpp.h	16 Aug 2002 14:22:44 -0000	1.4
+++ httpp.h	31 Dec 2002 06:28:39 -0000	1.5
@@ -33,6 +33,7 @@
         httpp_request_type_e req_type;
         char *uri;
         avl_tree *vars;
+    avl_tree *queryvars;
 } http_parser_t;
 
 http_parser_t *httpp_create_parser(void);
@@ -41,6 +42,8 @@
 int httpp_parse_response(http_parser_t *parser, char *http_data, unsigned long len, char *uri);
 void httpp_setvar(http_parser_t *parser, char *name, char *value);
 char *httpp_getvar(http_parser_t *parser, char *name);
+void httpp_set_query_param(http_parser_t *parser, char *name, char *value);
+char *httpp_get_query_param(http_parser_t *parser, char *name);
 void httpp_destroy(http_parser_t *parser);
 void httpp_clear(http_parser_t *parser);
  

<p><p>--- >8 ----
List archives:  http://www.xiph.org/archives/
Ogg project homepage: http://www.xiph.org/ogg/
To unsubscribe from this list, send a message to 'cvs-request at xiph.org'
containing only the word 'unsubscribe' in the body.  No subject is needed.
Unsubscribe messages sent to the list will be ignored/filtered.



More information about the commits mailing list