CURL HTTP headers (using visitors). (#103)
* PoC * Visitors in C, and I love it. * Minor. * Callack. * visitor instead of write_span. * Remove policy PoC. * CURL initial * adding visitor callback for headers * Minor. * adding convience method for bulding headers * az_span_seq * to str * minor * new line * Adding httpclient with curl send method implementation * minor * fix alignment * Include guard fix * Include guard fix * new line * completed keyVault POC with curl * add comments to POC * changes to make POC compatible with VS compiler * Remove functions with memory leaks. * Update sdk/core/core/inc/az_result.h Co-Authored-By: antkmsft <41349689+antkmsft@users.noreply.github.com> * Update sdk/core/core/inc/az_mock_curl.h Co-Authored-By: antkmsft <41349689+antkmsft@users.noreply.github.com> * Apply suggestions from code review Co-Authored-By: antkmsft <41349689+antkmsft@users.noreply.github.com> * address comments. * typo fix.
This commit is contained in:
Родитель
ee76b6e702
Коммит
38f62f59b1
|
@ -332,3 +332,4 @@ ASALocalRun/
|
|||
# CMake
|
||||
build/
|
||||
/cmake-build-debug
|
||||
.vscode/settings.json
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"configurations": [
|
||||
{
|
||||
"name": "x64-Debug",
|
||||
"generator": "Ninja",
|
||||
"configurationType": "Debug",
|
||||
"inheritEnvironments": [ "msvc_x64_x64" ],
|
||||
"buildRoot": "${projectDir}\\out\\build\\${name}",
|
||||
"installRoot": "${projectDir}\\out\\install\\${name}",
|
||||
"cmakeCommandArgs": "",
|
||||
"buildCommandArgs": "-v",
|
||||
"ctestCommandArgs": "",
|
||||
"variables": []
|
||||
}
|
||||
]
|
||||
}
|
|
@ -12,16 +12,18 @@ if(NOT CURL_FOUND)
|
|||
endif()
|
||||
|
||||
add_library (
|
||||
az_core
|
||||
src/az_assumptions.c
|
||||
src/az_base64.c
|
||||
src/az_json_read.c
|
||||
src/az_http_request.c
|
||||
src/az_pair.c
|
||||
src/az_span.c
|
||||
src/az_uri.c
|
||||
src/az_write_span_iter.c
|
||||
)
|
||||
az_core
|
||||
src/az_assumptions.c
|
||||
src/az_base64.c
|
||||
src/az_curl_adapter.c
|
||||
src/az_http_request.c
|
||||
src/az_json_read.c
|
||||
src/az_pair.c
|
||||
src/az_span.c
|
||||
src/az_span_seq.c
|
||||
src/az_uri.c
|
||||
src/az_write_span_iter.c
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
target_compile_options(az_core PRIVATE /W4 /WX)
|
||||
|
@ -44,6 +46,13 @@ target_link_libraries(curl_easy_perform_poc PRIVATE
|
|||
az_core
|
||||
CURL::libcurl)
|
||||
|
||||
target_link_libraries(az_core PRIVATE CURL::libcurl)
|
||||
|
||||
if (MOCK_CURL)
|
||||
MESSAGE("Will mock all calls to http client with static responses")
|
||||
add_definitions(-DMOCK_CURL="MOCK")
|
||||
endif()
|
||||
|
||||
if (UNIX)
|
||||
target_link_libraries(az_core_test PRIVATE m)
|
||||
target_link_libraries(curl_easy_perform_poc PRIVATE m)
|
||||
|
|
|
@ -2,11 +2,17 @@
|
|||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
||||
// warning C4204: nonstandard extension used: non-constant aggregate initializer
|
||||
#pragma warning(disable : 4204)
|
||||
|
||||
// warning C4221: nonstandard extension used: '...': cannot be initialized using address of
|
||||
// automatic variable '...'
|
||||
#pragma warning(disable : 4221)
|
||||
|
||||
// warning C4996: This function or variable may be unsafe. Consider using ..._s instead.
|
||||
#pragma warning(disable : 4996)
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef AZ_CFG_H
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
#include <az_result.h>
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <_az_cfg_prefix.h>
|
||||
|
||||
#define AZ_CONTRACT_ARG_NOT_NULL(arg) \
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef AZ_CURL_ADAPTER_H
|
||||
#define AZ_CURL_ADAPTER_H
|
||||
|
||||
#include <az_callback.h>
|
||||
#include <az_http_request.h>
|
||||
#include <az_span_seq.h>
|
||||
#include <az_write_span_iter.h>
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <_az_cfg_prefix.h>
|
||||
|
||||
typedef struct {
|
||||
CURL * p_curl;
|
||||
} az_curl;
|
||||
|
||||
AZ_INLINE az_result az_curl_init(az_curl * const out) {
|
||||
*out = (az_curl){
|
||||
.p_curl = curl_easy_init(),
|
||||
};
|
||||
curl_easy_setopt(out->p_curl, CURLOPT_FAILONERROR, 1);
|
||||
return AZ_OK;
|
||||
}
|
||||
|
||||
AZ_INLINE az_result az_curl_done(az_curl * const p) {
|
||||
AZ_CONTRACT_ARG_NOT_NULL(p);
|
||||
AZ_CONTRACT_ARG_NOT_NULL(p->p_curl);
|
||||
|
||||
curl_easy_cleanup(p->p_curl);
|
||||
p->p_curl = NULL;
|
||||
return AZ_OK;
|
||||
}
|
||||
|
||||
#include <_az_cfg_suffix.h>
|
||||
|
||||
#endif
|
|
@ -11,7 +11,7 @@
|
|||
|
||||
#include <_az_cfg_prefix.h>
|
||||
|
||||
// request
|
||||
#include <stddef.h>
|
||||
|
||||
typedef struct {
|
||||
az_const_span method;
|
||||
|
@ -25,16 +25,15 @@ az_result az_http_request_to_spans(
|
|||
az_http_request const * const p_request,
|
||||
az_span_visitor const span_visitor);
|
||||
|
||||
typedef struct {
|
||||
az_pair_seq headers;
|
||||
} az_http_standard_policy;
|
||||
az_result az_http_url_to_spans(
|
||||
az_http_request const * const p_request,
|
||||
az_span_visitor const span_visitor);
|
||||
|
||||
/**
|
||||
* Note: `*p_request` should not be used after `*out` is destroyed.
|
||||
*/
|
||||
az_result az_http_standard_policy_create(
|
||||
az_http_request * const p_request,
|
||||
az_http_standard_policy * const out);
|
||||
az_result az_http_get_url_size(az_http_request const * const p_request, size_t * out);
|
||||
|
||||
az_result az_http_url_to_new_str(az_http_request const * const p_request, char ** const out);
|
||||
|
||||
az_result az_build_header(az_pair const * header, az_span_visitor const visitor);
|
||||
|
||||
#include <_az_cfg_suffix.h>
|
||||
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef AZ_HTTP_RESPONSE_H
|
||||
#define AZ_HTTP_RESPONSE_H
|
||||
|
||||
#include <az_span.h>
|
||||
#include <az_result.h>
|
||||
|
||||
#include <_az_cfg_prefix.h>
|
||||
|
||||
typedef struct {
|
||||
az_span_visitor header_name;
|
||||
az_span_visitor header_value;
|
||||
az_span_visitor body;
|
||||
} az_http_response;
|
||||
|
||||
az_result az_http_response_parse(
|
||||
az_const_span const buffer,
|
||||
az_http_response const response);
|
||||
|
||||
#include <_az_cfg_suffix.h>
|
||||
|
||||
#endif
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef AZ_MOCK_CURL_H
|
||||
#define AZ_MOCK_CURL_H
|
||||
|
||||
#include <az_http_request.h>
|
||||
|
||||
|
||||
#include <_az_cfg_prefix.h>
|
||||
|
||||
AZ_INLINE az_result az_send_request_impl(
|
||||
az_http_request const * const p_request,
|
||||
az_span * const response,
|
||||
bool allow_allocate) {
|
||||
return AZ_ERROR_NOT_IMPLEMENTED;
|
||||
};
|
||||
|
||||
#include <_az_cfg_suffix.h>
|
||||
|
||||
#endif
|
|
@ -4,6 +4,7 @@
|
|||
#ifndef AZ_PAIR_H
|
||||
#define AZ_PAIR_H
|
||||
|
||||
#include <az_callback.h>
|
||||
#include <az_contract.h>
|
||||
#include <az_span.h>
|
||||
#include <az_callback.h>
|
||||
|
@ -25,7 +26,7 @@ typedef struct {
|
|||
/// @az_pair_visitor is a callback with one argument @az_pair.
|
||||
AZ_CALLBACK_DECL(az_pair_visitor, az_pair)
|
||||
|
||||
/// @az_pair_seq is a @az_pair sequence visitor.
|
||||
/// @az_pair_seq is a @az_pair sequence visitor.
|
||||
AZ_CALLBACK_DECL(az_pair_seq, az_pair_visitor)
|
||||
|
||||
/**
|
||||
|
|
|
@ -53,7 +53,9 @@ AZ_INLINE bool az_succeeded(az_result result) { return (result & AZ_ERROR_FLAG)
|
|||
enum {
|
||||
AZ_ERROR_ARG = AZ_MAKE_ERROR(AZ_CORE_FACILITY, 1),
|
||||
AZ_ERROR_BUFFER_OVERFLOW = AZ_MAKE_ERROR(AZ_CORE_FACILITY, 2),
|
||||
|
||||
AZ_ERROR_OUT_OF_MEMORY = AZ_MAKE_ERROR(AZ_CORE_FACILITY, 3),
|
||||
AZ_ERROR_NOT_IMPLEMENTED = AZ_MAKE_ERROR(AZ_CORE_FACILITY, 4),
|
||||
|
||||
AZ_ERROR_EOF = AZ_MAKE_ERROR(AZ_STD_FACILITY, 0xFFFF),
|
||||
};
|
||||
|
||||
|
|
|
@ -258,6 +258,21 @@ az_result az_span_replace(
|
|||
#define AZ_SPAN(ARRAY) \
|
||||
{ .begin = ARRAY, .size = AZ_ARRAY_SIZE(ARRAY) }
|
||||
|
||||
/**
|
||||
* ```c
|
||||
* typedef struct {
|
||||
* az_result (*func)(ptrdiff_t, az_const_span);
|
||||
* ptrdiff_t data;
|
||||
* } az_span_visitor;
|
||||
* ```
|
||||
*
|
||||
* Example of usage
|
||||
*
|
||||
* ```c
|
||||
* az_span_visitor const visitor = ...;
|
||||
* visitor.func(visitor.data, AZ_CONST_SPAN("Something"));
|
||||
* ```
|
||||
*/
|
||||
AZ_CALLBACK_DECL(az_span_visitor, az_const_span)
|
||||
|
||||
#include <_az_cfg_suffix.h>
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef AZ_SPAN_ITER_H
|
||||
#define AZ_SPAN_ITER_H
|
||||
|
||||
#include <az_iter_data.h>
|
||||
|
||||
#include <_az_cfg_prefix.h>
|
||||
|
||||
typedef struct az_span_iter az_span_iter;
|
||||
|
||||
typedef az_result (*az_span_iter_func)(az_span_iter * const p_i, az_span * const out);
|
||||
|
||||
struct az_span_iter {
|
||||
az_span_iter_func func;
|
||||
az_iter_data data;
|
||||
};
|
||||
|
||||
AZ_INLINE az_result az_span_iter_call(az_span_iter * const p_i, az_span * const out) {
|
||||
AZ_CONTRACT_ARG_NOT_NULL(p_i);
|
||||
AZ_CONTRACT_ARG_NOT_NULL(p_i->func);
|
||||
AZ_CONTRACT_ARG_NOT_NULL(out);
|
||||
|
||||
return p_i->func(p_i, out);
|
||||
}
|
||||
|
||||
#include <_az_cfg_suffix.h>
|
||||
|
||||
#endif
|
|
@ -0,0 +1,28 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#ifndef AZ_SPAN_SEQ_H
|
||||
#define AZ_SPAN_SEQ_H
|
||||
|
||||
#include <az_span.h>
|
||||
|
||||
#include <_az_cfg_prefix.h>
|
||||
|
||||
AZ_CALLBACK_DECL(az_span_seq, az_span_visitor)
|
||||
|
||||
typedef struct {
|
||||
az_const_span const * begin;
|
||||
size_t size;
|
||||
} az_span_span;
|
||||
|
||||
az_span_seq az_span_span_to_seq(az_span_span const * const p_span);
|
||||
|
||||
az_result az_span_add_size(size_t * const p_size, az_const_span const span);
|
||||
|
||||
az_result az_span_seq_size(az_span_seq const seq, size_t * const out_size);
|
||||
|
||||
az_result az_span_seq_to_new_str(az_span_seq const seq, char ** const out);
|
||||
|
||||
#include <_az_cfg_suffix.h>
|
||||
|
||||
#endif
|
|
@ -0,0 +1,34 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <az_curl_adapter.h>
|
||||
|
||||
#include <_az_cfg.h>
|
||||
|
||||
typedef struct {
|
||||
struct curl_slist * p_list;
|
||||
} az_headers_data;
|
||||
|
||||
AZ_CALLBACK_DATA(az_create_headers_callback, az_headers_data *, az_pair_visitor)
|
||||
AZ_CALLBACK_DATA(az_pair_callback, az_pair const *, az_span_seq)
|
||||
|
||||
az_result az_headers_to_curl(az_headers_data * const p_state, az_pair const header) {
|
||||
const az_span_seq token_seq = az_pair_callback(&header, az_build_header);
|
||||
char * str_header;
|
||||
AZ_RETURN_IF_FAILED(az_span_seq_to_new_str(token_seq, &str_header));
|
||||
|
||||
p_state->p_list = curl_slist_append(p_state->p_list, str_header);
|
||||
|
||||
free(str_header);
|
||||
return AZ_OK;
|
||||
}
|
||||
|
||||
az_result az_build_headers(az_http_request const * const p_request, az_headers_data * headers) {
|
||||
// create callback for visitor
|
||||
az_pair_visitor const pair_visitor = az_create_headers_callback(headers, az_headers_to_curl);
|
||||
|
||||
az_pair_seq const request_headers_seq = p_request->headers;
|
||||
AZ_RETURN_IF_FAILED(request_headers_seq.func(request_headers_seq.data, pair_visitor));
|
||||
|
||||
return AZ_OK;
|
||||
}
|
|
@ -4,9 +4,12 @@
|
|||
#include <az_http_request.h>
|
||||
|
||||
#include <az_contract.h>
|
||||
#include <az_span_seq.h>
|
||||
#include <az_str.h>
|
||||
#include <az_write_span_iter.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <_az_cfg.h>
|
||||
|
||||
#define AZ_CRLF "\r\n"
|
||||
|
@ -14,94 +17,130 @@
|
|||
static az_const_span const az_crlf = AZ_CONST_STR(AZ_CRLF);
|
||||
|
||||
typedef struct {
|
||||
az_span_visitor visitor;
|
||||
az_span_visitor spans;
|
||||
az_const_span separator;
|
||||
} az_data;
|
||||
} az_query_state;
|
||||
|
||||
AZ_CALLBACK_DATA(az_data_to_pair_visitor, az_data *, az_pair_visitor)
|
||||
AZ_CALLBACK_DATA(az_query_state_to_pair_visitor, az_query_state *, az_pair_visitor)
|
||||
|
||||
az_result az_query_to_spans_func(az_data * const p, az_pair const pair) {
|
||||
az_result az_query_to_spans(az_query_state * const p, az_pair const pair) {
|
||||
AZ_CONTRACT_ARG_NOT_NULL(p);
|
||||
|
||||
az_span_visitor const visitor = p->visitor;
|
||||
AZ_RETURN_IF_FAILED(visitor.func(visitor.data, p->separator));
|
||||
AZ_RETURN_IF_FAILED(visitor.func(visitor.data, pair.key));
|
||||
AZ_RETURN_IF_FAILED(visitor.func(visitor.data, AZ_STR("=")));
|
||||
AZ_RETURN_IF_FAILED(visitor.func(visitor.data, pair.value));
|
||||
az_span_visitor const spans = p->spans;
|
||||
AZ_RETURN_IF_FAILED(spans.func(spans.data, p->separator));
|
||||
AZ_RETURN_IF_FAILED(spans.func(spans.data, pair.key));
|
||||
AZ_RETURN_IF_FAILED(spans.func(spans.data, AZ_STR("=")));
|
||||
AZ_RETURN_IF_FAILED(spans.func(spans.data, pair.value));
|
||||
p->separator = AZ_STR("&");
|
||||
return AZ_OK;
|
||||
}
|
||||
|
||||
az_result az_header_to_spans_func(az_data * const p, az_pair const pair) {
|
||||
az_result az_build_header(az_pair const * header, az_span_visitor const visitor) {
|
||||
AZ_RETURN_IF_FAILED(visitor.func(visitor.data, header->key));
|
||||
AZ_RETURN_IF_FAILED(visitor.func(visitor.data, AZ_STR(": ")));
|
||||
AZ_RETURN_IF_FAILED(visitor.func(visitor.data, header->value));
|
||||
return AZ_OK;
|
||||
}
|
||||
|
||||
AZ_CALLBACK_DATA(az_span_visitor_to_pair_visitor, az_span_visitor const *, az_pair_visitor)
|
||||
|
||||
az_result az_header_to_spans(az_span_visitor const * const p, az_pair const pair) {
|
||||
AZ_CONTRACT_ARG_NOT_NULL(p);
|
||||
|
||||
az_span_visitor const visitor = p->visitor;
|
||||
AZ_RETURN_IF_FAILED(visitor.func(visitor.data, pair.key));
|
||||
AZ_RETURN_IF_FAILED(visitor.func(visitor.data, AZ_STR(": ")));
|
||||
AZ_RETURN_IF_FAILED(visitor.func(visitor.data, pair.value));
|
||||
AZ_RETURN_IF_FAILED(visitor.func(visitor.data, az_crlf));
|
||||
AZ_RETURN_IF_FAILED(az_build_header(&pair, *p));
|
||||
AZ_RETURN_IF_FAILED(p->func(p->data, az_crlf));
|
||||
return AZ_OK;
|
||||
}
|
||||
|
||||
az_result az_http_request_to_spans(
|
||||
az_http_request const* const p_request,
|
||||
az_span_visitor const visitor) {
|
||||
az_http_request const * const p_request,
|
||||
az_span_visitor const spans) {
|
||||
AZ_CONTRACT_ARG_NOT_NULL(p_request);
|
||||
|
||||
az_data data = {
|
||||
.visitor = visitor,
|
||||
.separator = AZ_STR("?"),
|
||||
};
|
||||
|
||||
// a request line
|
||||
{
|
||||
AZ_RETURN_IF_FAILED(visitor.func(visitor.data, p_request->method));
|
||||
AZ_RETURN_IF_FAILED(visitor.func(visitor.data, AZ_STR(" ")));
|
||||
AZ_RETURN_IF_FAILED(visitor.func(visitor.data, p_request->path));
|
||||
AZ_RETURN_IF_FAILED(spans.func(spans.data, p_request->method));
|
||||
AZ_RETURN_IF_FAILED(spans.func(spans.data, AZ_STR(" ")));
|
||||
AZ_RETURN_IF_FAILED(spans.func(spans.data, p_request->path));
|
||||
// query parameters
|
||||
{
|
||||
az_query_state state = {
|
||||
.spans = spans,
|
||||
.separator = AZ_STR("?"),
|
||||
};
|
||||
az_pair_visitor const pair_visitor
|
||||
= az_query_state_to_pair_visitor(&state, az_query_to_spans);
|
||||
az_pair_seq const query = p_request->query;
|
||||
az_pair_visitor const pair_visitor = az_data_to_pair_visitor(&data, az_query_to_spans_func);
|
||||
// for each query parameter apply `pair_visitor`
|
||||
AZ_RETURN_IF_FAILED(query.func(query.data, pair_visitor));
|
||||
}
|
||||
AZ_RETURN_IF_FAILED(visitor.func(visitor.data, AZ_STR(" HTTP/1.1" AZ_CRLF)));
|
||||
AZ_RETURN_IF_FAILED(spans.func(spans.data, AZ_STR(" HTTP/1.1" AZ_CRLF)));
|
||||
}
|
||||
|
||||
// headers
|
||||
{
|
||||
az_pair_visitor const pair_visitor
|
||||
= az_span_visitor_to_pair_visitor(&spans, az_header_to_spans);
|
||||
az_pair_seq const headers = p_request->headers;
|
||||
az_pair_visitor const pair_visitor = az_data_to_pair_visitor(&data, az_header_to_spans_func);
|
||||
AZ_RETURN_IF_FAILED(headers.func(headers.data, pair_visitor));
|
||||
}
|
||||
|
||||
// empty line
|
||||
AZ_RETURN_IF_FAILED(visitor.func(visitor.data, az_crlf));
|
||||
// an empty line
|
||||
AZ_RETURN_IF_FAILED(spans.func(spans.data, az_crlf));
|
||||
|
||||
// body.
|
||||
AZ_RETURN_IF_FAILED(visitor.func(visitor.data, p_request->body));
|
||||
AZ_RETURN_IF_FAILED(spans.func(spans.data, p_request->body));
|
||||
|
||||
return AZ_OK;
|
||||
}
|
||||
|
||||
az_pair const az_http_standard_header
|
||||
= { .key = AZ_CONST_STR("ContentType"), .value = AZ_CONST_STR("text/plain; charset=utf-8") };
|
||||
az_result az_http_url_to_spans(
|
||||
az_http_request const * const p_request,
|
||||
az_span_visitor const spans) {
|
||||
AZ_CONTRACT_ARG_NOT_NULL(p_request);
|
||||
|
||||
AZ_CALLBACK_DATA(az_http_standard_policy_to_pair_seq, az_http_standard_policy const *, az_pair_seq)
|
||||
|
||||
az_result az_http_standard_policy_func(
|
||||
az_http_standard_policy const * const p_data,
|
||||
az_pair_visitor const visitor) {
|
||||
AZ_RETURN_IF_FAILED(visitor.func(visitor.data, az_http_standard_header));
|
||||
// host path
|
||||
{
|
||||
az_pair_seq const headers = p_data->headers;
|
||||
AZ_RETURN_IF_FAILED(headers.func(headers.data, visitor));
|
||||
AZ_RETURN_IF_FAILED(spans.func(spans.data, p_request->path));
|
||||
// query parameters
|
||||
{
|
||||
az_query_state state = {
|
||||
.spans = spans,
|
||||
.separator = AZ_STR("?"),
|
||||
};
|
||||
az_pair_visitor const pair_visitor
|
||||
= az_query_state_to_pair_visitor(&state, az_query_to_spans);
|
||||
az_pair_seq const query = p_request->query;
|
||||
// for each query parameter apply `pair_visitor`
|
||||
AZ_RETURN_IF_FAILED(query.func(query.data, pair_visitor));
|
||||
}
|
||||
}
|
||||
return AZ_OK;
|
||||
}
|
||||
|
||||
az_result az_http_standard_policy_create(
|
||||
az_http_request * const p_request,
|
||||
az_http_standard_policy * const out) {
|
||||
out->headers = p_request->headers;
|
||||
p_request->headers = az_http_standard_policy_to_pair_seq(out, az_http_standard_policy_func);
|
||||
AZ_CALLBACK_DATA(az_size_callback, size_t *, az_span_visitor)
|
||||
|
||||
az_result az_http_get_url_size(az_http_request const * const p_request, size_t * out) {
|
||||
return az_http_url_to_spans(p_request, az_size_callback(out, az_span_add_size));
|
||||
}
|
||||
|
||||
az_result az_http_url_to_new_str(az_http_request const * const p_request, char ** const out) {
|
||||
*out = NULL;
|
||||
size_t size = 0;
|
||||
AZ_RETURN_IF_FAILED(az_http_get_url_size(p_request, &size));
|
||||
size += 1;
|
||||
uint8_t * const p = (uint8_t *)malloc(size);
|
||||
if (p == NULL) {
|
||||
return AZ_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
az_write_span_iter i = az_write_span_iter_create((az_span){ .begin = p, .size = size });
|
||||
az_span_visitor sv = az_write_span_iter_to_span_visitor(&i);
|
||||
az_result const result = az_http_url_to_spans(p_request, sv);
|
||||
az_write_span_iter_write(&i, AZ_STR("\0"));
|
||||
if (az_failed(result)) {
|
||||
free(p);
|
||||
return result;
|
||||
}
|
||||
*out = (char *)p;
|
||||
return AZ_OK;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <az_http_response.h>
|
||||
|
||||
#include <az_span_reader.h>
|
||||
|
||||
#include <_az_cfg.h>
|
||||
|
||||
az_result az_http_response_parse(az_const_span const span, az_http_response const response) {
|
||||
az_span_reader reader = az_span_reader_create(span);
|
||||
|
||||
// https://www.w3.org/Protocols/rfc2616/rfc2616-sec6.html
|
||||
// HTTP/1.1 200 OK
|
||||
//
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
#include <az_span_seq.h>
|
||||
|
||||
#include <az_str.h>
|
||||
#include <az_write_span_iter.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <_az_cfg.h>
|
||||
|
||||
//
|
||||
|
||||
AZ_CALLBACK_DATA(az_span_span_callback, az_span_span const *, az_span_seq)
|
||||
|
||||
az_result az_span_span_to_seq_func(
|
||||
az_span_span const * const context,
|
||||
az_span_visitor const visitor) {
|
||||
AZ_CONTRACT_ARG_NOT_NULL(context);
|
||||
|
||||
size_t const size = context->size;
|
||||
az_const_span const * begin = context->begin;
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
AZ_RETURN_IF_FAILED(visitor.func(visitor.data, begin[i]));
|
||||
}
|
||||
return AZ_OK;
|
||||
}
|
||||
|
||||
az_span_seq az_span_span_to_seq(az_span_span const * const p_span) {
|
||||
return az_span_span_callback(p_span, az_span_span_to_seq_func);
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
AZ_CALLBACK_DATA(az_size_callback, size_t *, az_span_visitor)
|
||||
|
||||
az_result az_span_add_size(size_t * const p_size, az_const_span const span) {
|
||||
*p_size += span.size;
|
||||
return AZ_OK;
|
||||
}
|
||||
|
||||
az_result az_span_seq_size(az_span_seq const seq, size_t * const out_size) {
|
||||
AZ_CONTRACT_ARG_NOT_NULL(out_size);
|
||||
|
||||
*out_size = 0;
|
||||
return seq.func(seq.data, az_size_callback(out_size, az_span_add_size));
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
az_result az_span_seq_to_str(az_span_seq const seq, az_span const span) {
|
||||
az_write_span_iter i = az_write_span_iter_create(span);
|
||||
AZ_RETURN_IF_FAILED(seq.func(seq.data, az_write_span_iter_to_span_visitor(&i)));
|
||||
AZ_RETURN_IF_FAILED(az_write_span_iter_write(&i, AZ_STR("\0")));
|
||||
return AZ_OK;
|
||||
}
|
||||
|
||||
//
|
||||
|
||||
az_result az_span_seq_to_new_str(az_span_seq const seq, char * * const out) {
|
||||
*out = NULL;
|
||||
size_t size;
|
||||
AZ_RETURN_IF_FAILED(az_span_seq_size(seq, &size));
|
||||
size += 1;
|
||||
uint8_t * const p = (uint8_t *)malloc(size);
|
||||
if (p == NULL) {
|
||||
return AZ_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
az_result const result = az_span_seq_to_str(seq, (az_span){ .begin = p, .size = size });
|
||||
if (az_failed(result)) {
|
||||
free(p);
|
||||
return result;
|
||||
}
|
||||
*out = (char *)p;
|
||||
return AZ_OK;
|
||||
}
|
|
@ -3,39 +3,34 @@
|
|||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include <az_http_request.h>
|
||||
#include <az_json_read.h>
|
||||
#include <az_pair.h>
|
||||
#include <az_write_span_iter.h>
|
||||
|
||||
#include <_az_cfg.h>
|
||||
|
||||
int main(int _, char ** argv) {
|
||||
CURL * curl;
|
||||
curl = curl_easy_init();
|
||||
int result;
|
||||
int exit_code = 0;
|
||||
|
||||
FILE * f;
|
||||
f = fopen("here.jpg", "wb");
|
||||
int main() {
|
||||
|
||||
printf("\n1...");
|
||||
/****** ------------- Create request from arrays ---------******/
|
||||
az_pair const query_array[] = { { .key = AZ_STR("key"), .value = AZ_STR("value") } };
|
||||
az_pair_span const query = AZ_SPAN(query_array);
|
||||
az_pair const header_array[] = { { .key = AZ_STR("key"), .value = AZ_STR("value") } };
|
||||
az_pair_span const header = AZ_SPAN(header_array);
|
||||
|
||||
curl_easy_setopt(
|
||||
curl,
|
||||
CURLOPT_URL,
|
||||
"http://www.laboratoons.com/wp-content/uploads/2018/11/Alternativas-A.jpg");
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEDATA, f);
|
||||
curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1l);
|
||||
az_const_span req_body
|
||||
= AZ_STR("grant_type=client_credentials&client_id=4317a660-6bfb-4585-9ce9-8f222314879c&"
|
||||
"client_secret=O2CT[Y:dkTqblml5V/T]ZEi9x1W1zoBW&resource=https://vault.azure.net");
|
||||
az_http_request const request = {
|
||||
.method = AZ_STR("POST"),
|
||||
.path
|
||||
= AZ_STR("https://login.microsoftonline.com/72f988bf-86f1-41af-91ab-2d7cd011db47/oauth2/token"),
|
||||
.query = az_pair_span_to_seq(&query),
|
||||
.headers = az_pair_span_to_seq(&header),
|
||||
.body = req_body,
|
||||
};
|
||||
|
||||
result = curl_easy_perform(curl);
|
||||
|
||||
if (result == CURLE_OK) {
|
||||
printf("\n Done.");
|
||||
} else {
|
||||
printf("\n Error: %s\n", curl_easy_strerror(result));
|
||||
}
|
||||
|
||||
// clean up
|
||||
fclose(f);
|
||||
curl_easy_cleanup(curl);
|
||||
|
||||
printf("Hello world");
|
||||
return _;
|
||||
return exit_code;
|
||||
}
|
||||
|
|
|
@ -6,11 +6,13 @@
|
|||
#include <az_json_read.h>
|
||||
#include <az_span_reader.h>
|
||||
#include <az_uri.h>
|
||||
#include <az_span_seq.h>
|
||||
#include <az_write_span_iter.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
int exit_code = 0;
|
||||
|
||||
|
@ -486,31 +488,68 @@ int main() {
|
|||
az_span out = az_write_span_iter_result(&wi);
|
||||
TEST_ASSERT(az_const_span_eq(az_span_to_const_span(out), expected));
|
||||
}
|
||||
// HTTP Builder with policies.
|
||||
{
|
||||
printf("----Test: az_http_request_to_url_span\n");
|
||||
az_write_span_iter wi = az_write_span_iter_create((az_span)AZ_SPAN(buffer));
|
||||
az_span_visitor sv = az_write_span_iter_to_span_visitor(&wi);
|
||||
az_const_span const expected = AZ_STR( //
|
||||
"GET /foo?hello=world!&x=42 HTTP/1.1\r\n"
|
||||
"ContentType: text/plain; charset=utf-8\r\n"
|
||||
"some: xml\r\n"
|
||||
"xyz: very_long\r\n"
|
||||
"\r\n"
|
||||
"{ \"somejson\": true }");
|
||||
az_http_request new_request = request;
|
||||
az_http_standard_policy s;
|
||||
{
|
||||
az_result const result = az_http_standard_policy_create(&new_request, &s);
|
||||
TEST_ASSERT(result == AZ_OK);
|
||||
}
|
||||
{
|
||||
az_result const result = az_http_request_to_spans(&new_request, sv);
|
||||
TEST_ASSERT(result == AZ_OK);
|
||||
}
|
||||
az_const_span const expected = AZ_STR("/foo?hello=world!&x=42");
|
||||
az_result const result = az_http_url_to_spans(&request, sv);
|
||||
TEST_ASSERT(result == AZ_OK);
|
||||
az_span out = az_write_span_iter_result(&wi);
|
||||
TEST_ASSERT(az_const_span_eq(az_span_to_const_span(out), expected));
|
||||
}
|
||||
// url size
|
||||
{
|
||||
printf("----Test: az_http_get_url_size\n");
|
||||
size_t x = 0;
|
||||
size_t const expected = 22;
|
||||
az_result const result = az_http_get_url_size(&request, &x);
|
||||
TEST_ASSERT(result == AZ_OK);
|
||||
TEST_ASSERT(expected == x);
|
||||
}
|
||||
// url to str
|
||||
{
|
||||
printf("----Test: az_http_url_to_new_str\n");
|
||||
char * p;
|
||||
az_result const result = az_http_url_to_new_str(&request, &p);
|
||||
TEST_ASSERT(result == AZ_OK);
|
||||
TEST_ASSERT(strcmp(p, "/foo?hello=world!&x=42") == 0);
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
|
||||
// span seq size
|
||||
{
|
||||
az_const_span const array[] = {
|
||||
AZ_STR("Hello"),
|
||||
AZ_STR(" "),
|
||||
AZ_STR("world!"),
|
||||
};
|
||||
az_span_span const span = AZ_SPAN(array);
|
||||
az_span_seq const seq = az_span_span_to_seq(&span);
|
||||
size_t s = 42;
|
||||
az_result const result = az_span_seq_size(seq, &s);
|
||||
TEST_ASSERT(result == AZ_OK);
|
||||
TEST_ASSERT(s == 12);
|
||||
}
|
||||
|
||||
// span seq to new str
|
||||
{
|
||||
az_const_span const array[] = {
|
||||
AZ_STR("Hello"),
|
||||
AZ_STR(" "),
|
||||
AZ_STR("world!"),
|
||||
};
|
||||
az_span_span const span = AZ_SPAN(array);
|
||||
az_span_seq const seq = az_span_span_to_seq(&span);
|
||||
//
|
||||
char * p;
|
||||
az_result const result = az_span_seq_to_new_str(seq, &p);
|
||||
TEST_ASSERT(result == AZ_OK);
|
||||
TEST_ASSERT(strcmp(p, "Hello world!") == 0);
|
||||
free(p);
|
||||
}
|
||||
|
||||
{
|
||||
az_const_span const expected = AZ_STR("@###copy#copy#make some zero-terminated strings#make "
|
||||
"some\0zero-terminated\0strings\0####@");
|
||||
|
|
Загрузка…
Ссылка в новой задаче