diff --git a/lib/api.c b/lib/api.c index 04870ba7a..540fe3ae4 100644 --- a/lib/api.c +++ b/lib/api.c @@ -132,24 +132,30 @@ int api_ws_protocol_cb(struct lws *wsi, enum lws_callback_reasons reason, void * int api_http_protocol_cb(struct lws *wsi, enum lws_callback_reasons reason, void *user, void *in, size_t len) { - int ret, pulled, pushed; + int ret, pulled, pushed, hdrlen; + char *uri; json_t *resp, *req; struct web *w = lws_context_user(lws_get_context(wsi)); struct api_session *s = (struct api_session *) user; switch (reason) { - case LWS_CALLBACK_HTTP: - if (w->api == NULL) { - lws_close_reason(wsi, LWS_CLOSE_STATUS_PROTOCOL_ERR, (unsigned char *) "API disabled", strlen("API disabled")); + case LWS_CALLBACK_HTTP_BIND_PROTOCOL: + if (w->api == NULL) return -1; - } + + hdrlen = lws_hdr_total_length(wsi, WSI_TOKEN_POST_URI); + uri = malloc(hdrlen+1); + + lws_hdr_copy(wsi, uri, sizeof(uri), WSI_TOKEN_POST_URI); /* Parse request URI */ - ret = sscanf(in, "/api/v%d", (int *) &s->version); + ret = sscanf(uri, "/api/v%d", (int *) &s->version); if (ret != 1) return -1; + free(uri); + ret = api_session_init(s, API_MODE_HTTP); if (ret) return -1; @@ -164,7 +170,7 @@ int api_http_protocol_cb(struct lws *wsi, enum lws_callback_reasons reason, void break; - case LWS_CALLBACK_CLOSED_HTTP: + case LWS_CALLBACK_HTTP_DROP_PROTOCOL: if (!s) return -1; @@ -177,7 +183,7 @@ int api_http_protocol_cb(struct lws *wsi, enum lws_callback_reasons reason, void if (w->api->sessions.state == STATE_INITIALIZED) list_remove(&w->api->sessions, s); - break; + return 1; case LWS_CALLBACK_HTTP_BODY: buffer_append(&s->request.buffer, in, len); @@ -204,33 +210,50 @@ int api_http_protocol_cb(struct lws *wsi, enum lws_callback_reasons reason, void case LWS_CALLBACK_HTTP_WRITEABLE: pulled = queue_pull(&s->response.queue, (void **) &resp); if (pulled) { - const char headers[] = "HTTP/1.1 200 OK\r\n" - "Content-type: application/json\r\n" - "User-agent: " USER_AGENT "\r\n" - "Access-Control-Allow-Origin: *\r\n" - "Access-Control-Allow-Methods: GET, POST, OPTIONS\r\n" - "Access-Control-Allow-Headers: Content-Type\r\n" - "Access-Control-Max-Age: 86400\r\n" - "\r\n"; + char headers[1024]; buffer_clear(&s->response.buffer); buffer_append_json(&s->response.buffer, resp); json_decref(resp); - lws_write(wsi, (unsigned char *) headers, strlen(headers), LWS_WRITE_HTTP_HEADERS); - lws_write(wsi, (unsigned char *) s->response.buffer.buf, s->response.buffer.len, LWS_WRITE_HTTP); + snprintf(headers, sizeof(headers), + "HTTP/1.1 200 OK\r\n" + "Content-type: application/json\r\n" + "User-agent: " USER_AGENT "\r\n" + "Access-Control-Allow-Origin: *\r\n" + "Access-Control-Allow-Methods: GET, POST, OPTIONS\r\n" + "Access-Control-Allow-Headers: Content-Type\r\n" + "Access-Control-Max-Age: 86400\r\n" + "Content-Length: %zu\r\n" + "\r\n", + s->response.buffer.len + ); - return -1; /* Close connection */ + ret = lws_write(wsi, (unsigned char *) headers, strlen(headers), LWS_WRITE_HTTP_HEADERS); + if (ret < 0) + return 1; + + ret = lws_write(wsi, (unsigned char *) s->response.buffer.buf, s->response.buffer.len, LWS_WRITE_HTTP); + if (ret < 0) + return 1; + + goto try_to_reuse; } break; default: - return 0; + break; } return 0; + +try_to_reuse: + if (lws_http_transaction_completed(wsi)) + return -1; + + return 0; } int api_init(struct api *a, struct super_node *sn) diff --git a/lib/web.c b/lib/web.c index 61b87fd64..834d93224 100644 --- a/lib/web.c +++ b/lib/web.c @@ -36,14 +36,20 @@ lws_callback_function api_http_protocol_cb; lws_callback_function websocket_protocol_cb; /** List of libwebsockets protocols. */ -static struct lws_protocols protocols[] = { -#ifdef WITH_API + struct lws_protocols protocols[] = { + { + .name = "http", + .callback = lws_callback_http_dummy, + .per_session_data_size = 0, + .rx_buffer_size = 1024 + }, { .name = "http-api", .callback = api_http_protocol_cb, .per_session_data_size = sizeof(struct api_session), - .rx_buffer_size = 0 + .rx_buffer_size = 1024 }, +#ifdef WITH_API { .name = "api", .callback = api_ws_protocol_cb, @@ -94,7 +100,7 @@ static struct lws_http_mount mounts[] = { .mount_next = &mounts[1] }, { - .mountpoint = "/api/v1/", + .mountpoint = "/api/v1", .origin = "http-api", .def = NULL, .cgienv = NULL, @@ -104,7 +110,7 @@ static struct lws_http_mount mounts[] = { .cache_revalidate = 0, .cache_intermediaries = 0, .origin_protocol = LWSMPRO_CALLBACK, - .mountpoint_len = 8, + .mountpoint_len = 7, #endif .mount_next = NULL } @@ -217,10 +223,7 @@ int web_start(struct web *w) .options = LWS_SERVER_OPTION_EXPLICIT_VHOSTS | LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT, .gid = -1, .uid = -1, - .user = (void *) w - }; - - struct lws_context_creation_info vhost_info = { + .user = (void *) w, .protocols = protocols, .mounts = mounts, .extensions = extensions, @@ -237,11 +240,11 @@ int web_start(struct web *w) w->context = lws_create_context(&ctx_info); if (w->context == NULL) - error("WebSocket: failed to initialize server"); + error("WebSocket: failed to initialize server context"); - w->vhost = lws_create_vhost(w->context, &vhost_info); + w->vhost = lws_create_vhost(w->context, &ctx_info); if (w->vhost == NULL) - error("WebSocket: failed to initialize server"); + error("WebSocket: failed to initialize virtual host"); } ret = pthread_create(&w->thread, NULL, web_worker, w);