jaulib v1.3.8
Jau Support Library (C++, Java, ..)
Loading...
Searching...
No Matches
test_httpstream01.cpp
Go to the documentation of this file.
1/*
2 * Author: Sven Gothel <sgothel@jausoft.com>
3 * Copyright (c) 2024 Gothel Software e.K.
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining
6 * a copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sublicense, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25#include <cassert>
26#include <cinttypes>
27#include <cstring>
28
29#include <memory>
30#include <thread>
31#include <pthread.h>
32
33#include <jau/test/catch2_ext.hpp>
34
35#include <jau/file_util.hpp>
36#include <jau/io_util.hpp>
37#include <jau/byte_stream.hpp>
38
39#include <jau/debug.hpp>
40
41extern "C" {
42 #include <unistd.h>
43}
44
45using namespace jau::fractions_i64_literals;
46using namespace jau::int_literals;
47
49 public:
50 const std::string url_input_root = "http://httpbin.org/post";
51 // const std::string url_input_root = "https://ssd.jpl.nasa.gov/api/horizons_file.api";
52 const std::string HttpBoundarySep = "--";
53 const std::string HttpBoundary = "affedeadbeaf";
54 const std::string CRLF = "\r\n";
55 const std::string HorizonCmd01 =
56 "!$$SOF\n"
57 "COMMAND='199'\n"
58 "TABLE_TYPE='Vector'\n"
59 "CENTER='@010'\n"
60 "REF_PLANE='Ecliptic'\n"
61 "START_TIME='2024-01-01 00:00:00'\n"
62 "STOP_TIME='2024-01-01 00:00:01'\n";
63
64 TestHttpStream01() = default;
65
67
70 jau::PLAIN_PRINT(true, "http not supported, abort\n");
71 return;
72 }
73 if( catch_auto_run ) {
74 jau::PLAIN_PRINT(true, "not enabled on auto-run\n");
75 return;
76 }
77 jau::io::http::PostRequestPtr postReq = std::make_unique<jau::io::http::PostRequest>();
78 postReq->header.emplace("Content-Type", "multipart/form-data; boundary="+HttpBoundary);
79 postReq->body.append(HttpBoundarySep).append(HttpBoundary).append(CRLF);
80 postReq->body.append("Content-Disposition: form-data; name=\"format\"").append(CRLF).append(CRLF);
81 postReq->body.append("text").append(CRLF);
82 postReq->body.append(HttpBoundarySep).append(HttpBoundary).append(CRLF);
83 postReq->body.append(R"(Content-Disposition: form-data; name="input"; filename="a.cmd")").append(CRLF);
84 postReq->body.append("Content-type: application/octet-stream").append(CRLF).append(CRLF);
85 postReq->body.append(HorizonCmd01).append(CRLF);
86 postReq->body.append(HttpBoundarySep).append(HttpBoundary).append(HttpBoundarySep).append(CRLF);
87
89 jau::relaxed_atomic_uint64 consumed_byte_count;
90 jau::io::SyncStreamResponseRef res = jau::io::read_url_stream_sync(handle, url_input_root, std::move(postReq), nullptr,
91 [&consumed_byte_count](jau::io::SyncStreamResponse& response, const uint8_t* data , size_t len, bool is_final) -> bool {
92 std::cout << "XXX: len " << len << "/" << response.content_length << ", final " << is_final << std::endl;
93 if( nullptr != data && len > 0 ) {
94 std::string d(data, data+len);
95 std::cout << " > " << d << std::endl;
96 }
97 consumed_byte_count.fetch_add(len);
98 return true;
99 });
100 REQUIRE( nullptr != res );
101
103
104 jau::PLAIN_PRINT(true, "test01_post_sync_ok.X Done: consumed %" PRIu64 " / total %" PRIu64 " / content_len %" PRIu64 ", result %d",
105 consumed_byte_count.load(), res->total_read, res->content_length, (int)res->result.load() );
106
107 REQUIRE( res->header_resp.completed() == true );
108 REQUIRE( res->header_resp.response_code() == 200 );
109 if( res->has_content_length ) {
110 REQUIRE( res->content_length == consumed_byte_count );
111 }
112 REQUIRE( res->total_read == consumed_byte_count );
113 REQUIRE( res->success() );
114 }
115
118 jau::PLAIN_PRINT(true, "http not supported, abort\n");
119 return;
120 }
121 if( catch_auto_run ) {
122 jau::PLAIN_PRINT(true, "not enabled on auto-run\n");
123 return;
124 }
125 jau::io::http::PostRequestPtr postReq = std::make_unique<jau::io::http::PostRequest>();
126 postReq->header.emplace("Content-Type", "multipart/form-data; boundary="+HttpBoundary);
127 postReq->body.append(HttpBoundarySep).append(HttpBoundary).append(CRLF);
128 postReq->body.append("Content-Disposition: form-data; name=\"format\"").append(CRLF).append(CRLF);
129 postReq->body.append("text").append(CRLF);
130 postReq->body.append(HttpBoundarySep).append(HttpBoundary).append(CRLF);
131 postReq->body.append(R"(Content-Disposition: form-data; name="input"; filename="a.cmd")").append(CRLF);
132 postReq->body.append("Content-type: application/octet-stream").append(CRLF).append(CRLF);
133 postReq->body.append(HorizonCmd01).append(CRLF);
134 postReq->body.append(HttpBoundarySep).append(HttpBoundary).append(HttpBoundarySep).append(CRLF);
135
137 jau::relaxed_atomic_uint64 consumed_byte_count;
138 jau::io::AsyncStreamResponseRef res = jau::io::read_url_stream_async(handle, url_input_root, std::move(postReq), nullptr,
139 [&consumed_byte_count](jau::io::AsyncStreamResponse& response, const uint8_t* data , size_t len, bool is_final) -> bool {
140 std::cout << "XXX: len " << len << "/" << response.content_length << ", final " << is_final << std::endl;
141 if( nullptr != data && len > 0 ) {
142 std::string d(data, data+len);
143 std::cout << " > " << d << std::endl;
144 }
145 consumed_byte_count.fetch_add(len);
146 return true;
147 });
148 REQUIRE( nullptr != res );
149
150 res->thread.join();
152
153 jau::PLAIN_PRINT(true, "test11_post_async_ok.X Done: consumed %" PRIu64 " / total %" PRIu64 " / content_len %" PRIu64 ", result %d",
154 consumed_byte_count.load(), res->total_read.load(), res->content_length.load(), (int)res->result.load() );
155
156 REQUIRE( res->header_resp.completed() == true );
157 REQUIRE( res->header_resp.response_code() == 200 );
158 if( res->has_content_length ) {
159 REQUIRE( res->content_length == consumed_byte_count );
160 // REQUIRE( res->content_length == HorizonCmd01.length() );
161 }
162 REQUIRE( res->total_read == consumed_byte_count );
163 REQUIRE( res->success() );
164 }
165
166};
167
168METHOD_AS_TEST_CASE( TestHttpStream01::test01_post_sync_ok, "TestIOStream01 - test01_post_sync_ok");
169METHOD_AS_TEST_CASE( TestHttpStream01::test11_post_async_ok, "TestIOStream01 - test11_post_async_ok");
170
const std::string HorizonCmd01
~TestHttpStream01()=default
const std::string HttpBoundary
const std::string CRLF
TestHttpStream01()=default
const std::string HttpBoundarySep
const std::string url_input_root
ordered_atomic< uint64_t, std::memory_order_relaxed > relaxed_atomic_uint64
Relaxed non-SC atomic integral scalar uint64_t.
AsyncStreamResponseRef read_url_stream_async(net_tk_handle handle, const std::string &url, http::PostRequestPtr httpPostReq, ByteRingbuffer *buffer, const AsyncStreamConsumerFunc &consumer_fn) noexcept
Asynchronous URL stream reader using the given AsyncStreamConsumerFunc consumer_fn.
Definition io_util.cpp:1119
SyncStreamResponseRef read_url_stream_sync(net_tk_handle handle, const std::string &url, http::PostRequestPtr httpPostReq, ByteRingbuffer *buffer, const SyncStreamConsumerFunc &consumer_fn) noexcept
Synchronous URL stream reader using the given SyncStreamConsumerFunc consumer_fn.
Definition io_util.cpp:1093
net_tk_handle create_net_tk_handle() noexcept
creates a reusable handle, free with free_net_tk_handle() after use.
Definition io_util.cpp:1072
void * net_tk_handle
Definition io_util.hpp:239
std::shared_ptr< SyncStreamResponse > SyncStreamResponseRef
Definition io_util.hpp:283
std::shared_ptr< AsyncStreamResponse > AsyncStreamResponseRef
Definition io_util.hpp:364
void free_net_tk_handle(net_tk_handle handle) noexcept
frees a handle after use created by create_net_tk_handle()
Definition io_util.cpp:1081
bool protocol_supported(const std::string_view &uri) noexcept
Returns true if the uri-scheme of given uri matches a supported by libcurl network protocols otherwis...
Definition io_util.cpp:196
std::unique_ptr< PostRequest > PostRequestPtr
Definition io_util.hpp:236
void PLAIN_PRINT(const bool printPrefix, const char *format,...) noexcept
Use for unconditional plain messages, prefix '[elapsed_time] ' if printPrefix == true.
Definition debug.cpp:258
Asynchronous stream response.
Definition io_util.hpp:326
relaxed_atomic_uint64 content_length
content_length tracking the content_length
Definition io_util.hpp:354
Synchronous stream response.
Definition io_util.hpp:247
uint64_t content_length
content_length tracking the content_length
Definition io_util.hpp:273
CXX_ALWAYS_INLINE _Tp fetch_add(_Tp __i) noexcept
CXX_ALWAYS_INLINE _Tp load() const noexcept
METHOD_AS_TEST_CASE(TestHttpStream01::test01_post_sync_ok, "TestIOStream01 - test01_post_sync_ok")