]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-10690: [libblade] Added web request and web response layer ontop of civetweb to...
authorShane Bryldt <astaelan@gmail.com>
Thu, 12 Oct 2017 17:47:07 +0000 (11:47 -0600)
committerShane Bryldt <astaelan@gmail.com>
Thu, 12 Oct 2017 17:47:07 +0000 (11:47 -0600)
libs/libblade/libblade.vcxproj
libs/libblade/libblade.vcxproj.filters
libs/libblade/src/blade_restmgr.c
libs/libblade/src/blade_web.c [new file with mode: 0644]
libs/libblade/src/include/blade.h
libs/libblade/src/include/blade_types.h
libs/libblade/src/include/blade_web.h [new file with mode: 0644]
libs/libblade/switchblade/switchblade.c
libs/libks/src/ks_sb.c

index 53937656713ad2eeb305c4cbcfdc72f50a086bb8..40baad7dda959dba7a10fd972dc30c8c744a23ff 100644 (file)
     <ClCompile Include="src\blade_stack.c" />
     <ClCompile Include="src\blade_transport.c" />
     <ClCompile Include="src\blade_tuple.c" />
+    <ClCompile Include="src\blade_web.c" />
     <ClCompile Include="src\unqlite.c" />
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="src\include\blade_transport.h" />
     <ClInclude Include="src\include\blade_tuple.h" />
     <ClInclude Include="src\include\blade_types.h" />
+    <ClInclude Include="src\include\blade_web.h" />
     <ClInclude Include="src\include\unqlite.h" />
   </ItemGroup>
   <ItemGroup>
index 95d31a319248d384b8495fad081a1b5c4324501b..2c7dbb8b5459a909719e201db83ce1dad88bc4ce 100644 (file)
@@ -78,6 +78,9 @@
     <ClCompile Include="src\blade_restmgr.c">
       <Filter>Source Files</Filter>
     </ClCompile>
+    <ClCompile Include="src\blade_web.c">
+      <Filter>Source Files</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="src\include\unqlite.h">
     <ClInclude Include="src\include\blade_restmgr.h">
       <Filter>Header Files</Filter>
     </ClInclude>
+    <ClInclude Include="src\include\blade_web.h">
+      <Filter>Header Files</Filter>
+    </ClInclude>
   </ItemGroup>
 </Project>
\ No newline at end of file
index 34964f43bcf14682ac43cd8c57d66e024347987f..2c2d43a2ef857ea15fe4f55c4daf6fa1ea0ab234 100644 (file)
@@ -61,6 +61,7 @@ typedef struct blade_restmgr_service_s {
        blade_restmgr_service_callback_t callback;
 } blade_restmgr_service_t;
 
+
 static void blade_restmgr_service_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type)
 {
        blade_restmgr_service_t *brestmgrs = (blade_restmgr_service_t *)ptr;
diff --git a/libs/libblade/src/blade_web.c b/libs/libblade/src/blade_web.c
new file mode 100644 (file)
index 0000000..1bf98db
--- /dev/null
@@ -0,0 +1,674 @@
+/*
+ * Copyright (c) 2017, Shane Bryldt
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "blade.h"
+
+struct blade_webrequest_s {
+       const char *action;
+       const char *path;
+
+       ks_hash_t *query;
+       ks_hash_t *headers;
+
+       ks_sb_t *content;
+};
+
+struct blade_webresponse_s {
+       const char *status_code;
+       const char *status_message;
+
+       ks_hash_t *headers;
+
+       ks_sb_t *content;
+};
+
+static void blade_webrequest_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type)
+{
+       blade_webrequest_t *bwreq = (blade_webrequest_t *)ptr;
+
+       ks_assert(bwreq);
+
+       switch (action) {
+       case KS_MPCL_ANNOUNCE:
+               break;
+       case KS_MPCL_TEARDOWN:
+               break;
+       case KS_MPCL_DESTROY:
+               break;
+       }
+}
+
+static void blade_webresponse_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type)
+{
+       blade_webresponse_t *bwres = (blade_webresponse_t *)ptr;
+
+       ks_assert(bwres);
+
+       switch (action) {
+       case KS_MPCL_ANNOUNCE:
+               break;
+       case KS_MPCL_TEARDOWN:
+               break;
+       case KS_MPCL_DESTROY:
+               break;
+       }
+}
+
+KS_DECLARE(ks_status_t) blade_webrequest_create(blade_webrequest_t **bwreqP, const char *action, const char *path)
+{
+       ks_pool_t *pool = NULL;
+       blade_webrequest_t *bwreq = NULL;
+
+       ks_assert(bwreqP);
+       ks_assert(action);
+       ks_assert(path);
+
+       ks_pool_open(&pool);
+       ks_assert(pool);
+
+       bwreq = ks_pool_alloc(pool, sizeof(blade_webrequest_t));
+
+       bwreq->action = ks_pstrdup(pool, action);
+       bwreq->path = ks_pstrdup(pool, path);
+
+       ks_hash_create(&bwreq->query, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY | KS_HASH_FLAG_FREE_VALUE, pool);
+       ks_assert(bwreq->query);
+
+       ks_hash_create(&bwreq->headers, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY | KS_HASH_FLAG_FREE_VALUE, pool);
+       ks_assert(bwreq->headers);
+
+       ks_sb_create(&bwreq->content, pool, 0);
+       ks_assert(bwreq->content);
+
+       ks_pool_set_cleanup(bwreq, NULL, blade_webrequest_cleanup);
+
+       *bwreqP = bwreq;
+
+       blade_webrequest_header_add(bwreq, "Content-Type", "application/x-www-form-urlencoded");
+
+       return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_status_t) blade_webrequest_load(blade_webrequest_t **bwreqP, struct mg_connection *conn)
+{
+       ks_status_t ret = KS_STATUS_SUCCESS;
+       ks_pool_t *pool = NULL;
+       blade_webrequest_t *bwreq = NULL;
+       struct mg_request_info *info = NULL;
+       char buf[1024];
+       int bytes = 0;
+
+       ks_assert(bwreqP);
+       ks_assert(conn);
+
+       info = mg_get_request_info(conn);
+
+       ks_pool_open(&pool);
+       ks_assert(pool);
+
+       bwreq = ks_pool_alloc(pool, sizeof(blade_webrequest_t));
+
+       bwreq->action = ks_pstrdup(pool, info->request_method);
+       bwreq->path = ks_pstrdup(pool, info->request_uri);
+
+       ks_hash_create(&bwreq->query, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY | KS_HASH_FLAG_FREE_VALUE, pool);
+       ks_assert(bwreq->query);
+
+       ks_hash_create(&bwreq->headers, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY | KS_HASH_FLAG_FREE_VALUE, pool);
+       ks_assert(bwreq->headers);
+
+       ks_sb_create(&bwreq->content, pool, 0);
+       ks_assert(bwreq->content);
+
+       ks_pool_set_cleanup(bwreq, NULL, blade_webrequest_cleanup);
+
+       if (info->query_string && info->query_string[0]) {
+               char *query = ks_pstrdup(pool, info->query_string);
+               char *start = query;
+               char *end = NULL;
+
+               do {
+                       char *key = start;
+                       char *value = NULL;
+
+                       end = strchr(start, '&');
+                       if (end) *end = '\0';
+
+                       value = strchr(start, '=');
+                       if (value) {
+                               *value = '\0';
+                               value++;
+
+                               if (*key && *value) {
+                                       ks_hash_insert(bwreq->query, (void *)ks_pstrdup(pool, key), (void *)ks_pstrdup(pool, value));
+                               }
+                       }
+
+                       if (end) start = ++end;
+                       else start = NULL;
+               } while (start);
+
+               ks_pool_free(&query);
+       }
+
+       for (int index = 0; index < info->num_headers; ++index) {
+               struct mg_header *header = &info->http_headers[index];
+               ks_hash_insert(bwreq->headers, (void *)ks_pstrdup(pool, header->name), (void *)ks_pstrdup(pool, header->value));
+       }
+
+       while ((bytes = mg_read(conn, buf, sizeof(buf))) > 0) ks_sb_append_ex(bwreq->content, buf, bytes);
+       if (bytes < 0) {
+               blade_webrequest_destroy(&bwreq);
+               ret = KS_STATUS_FAIL;
+       }
+       else *bwreqP = bwreq;
+
+       return ret;
+}
+
+KS_DECLARE(ks_status_t) blade_webrequest_destroy(blade_webrequest_t **bwreqP)
+{
+       blade_webrequest_t *bwreq = NULL;
+       ks_pool_t *pool;
+
+       ks_assert(bwreqP);
+       ks_assert(*bwreqP);
+
+       bwreq = *bwreqP;
+       *bwreqP = NULL;
+
+       pool = ks_pool_get(bwreq);
+
+       ks_pool_close(&pool);
+
+       return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(const char *) blade_webrequest_action_get(blade_webrequest_t *bwreq)
+{
+       ks_assert(bwreq);
+       return bwreq->action;
+}
+
+KS_DECLARE(const char *) blade_webrequest_path_get(blade_webrequest_t *bwreq)
+{
+       ks_assert(bwreq);
+       return bwreq->path;
+}
+
+KS_DECLARE(ks_status_t) blade_webrequest_query_add(blade_webrequest_t *bwreq, const char *name, const char *value)
+{
+       ks_assert(bwreq);
+       ks_assert(name);
+       ks_assert(value);
+
+       ks_hash_insert(bwreq->query, (void *)ks_pstrdup(ks_pool_get(bwreq), name), (void *)ks_pstrdup(ks_pool_get(bwreq), value));
+
+       return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(const char *) blade_webrequest_query_get(blade_webrequest_t *bwreq, const char *name)
+{
+       ks_assert(bwreq);
+       ks_assert(name);
+
+       return (const char *)ks_hash_search(bwreq->query, (void *)name, KS_UNLOCKED);
+}
+
+KS_DECLARE(ks_status_t) blade_webrequest_header_add(blade_webrequest_t *bwreq, const char *header, const char *value)
+{
+       ks_assert(bwreq);
+       ks_assert(header);
+       ks_assert(value);
+
+       ks_hash_insert(bwreq->headers, (void *)ks_pstrdup(ks_pool_get(bwreq), header), (void *)ks_pstrdup(ks_pool_get(bwreq), value));
+       
+       return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_status_t) blade_webrequest_header_printf(blade_webrequest_t *bwreq, const char *header, const char *fmt, ...)
+{
+       va_list ap;
+       char *result = NULL;
+
+       ks_assert(bwreq);
+       ks_assert(header);
+       ks_assert(fmt);
+
+       va_start(ap, fmt);
+       result = ks_vpprintf(ks_pool_get(bwreq), fmt, ap);
+       va_end(ap);
+
+       ks_hash_insert(bwreq->headers, (void *)ks_pstrdup(ks_pool_get(bwreq), header), (void *)result);
+
+       return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(const char *) blade_webrequest_header_get(blade_webrequest_t *bwreq, const char *header)
+{
+       ks_assert(bwreq);
+       ks_assert(header);
+
+       return (const char *)ks_hash_search(bwreq->headers, (void *)header, KS_UNLOCKED);
+}
+
+KS_DECLARE(ks_status_t) blade_webrequest_content_json_append(blade_webrequest_t *bwreq, cJSON *json)
+{
+       ks_assert(bwreq);
+       ks_assert(json);
+
+       blade_webrequest_header_add(bwreq, "Content-Type", "application/json");
+
+       ks_sb_json(bwreq->content, json);
+
+       return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_status_t) blade_webrequest_content_string_append(blade_webrequest_t *bwreq, const char *str)
+{
+       ks_assert(bwreq);
+       ks_assert(str);
+
+       ks_sb_append(bwreq->content, str);
+
+       return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_status_t) blade_webrequest_send(blade_webrequest_t *bwreq, ks_bool_t secure, const char *host, ks_port_t port, blade_webresponse_t **bwresP)
+{
+       ks_status_t ret = KS_STATUS_SUCCESS;
+       char buf[1024];
+       struct mg_connection *conn = NULL;
+       const char *path = NULL;
+       ks_sb_t *pathAndQuery = NULL;
+
+       ks_assert(bwreq);
+       ks_assert(host);
+       ks_assert(bwresP);
+
+       if (port == 0) port = secure ? 443 : 80;
+
+       conn = mg_connect_client(host, port, secure, buf, sizeof(buf));
+       if (!conn) {
+               ret = KS_STATUS_FAIL;
+               goto done;
+       }
+
+       path = bwreq->path;
+       if (ks_hash_count(bwreq->query) > 0) {
+               ks_bool_t firstQuery = KS_TRUE;
+
+               ks_sb_create(&pathAndQuery, NULL, 0);
+               ks_sb_append(pathAndQuery, bwreq->path);
+               for (ks_hash_iterator_t *it = ks_hash_first(bwreq->query, KS_UNLOCKED); it; it = ks_hash_next(&it)) {
+                       const char *key;
+                       const char *value;
+
+                       ks_hash_this(it, (const void **)&key, NULL, (void **)&value);
+
+                       // @todo make sure key and value are URL encoded
+                       mg_url_encode(key, buf, sizeof(buf));
+                       ks_sb_printf(pathAndQuery, "%c%s=", firstQuery ? '?' : '&', buf);
+                       
+                       mg_url_encode(value, buf, sizeof(buf));
+                       ks_sb_append(pathAndQuery, buf);
+
+                       firstQuery = KS_FALSE;
+               }
+
+               path = ks_sb_cstr(pathAndQuery);
+       }
+
+       mg_printf(conn,
+               "%s %s HTTP/1.1\r\n"
+               "Host: %s\r\n"
+               "Content-Length: %lu\r\n",
+               bwreq->action,
+               path,
+               host,
+               ks_sb_length(bwreq->content));
+
+       if (pathAndQuery) ks_sb_destroy(&pathAndQuery);
+
+       for (ks_hash_iterator_t *it = ks_hash_first(bwreq->headers, KS_UNLOCKED); it; it = ks_hash_next(&it)) {
+               const char *key;
+               const char *value;
+
+               ks_hash_this(it, (const void **)&key, NULL, (void **)&value);
+               mg_printf(conn, "%s: %s\r\n", key, value);
+       }
+
+       mg_write(conn, "\r\n", 2);
+
+       mg_write(conn, ks_sb_cstr(bwreq->content), ks_sb_length(bwreq->content));
+
+       if (mg_get_response(conn, buf, sizeof(buf), 1000) <= 0) {
+               ret = KS_STATUS_FAIL;
+               goto done;
+       }
+
+       ret = blade_webresponse_load(bwresP, conn);
+
+done:
+       if (conn) mg_close_connection(conn);
+       return ret;
+}
+
+KS_DECLARE(ks_status_t) blade_webrequest_oauth2_token_by_credentials_send(ks_bool_t secure, const char *host, ks_port_t port, const char *path, const char *client_id, const char *client_secret, const char **token)
+{
+       ks_status_t ret = KS_STATUS_SUCCESS;
+       blade_webrequest_t *bwreq = NULL;
+       blade_webresponse_t *bwres = NULL;
+       cJSON *json = NULL;
+       char *auth = NULL;
+       char encoded[1024];
+       ks_pool_t *pool = NULL;
+       char *tok = NULL;
+
+       ks_assert(host);
+       ks_assert(path);
+       ks_assert(client_id);
+       ks_assert(client_secret);
+       ks_assert(token);
+
+       blade_webrequest_create(&bwreq, "POST", path);
+
+       auth = ks_psprintf(ks_pool_get(bwreq), "%s:%s", client_id, client_secret);
+       ks_b64_encode((unsigned char *)auth, strlen(auth), (unsigned char *)encoded, sizeof(encoded));
+       ks_pool_free(&auth);
+
+       blade_webrequest_header_printf(bwreq, "Authorization", "Basic %s", encoded);
+
+       json = cJSON_CreateObject();
+       cJSON_AddStringToObject(json, "grant_type", "client_credentials");
+       blade_webrequest_content_json_append(bwreq, json);
+       cJSON_Delete(json);
+
+       if ((ret = blade_webrequest_send(bwreq, secure, host, port, &bwres)) != KS_STATUS_SUCCESS) goto done;
+       
+       if ((ret = blade_webresponse_content_json_get(bwres, &json)) != KS_STATUS_SUCCESS) goto done;
+
+       if ((tok = cJSON_GetObjectCstr(json, "access_token")) == NULL) {
+               ret = KS_STATUS_FAIL;
+               goto done;
+       }
+
+       ks_pool_open(&pool);
+       *token = ks_pstrdup(pool, tok);
+
+done:
+       if (json) cJSON_Delete(json);
+       blade_webrequest_destroy(&bwreq);
+       if (bwres) blade_webresponse_destroy(&bwres);
+
+       return ret;
+}
+
+KS_DECLARE(ks_status_t) blade_webrequest_oauth2_token_by_code_send(ks_bool_t secure, const char *host, ks_port_t port, const char *path, const char *client_id, const char *client_secret, const char *code, const char **token)
+{
+       ks_status_t ret = KS_STATUS_SUCCESS;
+       blade_webrequest_t *bwreq = NULL;
+       blade_webresponse_t *bwres = NULL;
+       cJSON *json = NULL;
+       char *auth = NULL;
+       char encoded[1024];
+       ks_pool_t *pool = NULL;
+       char *tok = NULL;
+
+       ks_assert(host);
+       ks_assert(path);
+       ks_assert(client_id);
+       ks_assert(client_secret);
+       ks_assert(code);
+       ks_assert(token);
+
+       blade_webrequest_create(&bwreq, "POST", path);
+
+       auth = ks_psprintf(ks_pool_get(bwreq), "%s:%s", client_id, client_secret);
+       ks_b64_encode((unsigned char *)auth, strlen(auth), (unsigned char *)encoded, sizeof(encoded));
+       ks_pool_free(&auth);
+
+       blade_webrequest_header_printf(bwreq, "Authorization", "Basic %s", encoded);
+
+       json = cJSON_CreateObject();
+       cJSON_AddStringToObject(json, "grant_type", "authorization_code");
+       cJSON_AddStringToObject(json, "code", code);
+       blade_webrequest_content_json_append(bwreq, json);
+       cJSON_Delete(json);
+
+       if ((ret = blade_webrequest_send(bwreq, secure, host, port, &bwres)) != KS_STATUS_SUCCESS) goto done;
+
+       if ((ret = blade_webresponse_content_json_get(bwres, &json)) != KS_STATUS_SUCCESS) goto done;
+
+       if ((tok = cJSON_GetObjectCstr(json, "access_token")) == NULL) {
+               ret = KS_STATUS_FAIL;
+               goto done;
+       }
+
+       ks_pool_open(&pool);
+       *token = ks_pstrdup(pool, tok);
+
+done:
+       if (json) cJSON_Delete(json);
+       blade_webrequest_destroy(&bwreq);
+       if (bwres) blade_webresponse_destroy(&bwres);
+
+       return ret;
+}
+
+
+KS_DECLARE(ks_status_t) blade_webresponse_create(blade_webresponse_t **bwresP, const char *status)
+{
+       ks_pool_t *pool = NULL;
+       blade_webresponse_t *bwres = NULL;
+
+       ks_assert(bwresP);
+       ks_assert(status);
+
+       ks_pool_open(&pool);
+       ks_assert(pool);
+
+       bwres = ks_pool_alloc(pool, sizeof(blade_webresponse_t));
+
+       bwres->status_code = ks_pstrdup(pool, status);
+       bwres->status_message = ks_pstrdup(pool, mg_get_response_code_text(NULL, atoi(status)));
+       
+       ks_hash_create(&bwres->headers, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY | KS_HASH_FLAG_FREE_VALUE, pool);
+       ks_assert(bwres->headers);
+
+       ks_sb_create(&bwres->content, pool, 0);
+       ks_assert(bwres->content);
+
+       ks_pool_set_cleanup(bwres, NULL, blade_webresponse_cleanup);
+
+       *bwresP = bwres;
+
+       blade_webresponse_header_add(bwres, "Content-Type", "application/x-www-form-urlencoded");
+
+       return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_status_t) blade_webresponse_load(blade_webresponse_t **bwresP, struct mg_connection *conn)
+{
+       ks_status_t ret = KS_STATUS_SUCCESS;
+       ks_pool_t *pool = NULL;
+       blade_webresponse_t *bwres = NULL;
+       struct mg_request_info *info = NULL;
+       char buf[1024];
+       int bytes = 0;
+
+       ks_assert(bwresP);
+       ks_assert(conn);
+
+       info = mg_get_request_info(conn);
+
+       ks_pool_open(&pool);
+       ks_assert(pool);
+
+       bwres = ks_pool_alloc(pool, sizeof(blade_webrequest_t));
+
+       bwres->status_code = ks_pstrdup(pool, info->request_uri);
+       bwres->status_message = ks_pstrdup(pool, info->http_version);
+
+       ks_hash_create(&bwres->headers, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY | KS_HASH_FLAG_FREE_VALUE, pool);
+       ks_assert(bwres->headers);
+
+       ks_sb_create(&bwres->content, pool, 0);
+       ks_assert(bwres->content);
+
+       ks_pool_set_cleanup(bwres, NULL, blade_webresponse_cleanup);
+
+       for (int index = 0; index < info->num_headers; ++index) {
+               struct mg_header *header = &info->http_headers[index];
+               ks_hash_insert(bwres->headers, (void *)ks_pstrdup(pool, header->name), (void *)ks_pstrdup(pool, header->value));
+       }
+
+       while ((bytes = mg_read(conn, buf, sizeof(buf))) > 0) ks_sb_append_ex(bwres->content, buf, bytes);
+       if (bytes < 0) {
+               blade_webresponse_destroy(&bwres);
+               ret = KS_STATUS_FAIL;
+       }
+       else *bwresP = bwres;
+
+       return ret;
+}
+
+KS_DECLARE(ks_status_t) blade_webresponse_destroy(blade_webresponse_t **bwresP)
+{
+       blade_webresponse_t *bwres = NULL;
+       ks_pool_t *pool;
+
+       ks_assert(bwresP);
+       ks_assert(*bwresP);
+
+       bwres = *bwresP;
+       *bwresP = NULL;
+
+       pool = ks_pool_get(bwres);
+
+       ks_pool_close(&pool);
+
+       return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_status_t) blade_webresponse_header_add(blade_webresponse_t *bwres, const char *header, const char *value)
+{
+       ks_assert(bwres);
+       ks_assert(header);
+       ks_assert(value);
+
+       ks_hash_insert(bwres->headers, (void *)ks_pstrdup(ks_pool_get(bwres), header), (void *)ks_pstrdup(ks_pool_get(bwres), value));
+
+       return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(const char *) blade_webresponse_header_get(blade_webresponse_t *bwres, const char *header)
+{
+       ks_assert(bwres);
+       ks_assert(header);
+
+       return (const char *)ks_hash_search(bwres->headers, (void *)header, KS_UNLOCKED);
+}
+
+KS_DECLARE(ks_status_t) blade_webresponse_content_json_append(blade_webresponse_t *bwres, cJSON *json)
+{
+       ks_assert(bwres);
+       ks_assert(json);
+
+       blade_webresponse_header_add(bwres, "Content-Type", "application/json");
+
+       ks_sb_json(bwres->content, json);
+
+       return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_status_t) blade_webresponse_content_string_append(blade_webresponse_t *bwres, const char *str)
+{
+       ks_assert(bwres);
+       ks_assert(str);
+
+       ks_sb_append(bwres->content, str);
+
+       return KS_STATUS_SUCCESS;
+}
+
+KS_DECLARE(ks_status_t) blade_webresponse_content_json_get(blade_webresponse_t *bwres, cJSON **json)
+{
+       ks_status_t ret = KS_STATUS_SUCCESS;
+
+       ks_assert(bwres);
+       ks_assert(json);
+
+       if (!(*json = cJSON_Parse(ks_sb_cstr(bwres->content)))) ret = KS_STATUS_FAIL;
+
+       return ret;
+}
+
+KS_DECLARE(ks_status_t) blade_webresponse_send(blade_webresponse_t *bwres, struct mg_connection *conn)
+{
+       ks_assert(bwres);
+       ks_assert(conn);
+
+       mg_printf(conn,
+               "HTTP/1.1 %s %s\r\n"
+               "Content-Length: %lu\r\n"
+               "Connection: close\r\n",
+               bwres->status_code,
+               bwres->status_message,
+               ks_sb_length(bwres->content));
+
+       for (ks_hash_iterator_t *it = ks_hash_first(bwres->headers, KS_UNLOCKED); it; it = ks_hash_next(&it)) {
+               const char *key;
+               const char *value;
+
+               ks_hash_this(it, (const void **)&key, NULL, (void **)&value);
+               mg_printf(conn, "%s: %s\r\n", key, value);
+       }
+
+       mg_write(conn, "\r\n", 2);
+
+       mg_write(conn, ks_sb_cstr(bwres->content), ks_sb_length(bwres->content));
+
+       return KS_STATUS_SUCCESS;
+}
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
+ */
index 812e95456c80e910ee02e6559cfb18cc74b24928..5e1cb3db8295e07979a98cc103437f655cfc8d46 100644 (file)
@@ -51,6 +51,7 @@
 #include "blade_channel.h"
 #include "blade_subscription.h"
 #include "blade_tuple.h"
+#include "blade_web.h"
 
 #include "blade_transportmgr.h"
 #include "blade_rpcmgr.h"
index 7e6f9602356972bbcb964ebd252c8df1154c2d1d..93d61b6f950104d53eb095fbf67e07179cfcdb38 100644 (file)
@@ -62,6 +62,8 @@ typedef struct blade_connectionmgr_s blade_connectionmgr_t;
 typedef struct blade_sessionmgr_s blade_sessionmgr_t;
 typedef struct blade_session_callback_data_s blade_session_callback_data_t;
 
+typedef struct blade_webrequest_s blade_webrequest_t;
+typedef struct blade_webresponse_s blade_webresponse_t;
 typedef struct blade_restmgr_s blade_restmgr_t;
 
 typedef ks_bool_t (*blade_rpc_request_callback_t)(blade_rpc_request_t *brpcreq, void *data);
diff --git a/libs/libblade/src/include/blade_web.h b/libs/libblade/src/include/blade_web.h
new file mode 100644 (file)
index 0000000..062259f
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2017, Shane Bryldt
+ * All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 
+ * * Neither the name of the original author; nor the names of any contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * 
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _BLADE_WEB_H_
+#define _BLADE_WEB_H_
+#include <blade.h>
+
+KS_BEGIN_EXTERN_C
+KS_DECLARE(ks_status_t) blade_webrequest_create(blade_webrequest_t **bwreqP, const char *action, const char *path);
+KS_DECLARE(ks_status_t) blade_webrequest_load(blade_webrequest_t **bwreqP, struct mg_connection *conn);
+KS_DECLARE(ks_status_t) blade_webrequest_destroy(blade_webrequest_t **bwreqP);
+KS_DECLARE(const char *) blade_webrequest_action_get(blade_webrequest_t *bwreq);
+KS_DECLARE(const char *) blade_webrequest_path_get(blade_webrequest_t *bwreq);
+KS_DECLARE(ks_status_t) blade_webrequest_query_add(blade_webrequest_t *bwreq, const char *name, const char *value);
+KS_DECLARE(const char *) blade_webrequest_query_get(blade_webrequest_t *bwreq, const char *name);
+KS_DECLARE(ks_status_t) blade_webrequest_header_add(blade_webrequest_t *bwreq, const char *header, const char *value);
+KS_DECLARE(ks_status_t) blade_webrequest_header_printf(blade_webrequest_t *bwreq, const char *header, const char *fmt, ...);
+KS_DECLARE(const char *) blade_webrequest_header_get(blade_webrequest_t *bwreq, const char *header);
+KS_DECLARE(ks_status_t) blade_webrequest_content_json_append(blade_webrequest_t *bwreq, cJSON *json);
+KS_DECLARE(ks_status_t) blade_webrequest_content_string_append(blade_webrequest_t *bwreq, const char *str);
+KS_DECLARE(ks_status_t) blade_webrequest_send(blade_webrequest_t *bwreq, ks_bool_t secure, const char *host, ks_port_t port, blade_webresponse_t **bwresP);
+
+KS_DECLARE(ks_status_t) blade_webrequest_oauth2_token_by_credentials_send(ks_bool_t secure, const char *host, ks_port_t port, const char *path, const char *client_id, const char *client_secret, const char **token);
+KS_DECLARE(ks_status_t) blade_webrequest_oauth2_token_by_code_send(ks_bool_t secure, const char *host, ks_port_t port, const char *path, const char *client_id, const char *client_secret, const char *code, const char **token);
+
+
+KS_DECLARE(ks_status_t) blade_webresponse_create(blade_webresponse_t **bwresP, const char *status);
+KS_DECLARE(ks_status_t) blade_webresponse_load(blade_webresponse_t **bwresP, struct mg_connection *conn);
+KS_DECLARE(ks_status_t) blade_webresponse_destroy(blade_webresponse_t **bwresP);
+KS_DECLARE(ks_status_t) blade_webresponse_header_add(blade_webresponse_t *bwres, const char *header, const char *value);
+KS_DECLARE(const char *) blade_webresponse_header_get(blade_webresponse_t *bwres, const char *header);
+KS_DECLARE(ks_status_t) blade_webresponse_content_json_append(blade_webresponse_t *bwres, cJSON *json);
+KS_DECLARE(ks_status_t) blade_webresponse_content_string_append(blade_webresponse_t *bwres, const char *str);
+KS_DECLARE(ks_status_t) blade_webresponse_content_json_get(blade_webresponse_t *bwres, cJSON **json);
+KS_DECLARE(ks_status_t) blade_webresponse_send(blade_webresponse_t *bwres, struct mg_connection *conn);
+
+KS_END_EXTERN_C
+
+#endif
+
+/* For Emacs:
+ * Local Variables:
+ * mode:c
+ * indent-tabs-mode:t
+ * tab-width:4
+ * c-basic-offset:4
+ * End:
+ * For VIM:
+ * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
+ */
index 5c4b89c70ed80384316b88ca69ae4a4aa503837e..9df78d46b044ec0321b27cae7b58653af42d5f9d 100644 (file)
@@ -139,37 +139,31 @@ void command_quit(blade_handle_t *bh, char *args)
 
 int rest_service_test(blade_restmgr_t *brestmgr, struct mg_connection *conn, const char **captures)
 {
-       const struct mg_request_info *info = NULL;
+       blade_webrequest_t *request = NULL;
+       blade_webresponse_t *response = NULL;
        cJSON *json = NULL;
        cJSON *json_captures = NULL;
-       ks_sb_t *sb = NULL;
+       const char *token = NULL;
 
-       json = cJSON_CreateObject();
-
-       ks_sb_create(&sb, NULL, 0);
-
-       info = mg_get_request_info(conn);
-
-       cJSON_AddStringToObject(json, "method", info->request_method);
+       blade_webrequest_load(&request, conn);
 
+       // make a json object to send back
+       json = cJSON_CreateObject();
+       cJSON_AddStringToObject(json, "method", blade_webrequest_action_get(request));
        cJSON_AddItemToObject(json, "captures", (json_captures = cJSON_CreateArray()));
-
        for (int i = 0; captures[i]; ++i) cJSON_AddItemToArray(json_captures, cJSON_CreateString(captures[i]));
 
-       ks_sb_json(sb, json);
-
-       mg_printf(conn,
-               "HTTP/1.1 200 OK\r\n"
-               "Content-Length: %lu\r\n"
-               "Content-Type: text/plain\r\n"
-               "Connection: close\r\n\r\n",
-               ks_sb_length(sb));
-       
-       mg_write(conn, ks_sb_cstr(sb), ks_sb_length(sb));
-
-       ks_sb_destroy(&sb);
+       blade_webresponse_create(&response, "200");
+       blade_webresponse_content_json_append(response, json);
+       blade_webresponse_send(response, conn);
+       blade_webresponse_destroy(&response);
 
        cJSON_Delete(json);
+       blade_webrequest_destroy(&request);
+
+       //blade_webrequest_oauth2_token_by_credentials_send(KS_FALSE, "192.168.1.99", 80, "/oauth2/token.php", "testclient", "testpass", &token);
+       //
+       //ks_pool_free(&token);
 
        return 200;
 }
index e2ebb7c8e5a9162edd1ff97b599f6e9905c20b67..4f9beacee54c34c72a5689e394e4005afa39aa6e 100644 (file)
@@ -88,6 +88,7 @@ KS_DECLARE(ks_status_t) ks_sb_destroy(ks_sb_t **sbP)
        ks_assert(*sbP);
 
        sb = *sbP;
+       *sbP = NULL;
 
        if (sb->pool_owner) {
                ks_pool_t *pool = ks_pool_get(sb);