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:
Sergey Shandar 2019-10-23 08:36:38 -07:00 коммит произвёл GitHub
Родитель ee76b6e702
Коммит 38f62f59b1
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
20 изменённых файлов: 478 добавлений и 144 удалений

1
.gitignore поставляемый
Просмотреть файл

@ -332,3 +332,4 @@ ASALocalRun/
# CMake
build/
/cmake-build-debug
.vscode/settings.json

16
CMakeSettings.json Normal file
Просмотреть файл

@ -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####@");