675 lines
18 KiB
C
675 lines
18 KiB
C
/*
|
|
* 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;
|
|
const 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) {
|
|
const 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;
|
|
const 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;
|
|
const 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;
|
|
const 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) {
|
|
const 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:
|
|
*/
|