avoid reentering MHD_run
[src/app-framework-binder.git] / src / afb-hsrv.c
index efbb935..abec0ad 100644 (file)
@@ -54,8 +54,15 @@ struct hsrv_alias {
        int dirfd;
 };
 
+enum afb_hsrv_state {
+       hsrv_idle = 0,
+       hsrv_run,
+       hsrv_rerun
+};
+
 struct afb_hsrv {
        unsigned refcount;
+       enum afb_hsrv_state state;
        struct hsrv_handler *handlers;
        struct MHD_Daemon *httpd;
        struct upoll *upoll;
@@ -65,19 +72,8 @@ struct afb_hsrv {
 
 static void reply_error(struct MHD_Connection *connection, unsigned int status)
 {
-       char *buffer;
-       int length;
-       struct MHD_Response *response;
-
-       length = asprintf(&buffer, "<html><body>error %u</body></html>", status);
-       if (length > 0)
-               response = MHD_create_response_from_buffer((unsigned)length, buffer, MHD_RESPMEM_MUST_FREE);
-       else {
-               buffer = "<html><body>error</body></html>";
-               response = MHD_create_response_from_buffer(strlen(buffer), buffer, MHD_RESPMEM_PERSISTENT);
-       }
-       if (!MHD_queue_response(connection, status, response))
-               fprintf(stderr, "Failed to reply error code %u", status);
+       struct MHD_Response *response = MHD_create_response_from_buffer(0, NULL, MHD_RESPMEM_PERSISTENT);
+       MHD_queue_response(connection, status, response);
        MHD_destroy_response(response);
 }
 
@@ -162,7 +158,7 @@ static int access_handler(
                        if (!MHD_post_process (hreq->postform, upload_data, *upload_data_size))
                                goto internal_error;
                } else {
-                       if (!afb_hreq_post_add(hreq, NULL, upload_data, *upload_data_size))
+                       if (!afb_hreq_post_add(hreq, "", upload_data, *upload_data_size))
                                goto internal_error;
                }
                *upload_data_size = 0;
@@ -214,6 +210,19 @@ static void end_handler(void *cls, struct MHD_Connection *connection, void **rec
        afb_hreq_free(hreq);
 }
 
+static void handle_epoll_readable(struct afb_hsrv *hsrv)
+{
+       if (hsrv->state != hsrv_idle)
+               hsrv->state = hsrv_rerun;
+       else {
+               do {
+                       hsrv->state = hsrv_run;
+                       MHD_run(hsrv->httpd);
+               } while (hsrv->state == hsrv_rerun);
+               hsrv->state = hsrv_idle;
+       }
+};
+
 static int new_client_handler(void *cls, const struct sockaddr *addr, socklen_t addrlen)
 {
        return MHD_YES;
@@ -347,7 +356,7 @@ int afb_hsrv_start(struct afb_hsrv *hsrv, uint16_t port, unsigned int connection
                MHD_OPTION_END);        /* options-end */
 
        if (httpd == NULL) {
-               printf("Error: httpStart invalid httpd port: %d", (int)port);
+               fprintf(stderr, "Error: httpStart invalid httpd port: %d", (int)port);
                return 0;
        }
 
@@ -358,13 +367,13 @@ int afb_hsrv_start(struct afb_hsrv *hsrv, uint16_t port, unsigned int connection
                return 0;
        }
 
-       upoll = upoll_open(info->listen_fd, httpd);
+       upoll = upoll_open(info->listen_fd, hsrv);
        if (upoll == NULL) {
                MHD_stop_daemon(httpd);
                fprintf(stderr, "Error: connection to upoll of httpd failed");
                return 0;
        }
-       upoll_on_readable(upoll, (void*)MHD_run);
+       upoll_on_readable(upoll, (void*)handle_epoll_readable);
 
        hsrv->httpd = httpd;
        hsrv->upoll = upoll;